From f7105d9f06bd3c20e516f5651a42c142414e9a20 Mon Sep 17 00:00:00 2001 From: Alexander Zobnin Date: Tue, 12 May 2020 19:12:41 +0300 Subject: [PATCH] fix TriggerPanelCtrl tests --- src/panel-triggers/specs/panel_ctrl.spec.ts | 295 ++++++++------------ src/panel-triggers/triggers_panel_ctrl.ts | 7 +- src/test-setup/jest-setup.js | 13 +- src/test-setup/panelStub.js | 99 ------- src/test-setup/panelStub.ts | 158 +++++++++++ 5 files changed, 294 insertions(+), 278 deletions(-) delete mode 100644 src/test-setup/panelStub.js create mode 100644 src/test-setup/panelStub.ts diff --git a/src/panel-triggers/specs/panel_ctrl.spec.ts b/src/panel-triggers/specs/panel_ctrl.spec.ts index cbf6876..e73fc00 100644 --- a/src/panel-triggers/specs/panel_ctrl.spec.ts +++ b/src/panel-triggers/specs/panel_ctrl.spec.ts @@ -1,8 +1,6 @@ import _ from 'lodash'; -import mocks from '../../test-setup/mocks'; -import {TriggerPanelCtrl} from '../triggers_panel_ctrl'; -import {PANEL_DEFAULTS, DEFAULT_TARGET} from '../triggers_panel_ctrl'; -// import { create } from 'domain'; +import { TriggerPanelCtrl } from '../triggers_panel_ctrl'; +import { PANEL_DEFAULTS, DEFAULT_TARGET } from '../triggers_panel_ctrl'; let datasourceSrvMock, zabbixDSMock; @@ -14,85 +12,37 @@ jest.mock('@grafana/runtime', () => { describe('TriggerPanelCtrl', () => { let ctx: any = {}; - const timeoutMock = () => {}; - let createPanelCtrl; + let createPanelCtrl: () => any; beforeEach(() => { - ctx = {scope: {panel: PANEL_DEFAULTS}}; + ctx = { scope: { panel: PANEL_DEFAULTS } }; + ctx.scope.panel.targets = [{ + ...DEFAULT_TARGET, + datasource: 'zabbix_default', + }]; + zabbixDSMock = { - replaceTemplateVars: () => {}, zabbix: { - getTriggers: jest.fn().mockReturnValue([generateTrigger("1"), generateTrigger("1")]), getExtendedEventData: jest.fn().mockResolvedValue([]), getEventAlerts: jest.fn().mockResolvedValue([]), } }; datasourceSrvMock = { - getMetricSources: () => { - return [ - { meta: {id: 'alexanderzobnin-zabbix-datasource'}, value: {}, name: 'zabbix_default' }, - { meta: {id: 'alexanderzobnin-zabbix-datasource'}, value: {}, name: 'zabbix' }, - { meta: {id: 'graphite'}, value: {}, name: 'graphite' }, - ]; - }, get: () => Promise.resolve(zabbixDSMock) }; + const timeoutMock = (fn: () => any) => Promise.resolve(fn()); createPanelCtrl = () => new TriggerPanelCtrl(ctx.scope, {}, timeoutMock); - const getTriggersResp = [ - [ - createTrigger({ - triggerid: "1", lastchange: "1510000010", priority: 5, lastEvent: {eventid: "11"}, hosts: [{maintenance_status: '1'}] - }), - createTrigger({ - triggerid: "2", lastchange: "1510000040", priority: 3, lastEvent: {eventid: "12"} - }), - ], - [ - createTrigger({triggerid: "3", lastchange: "1510000020", priority: 4, lastEvent: {eventid: "13"}}), - createTrigger({triggerid: "4", lastchange: "1510000030", priority: 2, lastEvent: {eventid: "14"}}), - ] - ]; - - // Simulate 2 data sources - zabbixDSMock.zabbix.getTriggers = jest.fn() - .mockReturnValueOnce(getTriggersResp[0]) - .mockReturnValueOnce(getTriggersResp[1]); - zabbixDSMock.zabbix.getExtendedEventData = jest.fn() - .mockReturnValue(Promise.resolve([defaultEvent])); - ctx.panelCtrl = createPanelCtrl(); - }); - describe('When adding new panel', () => { - it('should suggest all zabbix data sources', () => { - ctx.scope.panel = {}; - const panelCtrl = createPanelCtrl(); - expect(panelCtrl.available_datasources).toEqual([ - 'zabbix_default', 'zabbix' - ]); - }); - - it('should load first zabbix data source as default', () => { - ctx.scope.panel = {}; - const panelCtrl = createPanelCtrl(); - expect(panelCtrl.panel.targets[0].datasource).toEqual('zabbix_default'); - }); - - it('should rewrite default empty target', () => { - ctx.scope.panel = { - targets: [{ - "target": "", - "refId": "A" - }], - }; - const panelCtrl = createPanelCtrl(); - expect(panelCtrl.available_datasources).toEqual([ - 'zabbix_default', 'zabbix' - ]); - }); + ctx.dataFramesReceived = generateDataFramesResponse([ + {id: "1", lastchange: "1510000010", priority: 5}, + {id: "2", lastchange: "1510000040", priority: 3}, + {id: "3", lastchange: "1510000020", priority: 4}, + {id: "4", lastchange: "1510000030", priority: 2}, + ]); }); describe('When refreshing panel', () => { @@ -112,8 +62,8 @@ describe('TriggerPanelCtrl', () => { }); it('should format triggers', (done) => { - ctx.panelCtrl.onRefresh().then(() => { - const formattedTrigger: any = _.find(ctx.panelCtrl.triggerList, {triggerid: "1"}); + ctx.panelCtrl.onDataFramesReceived(ctx.dataFramesReceived).then(() => { + const formattedTrigger: any = _.find(ctx.panelCtrl.renderData, {triggerid: "1"}); expect(formattedTrigger.host).toBe('backend01'); expect(formattedTrigger.hostTechName).toBe('backend01_tech'); expect(formattedTrigger.datasource).toBe('zabbix_default'); @@ -124,8 +74,8 @@ describe('TriggerPanelCtrl', () => { }); it('should sort triggers by time by default', (done) => { - ctx.panelCtrl.onRefresh().then(() => { - const trigger_ids = _.map(ctx.panelCtrl.triggerList, 'triggerid'); + ctx.panelCtrl.onDataFramesReceived(ctx.dataFramesReceived).then(() => { + const trigger_ids = _.map(ctx.panelCtrl.renderData, 'triggerid'); expect(trigger_ids).toEqual([ '2', '4', '3', '1' ]); @@ -135,27 +85,14 @@ describe('TriggerPanelCtrl', () => { it('should sort triggers by severity', (done) => { ctx.panelCtrl.panel.sortTriggersBy = { text: 'severity', value: 'priority' }; - ctx.panelCtrl.onRefresh().then(() => { - const trigger_ids = _.map(ctx.panelCtrl.triggerList, 'triggerid'); + ctx.panelCtrl.onDataFramesReceived(ctx.dataFramesReceived).then(() => { + const trigger_ids = _.map(ctx.panelCtrl.renderData, 'triggerid'); expect(trigger_ids).toEqual([ '1', '3', '2', '4' ]); done(); }); }); - - it('should add acknowledges to trigger', (done) => { - ctx.panelCtrl.onRefresh().then(() => { - const trigger = getTriggerById(1, ctx); - expect(trigger.acknowledges).toHaveLength(1); - expect(trigger.acknowledges[0].message).toBe("event ack"); - - expect(getTriggerById(2, ctx).acknowledges).toBe(undefined); - expect(getTriggerById(3, ctx).acknowledges).toBe(undefined); - expect(getTriggerById(4, ctx).acknowledges).toBe(undefined); - done(); - }); - }); }); describe('When formatting triggers', () => { @@ -165,14 +102,14 @@ describe('TriggerPanelCtrl', () => { it('should handle new lines in trigger description', () => { ctx.panelCtrl.setTriggerSeverity = jest.fn((trigger) => trigger); - const trigger = {comments: "this is\ndescription"}; + const trigger = { comments: "this is\ndescription" }; const formattedTrigger = ctx.panelCtrl.formatTrigger(trigger); expect(formattedTrigger.comments).toBe("this is
description"); }); it('should format host name to display (default)', (done) => { - ctx.panelCtrl.onRefresh().then(() => { - const trigger = getTriggerById(1, ctx); + ctx.panelCtrl.onDataFramesReceived(ctx.dataFramesReceived).then(() => { + const trigger = getProblemById(1, ctx); const hostname = ctx.panelCtrl.formatHostName(trigger); expect(hostname).toBe('backend01'); done(); @@ -182,8 +119,8 @@ describe('TriggerPanelCtrl', () => { it('should format host name to display (tech name)', (done) => { ctx.panelCtrl.panel.hostField = false; ctx.panelCtrl.panel.hostTechNameField = true; - ctx.panelCtrl.onRefresh().then(() => { - const trigger = getTriggerById(1, ctx); + ctx.panelCtrl.onDataFramesReceived(ctx.dataFramesReceived).then(() => { + const trigger = getProblemById(1, ctx); const hostname = ctx.panelCtrl.formatHostName(trigger); expect(hostname).toBe('backend01_tech'); done(); @@ -193,8 +130,8 @@ describe('TriggerPanelCtrl', () => { it('should format host name to display (both tech and visible)', (done) => { ctx.panelCtrl.panel.hostField = true; ctx.panelCtrl.panel.hostTechNameField = true; - ctx.panelCtrl.onRefresh().then(() => { - const trigger = getTriggerById(1, ctx); + ctx.panelCtrl.onDataFramesReceived(ctx.dataFramesReceived).then(() => { + const trigger = getProblemById(1, ctx); const hostname = ctx.panelCtrl.formatHostName(trigger); expect(hostname).toBe('backend01 (backend01_tech)'); done(); @@ -204,105 +141,117 @@ describe('TriggerPanelCtrl', () => { it('should hide hostname if both visible and tech name checkboxes unset', (done) => { ctx.panelCtrl.panel.hostField = false; ctx.panelCtrl.panel.hostTechNameField = false; - ctx.panelCtrl.onRefresh().then(() => { - const trigger = getTriggerById(1, ctx); + ctx.panelCtrl.onDataFramesReceived(ctx.dataFramesReceived).then(() => { + const trigger = getProblemById(1, ctx); const hostname = ctx.panelCtrl.formatHostName(trigger); expect(hostname).toBe(""); done(); }); }); }); - - describe('When formatting acknowledges', () => { - beforeEach(() => { - ctx.panelCtrl = createPanelCtrl(); - }); - - it('should build proper user name', () => { - const ack = { - alias: 'alias', name: 'name', surname: 'surname' - }; - - const formatted = ctx.panelCtrl.formatAcknowledge(ack); - expect(formatted.user).toBe('alias (name surname)'); - }); - - it('should return empty name if it is not defined', () => { - const formatted = ctx.panelCtrl.formatAcknowledge({}); - expect(formatted.user).toBe(''); - }); - }); }); -const defaultTrigger: any = { - "triggerid": "13565", - "value": "1", - "groups": [{"groupid": "1", "name": "Backend"}] , - "hosts": [{"host": "backend01_tech", "hostid": "10001","maintenance_status": "0", "name": "backend01"}] , - "lastEvent": { - "eventid": "11", - "clock": "1507229064", - "ns": "556202037", - "acknowledged": "1", - "value": "1", - "object": "0", - "source": "0", - "objectid": "13565", - }, - "tags": [] , - "lastchange": "1440259530", - "priority": "2", - "description": "Lack of free swap space on server", +const defaultProblem: any = { + "acknowledges": [], "comments": "It probably means that the systems requires\nmore physical memory.", - "url": "https://host.local/path", - "templateid": "0", "expression": "{13174}<50", "manual_close": "0", "correlation_mode": "0", - "correlation_tag": "", "recovery_mode": "0", "recovery_expression": "", "state": "0", "status": "0", - "flags": "0", "type": "0", "items": [] , "error": "" -}; - -const defaultEvent: any = { - "eventid": "11", - "acknowledges": [ + "correlation_mode": "0", + "correlation_tag": "", + "datasource": "zabbix_default", + "description": "Lack of free swap space on server", + "error": "", + "expression": "{13297}>20", + "flags": "0", + "groups": [ { - "acknowledgeid": "185", - "action": "0", - "alias": "api", - "clock": "1512382246", - "eventid": "11", - "message": "event ack", - "name": "api", - "surname": "user", - "userid": "3" + "groupid": "2", + "name": "Linux servers" + }, + { + "groupid": "9", + "name": "Backend" } ], - "clock": "1507229064", - "ns": "556202037", - "acknowledged": "1", - "value": "1", - "object": "0", - "source": "0", - "objectid": "1", + "hosts": [ + { + "host": "backend01_tech", + "hostid": "10111", + "maintenance_status": "1", + "name": "backend01", + "proxy_hostid": "0" + } + ], + "items": [ + { + "itemid": "23979", + "key_": "system.cpu.util[,iowait]", + "lastvalue": "25.2091", + "name": "CPU $2 time" + } + ], + "lastEvent": { + "acknowledged": "0", + "clock": "1589297010", + "eventid": "4399289", + "name": "Disk I/O is overloaded on backend01", + "ns": "224779201", + "object": "0", + "objectid": "13682", + "severity": "2", + "source": "0", + "value": "1" + }, + "lastchange": "1440259530", + "maintenance": true, + "manual_close": "0", + "priority": "2", + "recovery_expression": "", + "recovery_mode": "0", + "showAckButton": true, + "state": "0", + "status": "0", + "tags": [], + "templateid": "13671", + "triggerid": "13682", + "type": "0", + "url": "", + "value": "1" }; -function generateTrigger(id, timestamp?, severity?): any { - const trigger = _.cloneDeep(defaultTrigger); - trigger.triggerid = id.toString(); +function generateDataFramesResponse(problemDescs: any[] = [{id: 1}]): any { + const problems = problemDescs.map(problem => generateProblem(problem.id, problem.lastchange, problem.priority)); + + return [ + { + "fields": [ + { + "config": {}, + "name": "Problems", + "state": { + "scopedVars": {}, + "title": null + }, + "type": "other", + "values": problems, + } + ], + "length": 16, + "name": "problems" + } + ]; +} + +function generateProblem(id, timestamp?, severity?): any { + const problem = _.cloneDeep(defaultProblem); + problem.triggerid = id.toString(); if (severity) { - trigger.priority = severity.toString(); + problem.priority = severity.toString(); } if (timestamp) { - trigger.lastchange = timestamp; + problem.lastchange = timestamp; } - return trigger; + return problem; } -function createTrigger(props): any { - let trigger = _.cloneDeep(defaultTrigger); - trigger = _.merge(trigger, props); - trigger.lastEvent.objectid = trigger.triggerid; - return trigger; -} - -function getTriggerById(id, ctx): any { - return _.find(ctx.panelCtrl.triggerList, {triggerid: id.toString()}); +function getProblemById(id, ctx): any { + return _.find(ctx.panelCtrl.renderData, {triggerid: id.toString()}); } diff --git a/src/panel-triggers/triggers_panel_ctrl.ts b/src/panel-triggers/triggers_panel_ctrl.ts index cd49380..43ef754 100644 --- a/src/panel-triggers/triggers_panel_ctrl.ts +++ b/src/panel-triggers/triggers_panel_ctrl.ts @@ -118,7 +118,7 @@ export class TriggerPanelCtrl extends MetricsPanelCtrl { this.addEditorTab('Options', triggerPanelOptionsTab); } - onDataFramesReceived(data) { + onDataFramesReceived(data: any): Promise { let problems = []; if (data && data.length) { @@ -133,17 +133,18 @@ export class TriggerPanelCtrl extends MetricsPanelCtrl { } } catch (error) { console.log(error); + return Promise.reject(error); } } } this.loading = false; problems = _.flatten(problems); - this.renderProblems(problems); + return this.renderProblems(problems); } onDataSnapshotLoad(snapshotData) { - this.onDataFramesReceived(snapshotData); + return this.onDataFramesReceived(snapshotData); } onRender() { diff --git a/src/test-setup/jest-setup.js b/src/test-setup/jest-setup.js index 9e4b81c..080e06f 100644 --- a/src/test-setup/jest-setup.js +++ b/src/test-setup/jest-setup.js @@ -2,7 +2,7 @@ /* globals global: false */ import { JSDOM } from 'jsdom'; -import { PanelCtrl } from './panelStub'; +import { PanelCtrl, MetricsPanelCtrl } from './panelStub'; // Mock Grafana modules that are not available outside of the core project // Required for loading module.js @@ -24,12 +24,19 @@ jest.mock('grafana/app/core/core_module', () => { }; }, {virtual: true}); -let mockPanelCtrl = PanelCtrl; +jest.mock('grafana/app/core/core', () => ({ + contextSrv: {}, +}), {virtual: true}); + +const mockPanelCtrl = PanelCtrl; +const mockMetricsPanelCtrl = MetricsPanelCtrl; + jest.mock('grafana/app/plugins/sdk', () => { return { QueryCtrl: null, loadPluginCss: () => {}, - PanelCtrl: mockPanelCtrl + PanelCtrl: mockPanelCtrl, + MetricsPanelCtrl: mockMetricsPanelCtrl, }; }, {virtual: true}); diff --git a/src/test-setup/panelStub.js b/src/test-setup/panelStub.js deleted file mode 100644 index 9c66080..0000000 --- a/src/test-setup/panelStub.js +++ /dev/null @@ -1,99 +0,0 @@ -// JSHint options -/* jshint ignore:start */ - -export class PanelCtrl { - constructor($scope, $injector) { - this.$injector = $injector; - this.$scope = $scope; - this.panel = $scope.panel; - this.timing = {}; - this.events = { - on: () => {}, - emit: () => {} - }; - } - - init() { - } - - renderingCompleted() { - } - - refresh() { - } - - publishAppEvent(evtName, evt) { - } - - changeView(fullscreen, edit) { - } - - viewPanel() { - this.changeView(true, false); - } - - editPanel() { - this.changeView(true, true); - } - - exitFullscreen() { - this.changeView(false, false); - } - - initEditMode() { - } - - changeTab(newIndex) { - } - - addEditorTab(title, directiveFn, index) { - } - - getMenu() { - return []; - } - - getExtendedMenu() { - return []; - } - - otherPanelInFullscreenMode() { - return false; - } - - calculatePanelHeight() { - } - - render(payload) { - } - - toggleEditorHelp(index) { - } - - duplicate() { - } - - updateColumnSpan(span) { - } - - removePanel() { - } - - editPanelJson() { - } - - replacePanel(newPanel, oldPanel) { - } - - sharePanel() { - } - - getInfoMode() { - } - - getInfoContent(options) { - } - - openInspector() { - } -} diff --git a/src/test-setup/panelStub.ts b/src/test-setup/panelStub.ts new file mode 100644 index 0000000..65fea62 --- /dev/null +++ b/src/test-setup/panelStub.ts @@ -0,0 +1,158 @@ +import { PanelEvents } from '@grafana/data'; + +export class PanelCtrl { + panel: any; + error: any; + dashboard: any; + pluginName: string; + pluginId: string; + editorTabs: any; + $scope: any; + $injector: any; + $location: any; + $timeout: any; + editModeInitiated: boolean; + height: number; + width: number; + containerHeight: any; + events: any; + loading: boolean; + timing: any; + + constructor($scope, $injector) { + this.$injector = $injector; + this.$scope = $scope; + this.panel = $scope.panel; + this.timing = {}; + this.events = { + on: () => {}, + emit: () => {} + }; + } + + init() { + } + + renderingCompleted() { + } + + refresh() { + } + + publishAppEvent(evtName, evt) { + } + + changeView(fullscreen, edit) { + } + + viewPanel() { + this.changeView(true, false); + } + + editPanel() { + this.changeView(true, true); + } + + exitFullscreen() { + this.changeView(false, false); + } + + initEditMode() { + } + + changeTab(newIndex) { + } + + addEditorTab(title, directiveFn, index) { + } + + getMenu() { + return []; + } + + getExtendedMenu() { + return []; + } + + otherPanelInFullscreenMode() { + return false; + } + + calculatePanelHeight() { + } + + render(payload) { + } + + toggleEditorHelp(index) { + } + + duplicate() { + } + + updateColumnSpan(span) { + } + + removePanel() { + } + + editPanelJson() { + } + + replacePanel(newPanel, oldPanel) { + } + + sharePanel() { + } + + getInfoMode() { + } + + getInfoContent(options) { + } + + openInspector() { + } +} + +export class MetricsPanelCtrl extends PanelCtrl { + scope: any; + datasource: any; + $timeout: any; + contextSrv: any; + datasourceSrv: any; + timeSrv: any; + templateSrv: any; + range: any; + interval: any; + intervalMs: any; + resolution: any; + timeInfo?: string; + skipDataOnInit: boolean; + dataList: any[]; + querySubscription?: any; + useDataFrames = false; + + constructor($scope, $injector) { + super($scope, $injector); + + this.events.on(PanelEvents.refresh, this.onMetricsPanelRefresh.bind(this)); + } + + onInitMetricsPanelEditMode() {} + onMetricsPanelRefresh() {} + setTimeQueryStart() {} + setTimeQueryEnd() {} + updateTimeRange() {} + calculateInterval() {} + applyPanelTimeOverrides() {} + issueQueries(datasource) {} + handleQueryResult(result) {} + handleDataStream(stream) {} + setDatasource(datasource) {} + getAdditionalMenuItems() {} + explore() {} + addQuery(target) {} + removeQuery(target) {} + moveQuery(target, direction) {} +}