Skip to content

Commit

Permalink
feat(alarms): HZN-1492 : Add RootCause and Tags to SituationFeedback (#…
Browse files Browse the repository at this point in the history
…35)

* feat(alarms): HZN-1492: Add Root Cause to Situation Feedback

* feat(alarms): HZN-1492: rootCause and tags

* feat(alarms): HZN-1492: rootCause and tags

* feat(alarms): HZN-1492: test typo

* feat(alarms): HZN-1492: New Feedback Type
  • Loading branch information
smith-opennms committed Apr 4, 2019
1 parent 727eb0f commit 3790072
Show file tree
Hide file tree
Showing 8 changed files with 275 additions and 3 deletions.
17 changes: 17 additions & 0 deletions src/dao/SituationFeedbackDAO.ts
Expand Up @@ -49,6 +49,21 @@ export class SituationFeedbackDAO extends BaseDAO {
});
}

public async getTags(prefix: string): Promise<string[]> {
const options = new OnmsHTTPOptions();
options.headers.accept = 'application/json';
return this.http.get(this.pathToEndpoint() + '/tags?prefix=' + prefix, options).then((result) => {
const data = result.data;
if (!Array.isArray(data)) {
if (!data) {
return [] as string[];
}
throw new OnmsError('Expected an array of tags but got "' + (typeof data) + '" instead.');
}
return data;
});
}

/**
* Submit Correlation Feedback for a Situation.
*
Expand Down Expand Up @@ -84,6 +99,8 @@ export class SituationFeedbackDAO extends BaseDAO {
feedback.fingerprint = data.situationFingerprint;
feedback.alarmKey = data.alarmKey;
feedback.reason = data.reason;
feedback.rootCause = data.rootCause;
feedback.tags = data.tags;
feedback.user = data.user;
if (data.feedbackType) {
const fbt = data.feedbackType;
Expand Down
6 changes: 6 additions & 0 deletions src/model/OnmsSituationFeedback.ts
Expand Up @@ -25,6 +25,12 @@ export class OnmsSituationFeedback implements IHasUrlValue {
/** the related alarm reduction key */
public user: string;

/** TRUE if Alarm in this Feedback is the Root Cause of the Situation in this Feedback */
public rootCause: boolean;

/** User defined attributes relating to the Situation/Feedback */
public tags: string[];

/** the related alarm reduction key */
public timestamp: number;

