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) {}
+}