mirror of
https://github.com/Studio-Saelix/sencho.git
synced 2026-08-20 07:13:05 +00:00
972f2b9483
* feat: add stack glob patterns and route severity levels Operators can filter notification routes and mute rules with anchored * globs, and routes can target info, warning, or error. Matching is fail-closed for unsafe stored patterns; write paths keep partial-PUT semantics and ReDoS caps. * test: split mute and routing chip tests to avoid dialog race * fix: move stack pattern client validator out of PatternChips * fix: bound stack glob matching and atomic pattern chip saves
120 lines
3.3 KiB
TypeScript
120 lines
3.3 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
import {
|
|
matchesNotificationFilters,
|
|
ruleNeedsStackLabels,
|
|
appliesToBell,
|
|
appliesToExternal,
|
|
} from '../helpers/notificationMatchers';
|
|
import type { NotificationMatchContext } from '../helpers/notificationMatchers';
|
|
|
|
const baseCtx: NotificationMatchContext = {
|
|
localNodeId: 1,
|
|
stackName: 'my-app',
|
|
category: 'monitor_alert',
|
|
level: 'error',
|
|
stackLabelIds: [10],
|
|
};
|
|
|
|
describe('notificationMatchers', () => {
|
|
it('matches when all non-empty filters pass', () => {
|
|
expect(matchesNotificationFilters(baseCtx, {
|
|
node_id: null,
|
|
stack_patterns: ['my-app'],
|
|
label_ids: [10],
|
|
categories: ['monitor_alert'],
|
|
levels: ['error'],
|
|
})).toBe(true);
|
|
});
|
|
|
|
it('rejects when node_id does not match', () => {
|
|
expect(matchesNotificationFilters(baseCtx, {
|
|
node_id: 2,
|
|
stack_patterns: [],
|
|
label_ids: null,
|
|
categories: null,
|
|
})).toBe(false);
|
|
});
|
|
|
|
it('rejects when stack pattern does not match', () => {
|
|
expect(matchesNotificationFilters(baseCtx, {
|
|
node_id: null,
|
|
stack_patterns: ['other'],
|
|
label_ids: null,
|
|
categories: null,
|
|
})).toBe(false);
|
|
});
|
|
|
|
it('rejects when category does not match', () => {
|
|
expect(matchesNotificationFilters(baseCtx, {
|
|
node_id: null,
|
|
stack_patterns: [],
|
|
label_ids: null,
|
|
categories: ['deploy_success'],
|
|
})).toBe(false);
|
|
});
|
|
|
|
it('rejects when level does not match', () => {
|
|
expect(matchesNotificationFilters(baseCtx, {
|
|
node_id: null,
|
|
stack_patterns: [],
|
|
label_ids: null,
|
|
categories: null,
|
|
levels: ['info'],
|
|
})).toBe(false);
|
|
});
|
|
|
|
it('matches any when all matchers empty', () => {
|
|
expect(matchesNotificationFilters(baseCtx, {
|
|
node_id: null,
|
|
stack_patterns: [],
|
|
label_ids: null,
|
|
categories: null,
|
|
levels: null,
|
|
})).toBe(true);
|
|
});
|
|
|
|
it('matches stack globs with OR across patterns', () => {
|
|
expect(matchesNotificationFilters(baseCtx, {
|
|
node_id: null,
|
|
stack_patterns: ['prod-*', 'my-app'],
|
|
label_ids: null,
|
|
categories: null,
|
|
})).toBe(true);
|
|
expect(matchesNotificationFilters({ ...baseCtx, stackName: 'prod-web' }, {
|
|
node_id: null,
|
|
stack_patterns: ['prod-*'],
|
|
label_ids: null,
|
|
categories: null,
|
|
})).toBe(true);
|
|
expect(matchesNotificationFilters(baseCtx, {
|
|
node_id: null,
|
|
stack_patterns: ['prod-*'],
|
|
label_ids: null,
|
|
categories: null,
|
|
})).toBe(false);
|
|
});
|
|
|
|
it('fails closed on invalid stored stack patterns', () => {
|
|
expect(matchesNotificationFilters(baseCtx, {
|
|
node_id: null,
|
|
stack_patterns: ['****'],
|
|
label_ids: null,
|
|
categories: null,
|
|
})).toBe(false);
|
|
});
|
|
|
|
it('detects when stack labels are needed', () => {
|
|
expect(ruleNeedsStackLabels([{ node_id: null, stack_patterns: [], label_ids: [1], categories: null }])).toBe(true);
|
|
expect(ruleNeedsStackLabels([{ node_id: null, stack_patterns: [], label_ids: null, categories: null }])).toBe(false);
|
|
});
|
|
|
|
it('applies_to helpers', () => {
|
|
expect(appliesToBell('bell')).toBe(true);
|
|
expect(appliesToBell('external')).toBe(false);
|
|
expect(appliesToExternal('external')).toBe(true);
|
|
expect(appliesToExternal('bell')).toBe(false);
|
|
expect(appliesToBell('both')).toBe(true);
|
|
expect(appliesToExternal('both')).toBe(true);
|
|
});
|
|
});
|