Expand Down
2 changes: 2 additions & 0 deletions src/model/OnmsSituationFeedbackType.ts
Expand Up @@ -26,6 +26,8 @@ export class OnmsSituationFeedbackType extends OnmsEnum<string> implements IHasU
const FeedbackTypes = {
/** Alarm is correctly correlated */
CORRECT: new OnmsSituationFeedbackType('CORRECT', 'CORRECT'),
/** Alarm should be correlated in a new Situation */
CREATE_SITUATION: new OnmsSituationFeedbackType('CREATE_SITUATION', 'CREATE_SITUATION'),
/** Alarm was incorrectly correlated */
FALSE_POSITIVE: new OnmsSituationFeedbackType('FALSE_POSITIVE', 'FALSE_POSITIVE'),
/** Alarm was incorrectly ommitted */
Expand Down
63 changes: 62 additions & 1 deletion test/dao/SituationFeedbackDAO.spec.ts
Expand Up @@ -20,6 +20,7 @@ import { SituationFeedbackDAO } from '../../src/dao/SituationFeedbackDAO';
import { OnmsSituationFeedback } from '../../src/model/OnmsSituationFeedback';

import { MockHTTP23 } from '../rest/MockHTTP23';
import { MockHTTP24 } from '../rest/MockHTTP24';
import { OnmsSituationFeedbackType, FeedbackTypes } from '../../src/model/OnmsSituationFeedbackType';

const SERVER_NAME = 'Demo';
Expand All @@ -30,7 +31,7 @@ const SERVER_PASSWORD = 'demo';
// tslint:disable-next-line:one-variable-per-declaration
let opennms: Client, server, auth, mockHTTP, dao: SituationFeedbackDAO;

describe('SituationfeedbackDAO with v1 API', () => {
describe('SituationfeedbackDAO via 23', () => {
beforeEach((done) => {
auth = new OnmsAuthConfig(SERVER_USER, SERVER_PASSWORD);
server = new OnmsServer(SERVER_NAME, SERVER_URL, auth);
Expand All @@ -51,6 +52,8 @@ describe('SituationfeedbackDAO with v1 API', () => {
expect(feedback[0].reason).toEqual('ALL_CORRECT');
expect(feedback[0].user).toEqual('admin');
expect(feedback[0].timestamp).toEqual(1533835399918);
expect(feedback[0].rootCause).toEqual(undefined);
expect(feedback[0].tags).toEqual(undefined);
});
});
it('SituationFeedbackDAO.serializeFeedback()', () => {
Expand All @@ -66,3 +69,61 @@ describe('SituationfeedbackDAO with v1 API', () => {
'[{"alarmKey":"some-key","fingerprint":"hash#","feedbackType":"CORRECT"}]');
});
});

describe('SituationfeedbackDAO via 24', () => {
beforeEach((done) => {
auth = new OnmsAuthConfig(SERVER_USER, SERVER_PASSWORD);
server = new OnmsServer(SERVER_NAME, SERVER_URL, auth);
mockHTTP = new MockHTTP24(server);
opennms = new Client(mockHTTP);
dao = new SituationFeedbackDAO(mockHTTP);
Client.getMetadata(server, mockHTTP).then((metadata) => {
server.metadata = metadata;
done();
});
});
it('SituationFeedbackDAO.get(616)', () => {
return dao.getFeedback(616).then((feedback) => {
expect(feedback).toHaveLength(9);
expect(feedback[0].alarmKey).toEqual('uei.opennms.org/alarms/trigger:localhost:0.0.0.0:ALARM_C');
expect(feedback[0].fingerprint).toEqual('NDg3ZjdiMjJmNjgzMTJkMmMxYmJjOTNiMWFlYTQ0NWI=');
expect(feedback[0].feedbackType).toEqual(OnmsSituationFeedbackType.forId('CORRECT'));
expect(feedback[0].reason).toEqual(null);
expect(feedback[0].user).toEqual('admin');
expect(feedback[0].timestamp).toEqual(1553886888758);
expect(feedback[0].rootCause).toEqual(false);
expect(feedback[0].tags).toHaveLength(8);
expect(feedback[0].tags[0]).toEqual('banana');
});
});
it('SituationFeedbackDAO.getTags("ba")', () => {
return dao.getTags('ba').then((tags) => {
expect(tags).toHaveLength(4);
expect(tags[0]).toEqual('ball');
});
});
it('SituationFeedbackDAO.serializeFeedback()', () => {
const feedback = new OnmsSituationFeedback();
feedback.alarmKey = 'some-key';
feedback.fingerprint = 'hash#';
feedback.feedbackType = FeedbackTypes.CORRECT;
const serializeFeedback = dao.serializeFeedback([feedback]);
expect(serializeFeedback[0].feedbackType).toEqual('CORRECT');
// Original entry should be unchanged
expect(feedback.feedbackType).toEqual(FeedbackTypes.CORRECT);
expect(JSON.stringify(serializeFeedback)).toEqual(
'[{"alarmKey":"some-key","fingerprint":"hash#","feedbackType":"CORRECT"}]');
});
it('SituationFeedbackDAO.serializeTags()', () => {
const feedback = new OnmsSituationFeedback();
feedback.alarmKey = 'some-key';
feedback.fingerprint = 'hash#';
feedback.feedbackType = FeedbackTypes.CORRECT;
const serializeFeedback = dao.serializeFeedback([feedback]);
expect(serializeFeedback[0].feedbackType).toEqual('CORRECT');
// Original entry should be unchanged
expect(feedback.feedbackType).toEqual(FeedbackTypes.CORRECT);
expect(JSON.stringify(serializeFeedback)).toEqual(
'[{"alarmKey":"some-key","fingerprint":"hash#","feedbackType":"CORRECT"}]');
});
});
128 changes: 128 additions & 0 deletions test/rest/24.0.0/get/rest/situation-feedback/616.json
@@ -0,0 +1,128 @@
[
{
"situationKey": "uei.opennms.org/alarms/trigger:localhost:0.0.0.0:SITUATION",
"situationFingerprint": "NDg3ZjdiMjJmNjgzMTJkMmMxYmJjOTNiMWFlYTQ0NWI=",
"alarmKey": "uei.opennms.org/alarms/trigger:localhost:0.0.0.0:ALARM_C",
"feedbackType": "CORRECT",
"rootCause": false,
"reason": null,
"tags": [
"banana",
"red",
"blue",
"green",
"basketball",
"baseball",
"ball",
"ball"
],
"user": "admin",
"timestamp": 1553886888758
},
{
"situationKey": "uei.opennms.org/alarms/trigger:localhost:0.0.0.0:SITUATION",
"situationFingerprint": "NDg3ZjdiMjJmNjgzMTJkMmMxYmJjOTNiMWFlYTQ0NWI=",
"alarmKey": "uei.opennms.org/alarms/trigger:localhost:0.0.0.0:ALARM_A",
"feedbackType": "FALSE_POSITIVE",
"rootCause": false,
"reason": null,
"tags": [
"banana",
"red",
"blue",
"green",
"basketball",
"baseball",
"ball",
"ball"
],
"user": "admin",
"timestamp": 1553886888758
},
{
"situationKey": "uei.opennms.org/alarms/trigger:localhost:0.0.0.0:SITUATION",
"situationFingerprint": "NDg3ZjdiMjJmNjgzMTJkMmMxYmJjOTNiMWFlYTQ0NWI=",
"alarmKey": "uei.opennms.org/alarms/trigger:localhost:0.0.0.0:ALARM_A",
"feedbackType": "CORRECT",
"rootCause": true,
"reason": "ALL_CORRECT",
"tags": [],
"user": "admin",
"timestamp": 1553886650607
},
{
"situationKey": "uei.opennms.org/alarms/trigger:localhost:0.0.0.0:SITUATION",
"situationFingerprint": "NDg3ZjdiMjJmNjgzMTJkMmMxYmJjOTNiMWFlYTQ0NWI=",
"alarmKey": "uei.opennms.org/alarms/trigger:localhost:0.0.0.0:ALARM_C",
"feedbackType": "CORRECT",
"rootCause": false,
"reason": "ALL_CORRECT",
"tags": [],
"user": "admin",
"timestamp": 1553886650608
},
{
"situationKey": "uei.opennms.org/alarms/trigger:localhost:0.0.0.0:SITUATION",
"situationFingerprint": "NDg3ZjdiMjJmNjgzMTJkMmMxYmJjOTNiMWFlYTQ0NWI=",
"alarmKey": "uei.opennms.org/alarms/trigger:localhost:0.0.0.0:ALARM_C",
"feedbackType": "CORRECT",
"rootCause": false,
"reason": "ALL_CORRECT",
"tags": [],
"user": "admin",
"timestamp": 1553886739828
},
{
"situationKey": "uei.opennms.org/alarms/trigger:localhost:0.0.0.0:SITUATION",
"situationFingerprint": "NDg3ZjdiMjJmNjgzMTJkMmMxYmJjOTNiMWFlYTQ0NWI=",
"alarmKey": "uei.opennms.org/alarms/trigger:localhost:0.0.0.0:ALARM_B",
"feedbackType": "FALSE_POSITIVE",
"rootCause": false,
"reason": "ALL_CORRECT",
"tags": [],
"user": "admin",
"timestamp": 1553886650608
},
{
"situationKey": "uei.opennms.org/alarms/trigger:localhost:0.0.0.0:SITUATION",
"situationFingerprint": "NDg3ZjdiMjJmNjgzMTJkMmMxYmJjOTNiMWFlYTQ0NWI=",
"alarmKey": "uei.opennms.org/alarms/trigger:localhost:0.0.0.0:ALARM_A",
"feedbackType": "FALSE_POSITIVE",
"rootCause": false,
"reason": "ALL_CORRECT",
"tags": [],
"user": "admin",
"timestamp": 1553886739827
},
{
"situationKey": "uei.opennms.org/alarms/trigger:localhost:0.0.0.0:SITUATION",
"situationFingerprint": "NDg3ZjdiMjJmNjgzMTJkMmMxYmJjOTNiMWFlYTQ0NWI=",
"alarmKey": "uei.opennms.org/alarms/trigger:localhost:0.0.0.0:ALARM_B",
"feedbackType": "CORRECT",
"rootCause": true,
"reason": "ALL_CORRECT",
"tags": [],
"user": "admin",
"timestamp": 1553886739827
},
{
"situationKey": "uei.opennms.org/alarms/trigger:localhost:0.0.0.0:SITUATION",
"situationFingerprint": "NDg3ZjdiMjJmNjgzMTJkMmMxYmJjOTNiMWFlYTQ0NWI=",
"alarmKey": "uei.opennms.org/alarms/trigger:localhost:0.0.0.0:ALARM_B",
"feedbackType": "CORRECT",
"rootCause": true,
"reason": null,
"tags": [
"banana",
"red",
"blue",
"green",
"basketball",
"baseball",
"ball",
"ball"
],
"user": "admin",
"timestamp": 1553886888758
}
]
1 change: 1 addition & 0 deletions test/rest/24.0.0/get/rest/situation-feedback/tags.json
@@ -0,0 +1 @@
["ball","banana","baseball","basketball"]
6 changes: 4 additions & 2 deletions test/rest/MockHTTP23.ts
Expand Up @@ -18,9 +18,11 @@ export class MockHTTP23 extends AbstractHTTP {
urlObj.search(options.parameters);
}

switch(urlObj.toString()) {
switch (urlObj.toString()) {
case 'http://demo.opennms.org/opennms/rest/info': {
return Promise.resolve(OnmsResult.ok({'packageDescription':'OpenNMS','displayVersion':'23.0.0','packageName':'opennms','version':'23.0.0'}));
return Promise.resolve(
OnmsResult.ok({displayVersion: '23.0.0', packageDescription: 'OpenNMS',
packageName: 'opennms', version: '23.0.0'}));
}
case 'api/v2/alarms/8': {
const result = OnmsResult.ok(require('./23.0.0/get/api/v2/alarms/8.json'));
Expand Down
55 changes: 55 additions & 0 deletions test/rest/MockHTTP24.ts
@@ -0,0 +1,55 @@
/** @hidden */
declare const Promise, require;

/** @hidden */
// tslint:disable-next-line
const URI = require('urijs');

import {AbstractHTTP} from '../../src/rest/AbstractHTTP';

import {OnmsHTTPOptions} from '../../src/api/OnmsHTTPOptions';
import {OnmsResult} from '../../src/api/OnmsResult';

export class MockHTTP24 extends AbstractHTTP {
/** make an HTTP get call -- this should be overridden by the implementation */
public get(url: string, options?: OnmsHTTPOptions): Promise<OnmsResult<any>> {
const urlObj = new URI(url);
if (options && options.parameters) {
urlObj.search(options.parameters);
}

switch (urlObj.toString()) {
case 'http://demo.opennms.org/opennms/rest/info': {
return Promise.resolve(
OnmsResult.ok({displayVersion: '24.0.0', packageDescription: 'OpenNMS',
packageName: 'opennms', version: '24.0.0'}));
}
case 'rest/situation-feedback/616': {
const result = OnmsResult.ok(require('./24.0.0/get/rest/situation-feedback/616.json'));
result.type = 'application/json';
return Promise.resolve(result);
}
case 'rest/situation-feedback/tags': {
const result = OnmsResult.ok(require('./24.0.0/get/rest/situation-feedback/tags.json'));
result.type = 'application/json';
return Promise.resolve(result);
}
}
throw new Error('Not yet implemented: GET ' + urlObj.toString());
}

public put(url: string, options?: OnmsHTTPOptions): Promise<OnmsResult<any>> {
const urlObj = new URI(url);
throw new Error('Not yet implemented: PUT ' + urlObj.toString());
}

public post(url: string, options?: OnmsHTTPOptions): Promise<OnmsResult<any>> {
const urlObj = new URI(url);
throw new Error('Not yet implemented: POST ' + urlObj.toString());
}

public httpDelete(url: string, options?: OnmsHTTPOptions): Promise<OnmsResult<any>> {
const urlObj = new URI(url);
throw new Error('Not yet implemented: DELETE ' + urlObj.toString());
}
}

0 comments on commit 3790072

Please sign in to comment.