]> git.proxmox.com Git - ceph.git/blob - ceph/src/pybind/mgr/dashboard/frontend/src/app/shared/services/prometheus-alert.service.spec.ts
8bf4c41a822276a3ca6a788c5efef55d52b047b5
[ceph.git] / ceph / src / pybind / mgr / dashboard / frontend / src / app / shared / services / prometheus-alert.service.spec.ts
1 import { HttpClientTestingModule } from '@angular/common/http/testing';
2 import { TestBed } from '@angular/core/testing';
3
4 import { ToastrModule } from 'ngx-toastr';
5 import { Observable, of } from 'rxjs';
6
7 import {
8 configureTestBed,
9 i18nProviders,
10 PrometheusHelper
11 } from '../../../testing/unit-test-helper';
12 import { PrometheusService } from '../api/prometheus.service';
13 import { NotificationType } from '../enum/notification-type.enum';
14 import { CdNotificationConfig } from '../models/cd-notification';
15 import { AlertmanagerAlert } from '../models/prometheus-alerts';
16 import { SharedModule } from '../shared.module';
17 import { NotificationService } from './notification.service';
18 import { PrometheusAlertFormatter } from './prometheus-alert-formatter';
19 import { PrometheusAlertService } from './prometheus-alert.service';
20
21 describe('PrometheusAlertService', () => {
22 let service: PrometheusAlertService;
23 let notificationService: NotificationService;
24 let alerts: AlertmanagerAlert[];
25 let prometheusService: PrometheusService;
26 let prometheus: PrometheusHelper;
27
28 configureTestBed({
29 imports: [ToastrModule.forRoot(), SharedModule, HttpClientTestingModule],
30 providers: [PrometheusAlertService, PrometheusAlertFormatter, i18nProviders]
31 });
32
33 beforeEach(() => {
34 prometheus = new PrometheusHelper();
35 });
36
37 it('should create', () => {
38 expect(TestBed.get(PrometheusAlertService)).toBeTruthy();
39 });
40
41 describe('test failing status codes and verify disabling of the alertmanager', () => {
42 const isDisabledByStatusCode = (statusCode: number, expectedStatus: boolean, done: any) => {
43 service = TestBed.get(PrometheusAlertService);
44 prometheusService = TestBed.get(PrometheusService);
45 spyOn(prometheusService, 'ifAlertmanagerConfigured').and.callFake((fn) => fn());
46 spyOn(prometheusService, 'getAlerts').and.returnValue(
47 Observable.create((observer: any) => observer.error({ status: statusCode, error: {} }))
48 );
49 const disableFn = spyOn(prometheusService, 'disableAlertmanagerConfig').and.callFake(() => {
50 expect(expectedStatus).toBe(true);
51 done();
52 });
53
54 if (!expectedStatus) {
55 expect(disableFn).not.toHaveBeenCalled();
56 done();
57 }
58
59 service.getAlerts();
60 };
61
62 it('disables on 504 error which is thrown if the mgr failed', (done) => {
63 isDisabledByStatusCode(504, true, done);
64 });
65
66 it('disables on 404 error which is thrown if the external api cannot be reached', (done) => {
67 isDisabledByStatusCode(404, true, done);
68 });
69
70 it('does not disable on 400 error which is thrown if the external api receives unexpected data', (done) => {
71 isDisabledByStatusCode(400, false, done);
72 });
73 });
74
75 it('should flatten the response of getRules()', () => {
76 service = TestBed.get(PrometheusAlertService);
77 prometheusService = TestBed.get(PrometheusService);
78
79 spyOn(service['prometheusService'], 'ifPrometheusConfigured').and.callFake((fn) => fn());
80 spyOn(prometheusService, 'getRules').and.returnValue(
81 of({
82 groups: [
83 {
84 name: 'group1',
85 rules: [{ name: 'nearly_full', type: 'alerting' }]
86 },
87 {
88 name: 'test',
89 rules: [
90 { name: 'load_0', type: 'alerting' },
91 { name: 'load_1', type: 'alerting' },
92 { name: 'load_2', type: 'alerting' }
93 ]
94 }
95 ]
96 })
97 );
98
99 service.getRules();
100
101 expect(service.rules as any).toEqual([
102 { name: 'nearly_full', type: 'alerting', group: 'group1' },
103 { name: 'load_0', type: 'alerting', group: 'test' },
104 { name: 'load_1', type: 'alerting', group: 'test' },
105 { name: 'load_2', type: 'alerting', group: 'test' }
106 ]);
107 });
108
109 describe('refresh', () => {
110 beforeEach(() => {
111 service = TestBed.get(PrometheusAlertService);
112 service['alerts'] = [];
113 service['canAlertsBeNotified'] = false;
114
115 spyOn(window, 'setTimeout').and.callFake((fn: Function) => fn());
116
117 notificationService = TestBed.get(NotificationService);
118 spyOn(notificationService, 'show').and.stub();
119
120 prometheusService = TestBed.get(PrometheusService);
121 spyOn(prometheusService, 'ifAlertmanagerConfigured').and.callFake((fn) => fn());
122 spyOn(prometheusService, 'getAlerts').and.callFake(() => of(alerts));
123
124 alerts = [prometheus.createAlert('alert0')];
125 service.refresh();
126 });
127
128 it('should not notify on first call', () => {
129 expect(notificationService.show).not.toHaveBeenCalled();
130 });
131
132 it('should not notify with no change', () => {
133 service.refresh();
134 expect(notificationService.show).not.toHaveBeenCalled();
135 });
136
137 it('should notify on alert change', () => {
138 alerts = [prometheus.createAlert('alert0', 'suppressed')];
139 service.refresh();
140 expect(notificationService.show).toHaveBeenCalledWith(
141 new CdNotificationConfig(
142 NotificationType.info,
143 'alert0 (suppressed)',
144 'alert0 is suppressed ' + prometheus.createLink('http://alert0'),
145 undefined,
146 'Prometheus'
147 )
148 );
149 });
150
151 it('should notify on a new alert', () => {
152 alerts = [prometheus.createAlert('alert1'), prometheus.createAlert('alert0')];
153 service.refresh();
154 expect(notificationService.show).toHaveBeenCalledTimes(1);
155 expect(notificationService.show).toHaveBeenCalledWith(
156 new CdNotificationConfig(
157 NotificationType.error,
158 'alert1 (active)',
159 'alert1 is active ' + prometheus.createLink('http://alert1'),
160 undefined,
161 'Prometheus'
162 )
163 );
164 });
165
166 it('should notify a resolved alert if it is not there anymore', () => {
167 alerts = [];
168 service.refresh();
169 expect(notificationService.show).toHaveBeenCalledTimes(1);
170 expect(notificationService.show).toHaveBeenCalledWith(
171 new CdNotificationConfig(
172 NotificationType.success,
173 'alert0 (resolved)',
174 'alert0 is active ' + prometheus.createLink('http://alert0'),
175 undefined,
176 'Prometheus'
177 )
178 );
179 });
180
181 it('should call multiple times for multiple changes', () => {
182 const alert1 = prometheus.createAlert('alert1');
183 alerts.push(alert1);
184 service.refresh();
185 alerts = [alert1, prometheus.createAlert('alert2')];
186 service.refresh();
187 expect(notificationService.show).toHaveBeenCalledTimes(2);
188 });
189 });
190 });