1 import { HttpClientTestingModule } from '@angular/common/http/testing';
2 import { fakeAsync, TestBed, tick } from '@angular/core/testing';
4 import { ToastrModule, ToastrService } from 'ngx-toastr';
5 import { of, throwError } from 'rxjs';
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 { AlertmanagerNotification } 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';
21 describe('PrometheusNotificationService', () => {
22 let service: PrometheusNotificationService;
23 let notificationService: NotificationService;
24 let notifications: AlertmanagerNotification[];
25 let prometheusService: PrometheusService;
26 let prometheus: PrometheusHelper;
27 let shown: CdNotificationConfig[];
28 let getNotificationSinceMock: Function;
30 const toastFakeService = {
37 imports: [ToastrModule.forRoot(), SharedModule, HttpClientTestingModule],
39 PrometheusNotificationService,
40 PrometheusAlertFormatter,
42 { provide: ToastrService, useValue: toastFakeService }
47 prometheus = new PrometheusHelper();
49 service = TestBed.get(PrometheusNotificationService);
50 service['notifications'] = [];
52 notificationService = TestBed.get(NotificationService);
54 spyOn(notificationService, 'show').and.callThrough();
55 spyOn(notificationService, 'save').and.callFake((n) => shown.push(n));
57 spyOn(window, 'setTimeout').and.callFake((fn: Function) => fn());
59 prometheusService = TestBed.get(PrometheusService);
60 getNotificationSinceMock = () => of(notifications);
61 spyOn(prometheusService, 'getNotifications').and.callFake(() => getNotificationSinceMock());
63 notifications = [prometheus.createNotification()];
66 it('should create', () => {
67 expect(service).toBeTruthy();
70 describe('getLastNotification', () => {
71 it('returns an empty object on the first call', () => {
73 expect(prometheusService.getNotifications).toHaveBeenCalledWith(undefined);
74 expect(service['notifications'].length).toBe(1);
77 it('returns last notification on any other call', () => {
79 notifications = [prometheus.createNotification(1, 'resolved')];
81 expect(prometheusService.getNotifications).toHaveBeenCalledWith(service['notifications'][0]);
82 expect(service['notifications'].length).toBe(2);
84 notifications = [prometheus.createNotification(2)];
86 notifications = [prometheus.createNotification(3, 'resolved')];
88 expect(prometheusService.getNotifications).toHaveBeenCalledWith(service['notifications'][2]);
89 expect(service['notifications'].length).toBe(4);
93 it('notifies not on the first call', () => {
95 expect(notificationService.save).not.toHaveBeenCalled();
98 it('notifies should not call the api again if it failed once', () => {
99 getNotificationSinceMock = () => throwError(new Error('Test error'));
101 expect(prometheusService.getNotifications).toHaveBeenCalledTimes(1);
102 expect(service['backendFailure']).toBe(true);
104 expect(prometheusService.getNotifications).toHaveBeenCalledTimes(1);
105 service['backendFailure'] = false;
108 describe('looks of fired notifications', () => {
109 const asyncRefresh = () => {
114 const expectShown = (expected: {}[]) => {
116 expect(shown.length).toBe(expected.length);
117 expected.forEach((e, i) =>
118 Object.keys(e).forEach((key) => expect(shown[i][key]).toEqual(expected[i][key]))
126 it('notifies on the second call', () => {
128 expect(notificationService.show).toHaveBeenCalledTimes(1);
131 it('notify looks on single notification with single alert like', fakeAsync(() => {
134 new CdNotificationConfig(
135 NotificationType.error,
137 'alert0 is firing ' + prometheus.createLink('http://alert0'),
144 it('raises multiple pop overs for a single notification with multiple alerts', fakeAsync(() => {
146 notifications[0].alerts.push(prometheus.createNotificationAlert('alert1', 'resolved'));
149 new CdNotificationConfig(
150 NotificationType.error,
152 'alert0 is firing ' + prometheus.createLink('http://alert0'),
156 new CdNotificationConfig(
157 NotificationType.success,
159 'alert1 is resolved ' + prometheus.createLink('http://alert1'),
166 it('should raise multiple notifications if they do not look like each other', fakeAsync(() => {
167 notifications[0].alerts.push(prometheus.createNotificationAlert('alert1'));
168 notifications.push(prometheus.createNotification());
169 notifications[1].alerts.push(prometheus.createNotificationAlert('alert2'));
172 new CdNotificationConfig(
173 NotificationType.error,
175 'alert0 is firing ' + prometheus.createLink('http://alert0'),
179 new CdNotificationConfig(
180 NotificationType.error,
182 'alert1 is firing ' + prometheus.createLink('http://alert1'),
186 new CdNotificationConfig(
187 NotificationType.error,
189 'alert2 is firing ' + prometheus.createLink('http://alert2'),
196 it('only shows toasties if it got new data', () => {
198 expect(notificationService.save).toHaveBeenCalledTimes(1);
202 expect(notificationService.save).toHaveBeenCalledTimes(1);
203 notifications = [prometheus.createNotification()];
205 expect(notificationService.save).toHaveBeenCalledTimes(2);
207 expect(notificationService.save).toHaveBeenCalledTimes(3);
210 it('filters out duplicated and non user visible changes in notifications', fakeAsync(() => {
212 // Return 2 notifications with 3 duplicated alerts and 1 non visible changed alert
213 const secondAlert = prometheus.createNotificationAlert('alert0');
214 secondAlert.endsAt = new Date().toString(); // Should be ignored as it's not visible
215 notifications[0].alerts.push(secondAlert);
216 notifications.push(prometheus.createNotification());
217 notifications[1].alerts.push(prometheus.createNotificationAlert('alert0'));
218 notifications[1].notified = 'by somebody else';
222 new CdNotificationConfig(
223 NotificationType.error,
225 'alert0 is firing ' + prometheus.createLink('http://alert0'),