]> git.proxmox.com Git - ceph.git/blob - ceph/src/pybind/mgr/dashboard/frontend/src/app/shared/services/prometheus-notification.service.spec.ts
import ceph nautilus 14.2.2
[ceph.git] / ceph / src / pybind / mgr / dashboard / frontend / src / app / shared / services / prometheus-notification.service.spec.ts
1 import { HttpClientTestingModule } from '@angular/common/http/testing';
2 import { fakeAsync, TestBed, tick } from '@angular/core/testing';
3
4 import { ToastModule, ToastsManager } from 'ng2-toastr';
5 import { 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 { PrometheusNotification } 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 { PrometheusNotificationService } from './prometheus-notification.service';
20
21 describe('PrometheusNotificationService', () => {
22 let service: PrometheusNotificationService;
23 let notificationService: NotificationService;
24 let notifications: PrometheusNotification[];
25 let prometheusService: PrometheusService;
26 let prometheus: PrometheusHelper;
27 let shown: CdNotificationConfig[];
28
29 const toastFakeService = {
30 error: () => true,
31 info: () => true,
32 success: () => true
33 };
34
35 configureTestBed({
36 imports: [ToastModule.forRoot(), SharedModule, HttpClientTestingModule],
37 providers: [
38 PrometheusNotificationService,
39 PrometheusAlertFormatter,
40 i18nProviders,
41 { provide: ToastsManager, useValue: toastFakeService }
42 ]
43 });
44
45 beforeEach(() => {
46 prometheus = new PrometheusHelper();
47
48 service = TestBed.get(PrometheusNotificationService);
49 service['notifications'] = [];
50
51 notificationService = TestBed.get(NotificationService);
52 shown = [];
53 spyOn(notificationService, 'show').and.callThrough();
54 spyOn(notificationService, 'save').and.callFake((n) => shown.push(n));
55
56 spyOn(window, 'setTimeout').and.callFake((fn: Function) => fn());
57
58 prometheusService = TestBed.get(PrometheusService);
59 spyOn(prometheusService, 'getNotifications').and.callFake(() => of(notifications));
60
61 notifications = [prometheus.createNotification()];
62 });
63
64 it('should create', () => {
65 expect(service).toBeTruthy();
66 });
67
68 describe('getLastNotification', () => {
69 it('returns an empty object on the first call', () => {
70 service.refresh();
71 expect(prometheusService.getNotifications).toHaveBeenCalledWith(undefined);
72 expect(service['notifications'].length).toBe(1);
73 });
74
75 it('returns last notification on any other call', () => {
76 service.refresh();
77 notifications = [prometheus.createNotification(1, 'resolved')];
78 service.refresh();
79 expect(prometheusService.getNotifications).toHaveBeenCalledWith(service['notifications'][0]);
80 expect(service['notifications'].length).toBe(2);
81
82 notifications = [prometheus.createNotification(2)];
83 service.refresh();
84 notifications = [prometheus.createNotification(3, 'resolved')];
85 service.refresh();
86 expect(prometheusService.getNotifications).toHaveBeenCalledWith(service['notifications'][2]);
87 expect(service['notifications'].length).toBe(4);
88 });
89 });
90
91 it('notifies not on the first call', () => {
92 service.refresh();
93 expect(notificationService.show).not.toHaveBeenCalled();
94 });
95
96 describe('looks of fired notifications', () => {
97 const asyncRefresh = () => {
98 service.refresh();
99 tick(20);
100 };
101
102 const expectShown = (expected: {}[]) => {
103 tick(500);
104 expect(shown.length).toBe(expected.length);
105 expected.forEach((e, i) =>
106 Object.keys(e).forEach((key) => expect(shown[i][key]).toEqual(expected[i][key]))
107 );
108 };
109
110 beforeEach(() => {
111 service.refresh();
112 });
113
114 it('notifies on the second call', () => {
115 service.refresh();
116 expect(notificationService.show).toHaveBeenCalledTimes(1);
117 });
118
119 it('notify looks on single notification with single alert like', fakeAsync(() => {
120 asyncRefresh();
121 expectShown([
122 new CdNotificationConfig(
123 NotificationType.error,
124 'alert0 (active)',
125 'alert0 is firing ' + prometheus.createLink('http://alert0'),
126 undefined,
127 'Prometheus'
128 )
129 ]);
130 }));
131
132 it('raises multiple pop overs for a single notification with multiple alerts', fakeAsync(() => {
133 asyncRefresh();
134 notifications[0].alerts.push(prometheus.createNotificationAlert('alert1', 'resolved'));
135 asyncRefresh();
136 expectShown([
137 new CdNotificationConfig(
138 NotificationType.error,
139 'alert0 (active)',
140 'alert0 is firing ' + prometheus.createLink('http://alert0'),
141 undefined,
142 'Prometheus'
143 ),
144 new CdNotificationConfig(
145 NotificationType.success,
146 'alert1 (resolved)',
147 'alert1 is resolved ' + prometheus.createLink('http://alert1'),
148 undefined,
149 'Prometheus'
150 )
151 ]);
152 }));
153
154 it('should raise multiple notifications if they do not look like each other', fakeAsync(() => {
155 notifications[0].alerts.push(prometheus.createNotificationAlert('alert1'));
156 notifications.push(prometheus.createNotification());
157 notifications[1].alerts.push(prometheus.createNotificationAlert('alert2'));
158 asyncRefresh();
159 expectShown([
160 new CdNotificationConfig(
161 NotificationType.error,
162 'alert0 (active)',
163 'alert0 is firing ' + prometheus.createLink('http://alert0'),
164 undefined,
165 'Prometheus'
166 ),
167 new CdNotificationConfig(
168 NotificationType.error,
169 'alert1 (active)',
170 'alert1 is firing ' + prometheus.createLink('http://alert1'),
171 undefined,
172 'Prometheus'
173 ),
174 new CdNotificationConfig(
175 NotificationType.error,
176 'alert2 (active)',
177 'alert2 is firing ' + prometheus.createLink('http://alert2'),
178 undefined,
179 'Prometheus'
180 )
181 ]);
182 }));
183
184 it('only shows toasties if it got new data', () => {
185 service.refresh();
186 expect(notificationService.show).toHaveBeenCalledTimes(1);
187 notifications = [];
188 service.refresh();
189 service.refresh();
190 expect(notificationService.show).toHaveBeenCalledTimes(1);
191 notifications = [prometheus.createNotification()];
192 service.refresh();
193 expect(notificationService.show).toHaveBeenCalledTimes(2);
194 service.refresh();
195 expect(notificationService.show).toHaveBeenCalledTimes(3);
196 });
197
198 it('filters out duplicated and non user visible changes in notifications', fakeAsync(() => {
199 // Return 2 notifications with 3 duplicated alerts and 1 non visible changed alert
200 const secondAlert = prometheus.createNotificationAlert('alert0');
201 secondAlert.endsAt = new Date().toString(); // Should be ignored as it's not visible
202 notifications[0].alerts.push(secondAlert);
203 notifications.push(prometheus.createNotification());
204 notifications[1].alerts.push(prometheus.createNotificationAlert('alert0'));
205 notifications[1].notified = 'by somebody else';
206 asyncRefresh();
207
208 expectShown([
209 new CdNotificationConfig(
210 NotificationType.error,
211 'alert0 (active)',
212 'alert0 is firing ' + prometheus.createLink('http://alert0'),
213 undefined,
214 'Prometheus'
215 )
216 ]);
217 }));
218 });
219 });