feat: 重建 Bell 规则与预警链路 (#132)

This commit is contained in:
QiuSW
2026-08-29 10:01:09 +08:00
parent 689de560bb
commit b01ca1fe09
22 changed files with 1759 additions and 0 deletions
@@ -0,0 +1,41 @@
import request from '@/utils/request'
import { getAlert, listAlerts } from '@/api/bell/alert'
import { getEvent, getEventRuleResults, listEvents } from '@/api/bell/event'
import { createRule, listRules, setRuleEnabled, updateRule } from '@/api/bell/rule'
jest.mock('@/utils/request', () => jest.fn(config => Promise.resolve(config)))
describe('Bell rule-alert API adapters', () => {
beforeEach(() => request.mockClear())
it('maps read operations to the versioned Bell routes', async() => {
await listAlerts({ status: 'open' })
await getAlert('alert-1')
await listEvents({ severity: 'high' })
await getEvent('event-1')
await getEventRuleResults('event-1')
await listRules({ enabled: true })
expect(request.mock.calls.map(call => call[0])).toEqual([
{ url: '/api/v1/bell/alerts', method: 'get', params: { status: 'open' }},
{ url: '/api/v1/bell/alerts/alert-1', method: 'get' },
{ url: '/api/v1/bell/events', method: 'get', params: { severity: 'high' }},
{ url: '/api/v1/bell/events/event-1', method: 'get' },
{ url: '/api/v1/bell/events/event-1/rule-results', method: 'get' },
{ url: '/api/v1/bell/rules', method: 'get', params: { enabled: true }}
])
})
it('maps administrator writes without exposing unrelated operations', async() => {
const payload = { name: '区域规则', minimumSeverity: 'high' }
await createRule(payload)
await updateRule('rule-1', payload)
await setRuleEnabled('rule-1', false)
expect(request.mock.calls.map(call => call[0])).toEqual([
{ url: '/api/v1/bell/rules', method: 'post', data: payload },
{ url: '/api/v1/bell/rules/rule-1', method: 'put', data: payload },
{ url: '/api/v1/bell/rules/rule-1/enabled', method: 'put', data: { enabled: false }}
])
})
})
@@ -0,0 +1,44 @@
import RulesPage from '@/views/bell/rules/index.vue'
import { listRules } from '@/api/bell/rule'
jest.mock('@/api/bell/rule', () => ({
createRule: jest.fn(),
listRules: jest.fn(),
setRuleEnabled: jest.fn(),
updateRule: jest.fn()
}))
function pageContext() {
return {
loading: false,
error: '',
items: [],
total: 0,
query: { pageIndex: 1, pageSize: 10, name: '', enabled: null }
}
}
describe('Bell ordinary warning rule page', () => {
beforeEach(() => jest.clearAllMocks())
it('only enables rule changes for the GoAdmin edit permission', () => {
expect(RulesPage.computed.canEdit.call({ $store: { getters: { permisaction: ['bell:rule:list'] }}})).toBe(false)
expect(RulesPage.computed.canEdit.call({ $store: { getters: { permisaction: ['bell:rule:edit'] }}})).toBe(true)
expect(RulesPage.computed.canEdit.call({ $store: { getters: { permisaction: ['*:*:*'] }}})).toBe(true)
})
it('keeps an empty list as an intentional page state', async() => {
listRules.mockResolvedValue({ data: { list: [], count: 0 }})
const context = pageContext()
await RulesPage.methods.load.call(context)
expect(context).toMatchObject({ loading: false, error: '', items: [], total: 0 })
})
it('surfaces a failed list request instead of leaving a blank page', async() => {
listRules.mockRejectedValue(new Error('网络不可用'))
const context = pageContext()
await RulesPage.methods.load.call(context)
expect(context.loading).toBe(false)
expect(context.error).toBe('网络不可用')
})
})