import { HttpResponse, http } from 'msw'; import { SetupServer, setupServer } from 'msw/node'; import { setBackendSrv } from '@grafana/runtime'; import { AlertGroupUpdated } from 'app/features/alerting/unified/api/alertRuleApi'; import allHandlers from 'app/features/alerting/unified/mocks/server/all-handlers'; import { setupAlertmanagerConfigMapDefaultState, setupAlertmanagerStatusMapDefaultState, } from 'app/features/alerting/unified/mocks/server/entities/alertmanagers'; import { resetRoutingTreeMap } from 'app/features/alerting/unified/mocks/server/entities/k8s/routingtrees'; import { DashboardDTO, FolderDTO, OrgUser } from 'app/types'; import { PromRulesResponse, RulerGrafanaRuleDTO, RulerRuleGroupDTO, RulerRulesConfigDTO, } from 'app/types/unified-alerting-dto'; import { backendSrv } from '../../../core/services/backend_srv'; import { AlertManagerCortexConfig, AlertmanagerConfig, AlertmanagerReceiver, EmailConfig, GrafanaManagedReceiverConfig, MatcherOperator, Route, } from '../../../plugins/datasource/alertmanager/types'; import { DashboardSearchItem } from '../../search/types'; type Configurator = (builder: T) => T; export class AlertmanagerConfigBuilder { private alertmanagerConfig: AlertmanagerConfig = { receivers: [] }; addReceivers(configure: (builder: AlertmanagerReceiverBuilder) => void): AlertmanagerConfigBuilder { const receiverBuilder = new AlertmanagerReceiverBuilder(); configure(receiverBuilder); this.alertmanagerConfig.receivers?.push(receiverBuilder.build()); return this; } withRoute(configure: (routeBuilder: AlertmanagerRouteBuilder) => void): AlertmanagerConfigBuilder { const routeBuilder = new AlertmanagerRouteBuilder(); configure(routeBuilder); this.alertmanagerConfig.route = routeBuilder.build(); return this; } build() { return this.alertmanagerConfig; } } class AlertmanagerRouteBuilder { private route: Route = { routes: [], object_matchers: [] }; withReceiver(receiver: string): AlertmanagerRouteBuilder { this.route.receiver = receiver; return this; } withoutReceiver(): AlertmanagerRouteBuilder { return this; } withEmptyReceiver(): AlertmanagerRouteBuilder { this.route.receiver = ''; return this; } addRoute(configure: (builder: AlertmanagerRouteBuilder) => void): AlertmanagerRouteBuilder { const routeBuilder = new AlertmanagerRouteBuilder(); configure(routeBuilder); this.route.routes?.push(routeBuilder.build()); return this; } addMatcher(key: string, operator: MatcherOperator, value: string): AlertmanagerRouteBuilder { this.route.object_matchers?.push([key, operator, value]); return this; } build() { return this.route; } } class EmailConfigBuilder { private emailConfig: EmailConfig = { to: '' }; withTo(to: string): EmailConfigBuilder { this.emailConfig.to = to; return this; } build() { return this.emailConfig; } } class GrafanaReceiverConfigBuilder { private grafanaReceiverConfig: GrafanaManagedReceiverConfig = { name: '', type: '', settings: {}, disableResolveMessage: false, }; withType(type: string): GrafanaReceiverConfigBuilder { this.grafanaReceiverConfig.type = type; return this; } withName(name: string): GrafanaReceiverConfigBuilder { this.grafanaReceiverConfig.name = name; return this; } addSetting(key: string, value: string): GrafanaReceiverConfigBuilder { if (this.grafanaReceiverConfig.settings) { this.grafanaReceiverConfig.settings[key] = value; } return this; } build() { return this.grafanaReceiverConfig; } } export class AlertmanagerReceiverBuilder { private receiver: AlertmanagerReceiver = { name: '', email_configs: [], grafana_managed_receiver_configs: [] }; withName(name: string): AlertmanagerReceiverBuilder { this.receiver.name = name; return this; } addGrafanaReceiverConfig(configure: Configurator): AlertmanagerReceiverBuilder { this.receiver.grafana_managed_receiver_configs?.push(configure(new GrafanaReceiverConfigBuilder()).build()); return this; } addEmailConfig(configure: (builder: EmailConfigBuilder) => void): AlertmanagerReceiverBuilder { const builder = new EmailConfigBuilder(); configure(builder); this.receiver.email_configs?.push(builder.build()); return this; } build() { return this.receiver; } } export const getMockConfig = (configure: (builder: AlertmanagerConfigBuilder) => void): AlertManagerCortexConfig => { const builder = new AlertmanagerConfigBuilder(); configure(builder); return { alertmanager_config: builder.build(), template_files: {} }; }; export function mockAlertRuleApi(server: SetupServer) { return { prometheusRuleNamespaces: (dsName: string, response: PromRulesResponse) => { server.use( http.get(`api/prometheus/${dsName}/api/v1/rules`, () => HttpResponse.json(response)) ); }, rulerRules: (dsName: string, response: RulerRulesConfigDTO) => { server.use(http.get(`/api/ruler/${dsName}/api/v1/rules`, () => HttpResponse.json(response))); }, updateRule: (dsName: string, response: AlertGroupUpdated) => { server.use(http.post(`/api/ruler/${dsName}/api/v1/rules/:namespaceUid`, () => HttpResponse.json(response))); }, rulerRuleGroup: (dsName: string, namespace: string, group: string, response: RulerRuleGroupDTO) => { server.use( http.get(`/api/ruler/${dsName}/api/v1/rules/${namespace}/${group}`, () => HttpResponse.json(response)) ); }, getAlertRule: (uid: string, response: RulerGrafanaRuleDTO) => { server.use(http.get(`/api/ruler/grafana/api/v1/rule/${uid}`, () => HttpResponse.json(response))); }, getAlertRuleVersionHistory: (uid: string, response: RulerGrafanaRuleDTO[]) => { server.use(http.get(`/api/ruler/grafana/api/v1/rule/${uid}/versions`, () => HttpResponse.json(response))); }, }; } export function mockExportApi(server: SetupServer) { // exportRule, exportRulesGroup, exportRulesFolder use the same API endpoint but with different parameters return { // exportRulesGroup requires folderUid and group parameters and doesn't allow ruleUid parameter exportRulesGroup: (folderUid: string, group: string, response: Record) => { server.use( http.get('/api/ruler/grafana/api/v1/export/rules', ({ request }) => { const url = new URL(request.url); if (url.searchParams.get('folderUid') === folderUid && url.searchParams.get('group') === group) { const format = url.searchParams.get('format') ?? 'yaml'; return HttpResponse.text(response[format]); } return HttpResponse.text('', { status: 500 }); }) ); }, modifiedExport: (namespaceUID: string, response: Record) => { server.use( http.post(`/api/ruler/grafana/api/v1/rules/${namespaceUID}/export`, ({ request }) => { const url = new URL(request.url); const format = url.searchParams.get('format') ?? 'yaml'; return HttpResponse.text(response[format]); }) ); }, }; } export function mockFolderApi(server: SetupServer) { return { folder: (folderUid: string, response: FolderDTO) => { server.use(http.get(`/api/folders/${folderUid}`, () => HttpResponse.json(response))); }, }; } export function mockSearchApi(server: SetupServer) { return { search: (results: DashboardSearchItem[]) => { server.use(http.get(`/api/search`, () => HttpResponse.json(results))); }, }; } export function mockUserApi(server: SetupServer) { return { user: (user: OrgUser) => { server.use(http.get(`/api/user`, () => HttpResponse.json(user))); }, }; } export function mockDashboardApi(server: SetupServer) { return { search: (results: DashboardSearchItem[]) => { server.use(http.get(`/api/search`, () => HttpResponse.json(results))); }, dashboard: (response: DashboardDTO) => { server.use(http.get(`/api/dashboards/uid/${response.dashboard.uid}`, () => HttpResponse.json(response))); }, }; } const server = setupServer(...allHandlers); /** * Sets up beforeAll, afterAll and beforeEach handlers for mock server */ export function setupMswServer() { beforeAll(() => { setBackendSrv(backendSrv); server.listen({ onUnhandledRequest: 'error' }); }); afterEach(() => { server.resetHandlers(); // Reset any other necessary mock entities/state setupAlertmanagerConfigMapDefaultState(); setupAlertmanagerStatusMapDefaultState(); resetRoutingTreeMap(); }); afterAll(() => { server.close(); }); return server; } export default server;