summaryrefslogtreecommitdiffstats
path: root/src/pybind/mgr/dashboard/frontend/src/app/shared/services/prometheus-notification.service.spec.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/pybind/mgr/dashboard/frontend/src/app/shared/services/prometheus-notification.service.spec.ts')
-rw-r--r--src/pybind/mgr/dashboard/frontend/src/app/shared/services/prometheus-notification.service.spec.ts227
1 files changed, 227 insertions, 0 deletions
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/services/prometheus-notification.service.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/services/prometheus-notification.service.spec.ts
new file mode 100644
index 000000000..4fb2bbbb9
--- /dev/null
+++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/services/prometheus-notification.service.spec.ts
@@ -0,0 +1,227 @@
+import { HttpClientTestingModule } from '@angular/common/http/testing';
+import { fakeAsync, TestBed, tick } from '@angular/core/testing';
+
+import { ToastrModule, ToastrService } from 'ngx-toastr';
+import { of, throwError } from 'rxjs';
+
+import { configureTestBed, PrometheusHelper } from '~/testing/unit-test-helper';
+import { PrometheusService } from '../api/prometheus.service';
+import { NotificationType } from '../enum/notification-type.enum';
+import { CdNotificationConfig } from '../models/cd-notification';
+import { AlertmanagerNotification } from '../models/prometheus-alerts';
+import { SharedModule } from '../shared.module';
+import { NotificationService } from './notification.service';
+import { PrometheusAlertFormatter } from './prometheus-alert-formatter';
+import { PrometheusNotificationService } from './prometheus-notification.service';
+
+describe('PrometheusNotificationService', () => {
+ let service: PrometheusNotificationService;
+ let notificationService: NotificationService;
+ let notifications: AlertmanagerNotification[];
+ let prometheusService: PrometheusService;
+ let prometheus: PrometheusHelper;
+ let shown: CdNotificationConfig[];
+ let getNotificationSinceMock: Function;
+
+ const toastFakeService = {
+ error: () => true,
+ info: () => true,
+ success: () => true
+ };
+
+ configureTestBed({
+ imports: [ToastrModule.forRoot(), SharedModule, HttpClientTestingModule],
+ providers: [
+ PrometheusNotificationService,
+ PrometheusAlertFormatter,
+ { provide: ToastrService, useValue: toastFakeService }
+ ]
+ });
+
+ beforeEach(() => {
+ prometheus = new PrometheusHelper();
+
+ service = TestBed.inject(PrometheusNotificationService);
+ service['notifications'] = [];
+
+ notificationService = TestBed.inject(NotificationService);
+ shown = [];
+ spyOn(notificationService, 'show').and.callThrough();
+ spyOn(notificationService, 'save').and.callFake((n) => shown.push(n));
+
+ spyOn(window, 'setTimeout').and.callFake((fn: Function) => fn());
+
+ prometheusService = TestBed.inject(PrometheusService);
+ getNotificationSinceMock = () => of(notifications);
+ spyOn(prometheusService, 'getNotifications').and.callFake(() => getNotificationSinceMock());
+
+ notifications = [prometheus.createNotification()];
+ });
+
+ it('should create', () => {
+ expect(service).toBeTruthy();
+ });
+
+ describe('getLastNotification', () => {
+ it('returns an empty object on the first call', () => {
+ service.refresh();
+ expect(prometheusService.getNotifications).toHaveBeenCalledWith(undefined);
+ expect(service['notifications'].length).toBe(1);
+ });
+
+ it('returns last notification on any other call', () => {
+ service.refresh();
+ notifications = [prometheus.createNotification(1, 'resolved')];
+ service.refresh();
+ expect(prometheusService.getNotifications).toHaveBeenCalledWith(service['notifications'][0]);
+ expect(service['notifications'].length).toBe(2);
+
+ notifications = [prometheus.createNotification(2)];
+ service.refresh();
+ notifications = [prometheus.createNotification(3, 'resolved')];
+ service.refresh();
+ expect(prometheusService.getNotifications).toHaveBeenCalledWith(service['notifications'][2]);
+ expect(service['notifications'].length).toBe(4);
+ });
+ });
+
+ it('notifies not on the first call', () => {
+ service.refresh();
+ expect(notificationService.save).not.toHaveBeenCalled();
+ });
+
+ it('notifies should not call the api again if it failed once', () => {
+ getNotificationSinceMock = () => throwError(new Error('Test error'));
+ service.refresh();
+ expect(prometheusService.getNotifications).toHaveBeenCalledTimes(1);
+ expect(service['backendFailure']).toBe(true);
+ service.refresh();
+ expect(prometheusService.getNotifications).toHaveBeenCalledTimes(1);
+ service['backendFailure'] = false;
+ });
+
+ describe('looks of fired notifications', () => {
+ const asyncRefresh = () => {
+ service.refresh();
+ tick(20);
+ };
+
+ const expectShown = (expected: object[]) => {
+ tick(500);
+ expect(shown.length).toBe(expected.length);
+ expected.forEach((e, i) =>
+ Object.keys(e).forEach((key) => expect(shown[i][key]).toEqual(expected[i][key]))
+ );
+ };
+
+ beforeEach(() => {
+ service.refresh();
+ });
+
+ it('notifies on the second call', () => {
+ service.refresh();
+ expect(notificationService.show).toHaveBeenCalledTimes(1);
+ });
+
+ it('notify looks on single notification with single alert like', fakeAsync(() => {
+ asyncRefresh();
+ expectShown([
+ new CdNotificationConfig(
+ NotificationType.error,
+ 'alert0 (active)',
+ 'alert0 is firing ' + prometheus.createLink('http://alert0'),
+ undefined,
+ 'Prometheus'
+ )
+ ]);
+ }));
+
+ it('raises multiple pop overs for a single notification with multiple alerts', fakeAsync(() => {
+ asyncRefresh();
+ notifications[0].alerts.push(prometheus.createNotificationAlert('alert1', 'resolved'));
+ asyncRefresh();
+ expectShown([
+ new CdNotificationConfig(
+ NotificationType.error,
+ 'alert0 (active)',
+ 'alert0 is firing ' + prometheus.createLink('http://alert0'),
+ undefined,
+ 'Prometheus'
+ ),
+ new CdNotificationConfig(
+ NotificationType.success,
+ 'alert1 (resolved)',
+ 'alert1 is resolved ' + prometheus.createLink('http://alert1'),
+ undefined,
+ 'Prometheus'
+ )
+ ]);
+ }));
+
+ it('should raise multiple notifications if they do not look like each other', fakeAsync(() => {
+ notifications[0].alerts.push(prometheus.createNotificationAlert('alert1'));
+ notifications.push(prometheus.createNotification());
+ notifications[1].alerts.push(prometheus.createNotificationAlert('alert2'));
+ asyncRefresh();
+ expectShown([
+ new CdNotificationConfig(
+ NotificationType.error,
+ 'alert0 (active)',
+ 'alert0 is firing ' + prometheus.createLink('http://alert0'),
+ undefined,
+ 'Prometheus'
+ ),
+ new CdNotificationConfig(
+ NotificationType.error,
+ 'alert1 (active)',
+ 'alert1 is firing ' + prometheus.createLink('http://alert1'),
+ undefined,
+ 'Prometheus'
+ ),
+ new CdNotificationConfig(
+ NotificationType.error,
+ 'alert2 (active)',
+ 'alert2 is firing ' + prometheus.createLink('http://alert2'),
+ undefined,
+ 'Prometheus'
+ )
+ ]);
+ }));
+
+ it('only shows toasties if it got new data', () => {
+ service.refresh();
+ expect(notificationService.save).toHaveBeenCalledTimes(1);
+ notifications = [];
+ service.refresh();
+ service.refresh();
+ expect(notificationService.save).toHaveBeenCalledTimes(1);
+ notifications = [prometheus.createNotification()];
+ service.refresh();
+ expect(notificationService.save).toHaveBeenCalledTimes(2);
+ service.refresh();
+ expect(notificationService.save).toHaveBeenCalledTimes(3);
+ });
+
+ it('filters out duplicated and non user visible changes in notifications', fakeAsync(() => {
+ asyncRefresh();
+ // Return 2 notifications with 3 duplicated alerts and 1 non visible changed alert
+ const secondAlert = prometheus.createNotificationAlert('alert0');
+ secondAlert.endsAt = new Date().toString(); // Should be ignored as it's not visible
+ notifications[0].alerts.push(secondAlert);
+ notifications.push(prometheus.createNotification());
+ notifications[1].alerts.push(prometheus.createNotificationAlert('alert0'));
+ notifications[1].notified = 'by somebody else';
+ asyncRefresh();
+
+ expectShown([
+ new CdNotificationConfig(
+ NotificationType.error,
+ 'alert0 (active)',
+ 'alert0 is firing ' + prometheus.createLink('http://alert0'),
+ undefined,
+ 'Prometheus'
+ )
+ ]);
+ }));
+ });
+});