2026-05-23 10:40:25 +08:00
|
|
|
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
|
|
|
|
2026-07-15 23:47:19 +08:00
|
|
|
const { getAllSystemConfigsMock, updateSystemConfigMock } = vi.hoisted(() => ({
|
|
|
|
|
getAllSystemConfigsMock: vi.fn(),
|
2026-05-29 14:35:16 +08:00
|
|
|
updateSystemConfigMock: vi.fn(),
|
2026-05-23 10:40:25 +08:00
|
|
|
}))
|
|
|
|
|
|
|
|
|
|
vi.mock('@/api/admin', () => ({
|
|
|
|
|
adminApi: {
|
2026-07-15 23:47:19 +08:00
|
|
|
getAllSystemConfigs: getAllSystemConfigsMock,
|
2026-05-29 14:35:16 +08:00
|
|
|
updateSystemConfig: updateSystemConfigMock,
|
2026-05-23 10:40:25 +08:00
|
|
|
getSystemVersion: vi.fn(),
|
|
|
|
|
},
|
|
|
|
|
}))
|
|
|
|
|
|
|
|
|
|
vi.mock('@/composables/useToast', () => ({
|
|
|
|
|
useToast: () => ({
|
|
|
|
|
success: vi.fn(),
|
|
|
|
|
error: vi.fn(),
|
|
|
|
|
}),
|
|
|
|
|
}))
|
|
|
|
|
|
|
|
|
|
vi.mock('@/composables/useSiteInfo', () => ({
|
|
|
|
|
useSiteInfo: () => ({
|
|
|
|
|
refreshSiteInfo: vi.fn(),
|
|
|
|
|
}),
|
|
|
|
|
}))
|
|
|
|
|
|
|
|
|
|
vi.mock('@/utils/logger', () => ({
|
|
|
|
|
log: {
|
|
|
|
|
error: vi.fn(),
|
|
|
|
|
},
|
|
|
|
|
}))
|
|
|
|
|
|
|
|
|
|
import { useSystemConfig } from '../composables/useSystemConfig'
|
|
|
|
|
|
|
|
|
|
describe('useSystemConfig', () => {
|
|
|
|
|
beforeEach(() => {
|
2026-07-15 23:47:19 +08:00
|
|
|
getAllSystemConfigsMock.mockReset()
|
2026-05-29 14:35:16 +08:00
|
|
|
updateSystemConfigMock.mockReset()
|
2026-05-23 10:40:25 +08:00
|
|
|
})
|
|
|
|
|
|
2026-07-15 23:47:19 +08:00
|
|
|
it('loads config keys in one request and keeps change detection disabled until the baseline is ready', async () => {
|
|
|
|
|
let resolveConfigs: ((value: Array<{ key: string, value: unknown, is_set?: boolean }>) => void) | null = null
|
|
|
|
|
getAllSystemConfigsMock.mockImplementation(() => new Promise((resolve) => {
|
|
|
|
|
resolveConfigs = resolve
|
2026-05-23 10:40:25 +08:00
|
|
|
}))
|
|
|
|
|
|
|
|
|
|
const state = useSystemConfig()
|
|
|
|
|
const loadPromise = state.loadSystemConfig()
|
|
|
|
|
|
2026-07-15 23:47:19 +08:00
|
|
|
expect(getAllSystemConfigsMock).toHaveBeenCalledTimes(1)
|
|
|
|
|
expect(getAllSystemConfigsMock).toHaveBeenCalledWith({ cacheTtlMs: 30_000 })
|
2026-05-23 10:40:25 +08:00
|
|
|
|
|
|
|
|
state.systemConfig.value.request_record_level = 'headers'
|
|
|
|
|
expect(state.systemConfigLoading.value).toBe(true)
|
|
|
|
|
expect(state.hasLogConfigChanges.value).toBe(false)
|
|
|
|
|
|
2026-07-15 23:47:19 +08:00
|
|
|
resolveConfigs?.([
|
|
|
|
|
{ key: 'request_record_level', value: 'basic' },
|
|
|
|
|
{ key: 'proxy_node_metrics_cleanup_batch_size', value: 5000 },
|
|
|
|
|
{ key: 'enable_standard_text_sync_heartbeat', value: false },
|
|
|
|
|
])
|
2026-05-23 10:40:25 +08:00
|
|
|
await loadPromise
|
|
|
|
|
|
|
|
|
|
expect(state.systemConfigLoading.value).toBe(false)
|
|
|
|
|
expect(state.systemConfig.value.request_record_level).toBe('basic')
|
|
|
|
|
expect(state.hasLogConfigChanges.value).toBe(false)
|
|
|
|
|
|
|
|
|
|
state.systemConfig.value.request_record_level = 'full'
|
|
|
|
|
expect(state.hasLogConfigChanges.value).toBe(true)
|
|
|
|
|
})
|
2026-05-29 14:35:16 +08:00
|
|
|
|
|
|
|
|
it('loads and saves the standard text sync heartbeat flag as a basic config item', async () => {
|
2026-07-15 23:47:19 +08:00
|
|
|
getAllSystemConfigsMock.mockResolvedValue([
|
|
|
|
|
{ key: 'enable_standard_text_sync_heartbeat', value: false },
|
|
|
|
|
])
|
2026-05-29 14:35:16 +08:00
|
|
|
updateSystemConfigMock.mockResolvedValue({})
|
|
|
|
|
|
|
|
|
|
const state = useSystemConfig()
|
|
|
|
|
await state.loadSystemConfig()
|
|
|
|
|
|
|
|
|
|
expect(state.systemConfig.value.enable_standard_text_sync_heartbeat).toBe(false)
|
|
|
|
|
state.systemConfig.value.enable_standard_text_sync_heartbeat = true
|
|
|
|
|
expect(state.hasBasicConfigChanges.value).toBe(true)
|
|
|
|
|
|
|
|
|
|
await state.saveBasicConfig()
|
|
|
|
|
|
|
|
|
|
expect(updateSystemConfigMock).toHaveBeenCalledWith(
|
|
|
|
|
'enable_standard_text_sync_heartbeat',
|
|
|
|
|
true,
|
|
|
|
|
'标准文本非流式心跳开关:开启后外层 HTTP 状态固定为 200,上游失败写入响应体'
|
|
|
|
|
)
|
|
|
|
|
expect(state.hasBasicConfigChanges.value).toBe(false)
|
|
|
|
|
})
|
2026-07-15 23:47:19 +08:00
|
|
|
|
2026-07-19 23:27:19 +08:00
|
|
|
it('keeps Cyber failover disabled by default and saves the enabled state', async () => {
|
|
|
|
|
getAllSystemConfigsMock.mockResolvedValue([])
|
|
|
|
|
updateSystemConfigMock.mockResolvedValue({})
|
|
|
|
|
|
|
|
|
|
const state = useSystemConfig()
|
|
|
|
|
await state.loadSystemConfig()
|
|
|
|
|
|
|
|
|
|
expect(state.systemConfig.value.cyber_continue_failover).toBe(false)
|
|
|
|
|
state.systemConfig.value.cyber_continue_failover = true
|
|
|
|
|
expect(state.hasBasicConfigChanges.value).toBe(true)
|
|
|
|
|
|
|
|
|
|
await state.saveBasicConfig()
|
|
|
|
|
|
|
|
|
|
expect(updateSystemConfigMock).toHaveBeenCalledWith(
|
|
|
|
|
'cyber_continue_failover',
|
|
|
|
|
true,
|
|
|
|
|
'Cyber继续转移开关:开启后在响应内容开始前将Cyber Policy错误按普通错误继续故障转移,可能增加首字等待时间'
|
|
|
|
|
)
|
|
|
|
|
expect(state.hasBasicConfigChanges.value).toBe(false)
|
|
|
|
|
})
|
|
|
|
|
|
2026-07-15 23:47:19 +08:00
|
|
|
it('uses backend-compatible defaults when config rows have not been persisted yet', async () => {
|
|
|
|
|
getAllSystemConfigsMock.mockResolvedValue([])
|
|
|
|
|
|
|
|
|
|
const state = useSystemConfig()
|
|
|
|
|
await state.loadSystemConfig()
|
|
|
|
|
|
|
|
|
|
expect(state.systemConfig.value.request_record_level).toBe('full')
|
|
|
|
|
expect(state.systemConfig.value.max_request_body_size).toBe(5_242_880)
|
|
|
|
|
expect(state.systemConfig.value.max_response_body_size).toBe(5_242_880)
|
|
|
|
|
})
|
2026-05-23 10:40:25 +08:00
|
|
|
})
|