Skip to content

Commit

Permalink
use mock in metric threshold
Browse files Browse the repository at this point in the history
  • Loading branch information
gmmorris committed Apr 15, 2020
1 parent a2a742f commit 13923bb
Showing 1 changed file with 126 additions and 111 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,62 +8,77 @@ import { createMetricThresholdExecutor, FIRED_ACTIONS } from './metric_threshold
import { Comparator, AlertStates } from './types';
import * as mocks from './test_mocks';
import { AlertExecutorOptions } from '../../../../../alerting/server';
import {
alertsMock,
AlertServicesMock,
AlertInstanceMock,
} from '../../../../../alerting/server/mocks';

const executor = createMetricThresholdExecutor('test') as (opts: {
params: AlertExecutorOptions['params'];
services: { callCluster: AlertExecutorOptions['params']['callCluster'] };
}) => Promise<void>;
const alertInstances = new Map();

const services = {
callCluster(_: string, { body, index }: any) {
if (index === 'alternatebeat-*') return mocks.changedSourceIdResponse;
const metric = body.query.bool.filter[1]?.exists.field;
if (body.aggs.groupings) {
if (body.aggs.groupings.composite.after) {
return mocks.compositeEndResponse;
}
if (metric === 'test.metric.2') {
return mocks.alternateCompositeResponse;
}
return mocks.basicCompositeResponse;
const services: AlertServicesMock = alertsMock.createAlertServices();
services.callCluster.mockImplementation((_: string, { body, index }: any) => {
if (index === 'alternatebeat-*') return mocks.changedSourceIdResponse;
const metric = body.query.bool.filter[1]?.exists.field;
if (body.aggs.groupings) {
if (body.aggs.groupings.composite.after) {
return mocks.compositeEndResponse;
}
if (metric === 'test.metric.2') {
return mocks.alternateMetricResponse;
return mocks.alternateCompositeResponse;
}
return mocks.basicMetricResponse;
},
alertInstanceFactory(instanceID: string) {
let state: any;
const actionQueue: any[] = [];
const instance = {
actionQueue: [],
get state() {
return state;
},
get mostRecentAction() {
return actionQueue.pop();
},
};
alertInstances.set(instanceID, instance);
return mocks.basicCompositeResponse;
}
if (metric === 'test.metric.2') {
return mocks.alternateMetricResponse;
}
return mocks.basicMetricResponse;
});
services.savedObjectsClient.get.mockImplementation(async (type: string, sourceId: string) => {
if (sourceId === 'alternate')
return {
instanceID,
scheduleActions(id: string, action: any) {
actionQueue.push({ id, action });
},
replaceState(newState: any) {
state = newState;
},
id: 'alternate',
attributes: { metricAlias: 'alternatebeat-*' },
type,
references: [],
};
},
savedObjectsClient: {
get(_: string, sourceId: string) {
if (sourceId === 'alternate')
return { id: 'alternate', attributes: { metricAlias: 'alternatebeat-*' } };
return { id: 'default', attributes: { metricAlias: 'metricbeat-*' } };
},
},
};
return { id: 'default', attributes: { metricAlias: 'metricbeat-*' }, type, references: [] };
});

interface AlertTestInstance {
instance: AlertInstanceMock;
actionQueue: any[];
state: any;
}
const alertInstances = new Map<string, AlertTestInstance>();
services.alertInstanceFactory.mockImplementation((instanceID: string) => {
const alertInstance: AlertTestInstance = {
instance: alertsMock.createAlertInstanceFactory(),
actionQueue: [],
state: {},
};
alertInstances.set(instanceID, alertInstance);
alertInstance.instance.replaceState.mockImplementation((newState: any) => {
alertInstance.state = newState;
return alertInstance.instance;
});
alertInstance.instance.scheduleActions.mockImplementation((id: string, action: any) => {
alertInstance.actionQueue.push({ id, action });
return alertInstance.instance;
});
return alertInstance.instance;
});

function mostRecentAction(id: string) {
return alertInstances.get(id)!.actionQueue.pop();
}

function getState(id: string) {
return alertInstances.get(id)!.state;
}

const baseCriterion = {
aggType: 'avg',
Expand All @@ -90,65 +105,65 @@ describe('The metric threshold alert type', () => {
});
test('alerts as expected with the > comparator', async () => {
await execute(Comparator.GT, [0.75]);
expect(alertInstances.get(instanceID).mostRecentAction.id).toBe(FIRED_ACTIONS.id);
expect(alertInstances.get(instanceID).state.alertState).toBe(AlertStates.ALERT);
expect(mostRecentAction(instanceID).id).toBe(FIRED_ACTIONS.id);
expect(getState(instanceID).alertState).toBe(AlertStates.ALERT);
await execute(Comparator.GT, [1.5]);
expect(alertInstances.get(instanceID).mostRecentAction).toBe(undefined);
expect(alertInstances.get(instanceID).state.alertState).toBe(AlertStates.OK);
expect(mostRecentAction(instanceID)).toBe(undefined);
expect(getState(instanceID).alertState).toBe(AlertStates.OK);
});
test('alerts as expected with the < comparator', async () => {
await execute(Comparator.LT, [1.5]);
expect(alertInstances.get(instanceID).mostRecentAction.id).toBe(FIRED_ACTIONS.id);
expect(alertInstances.get(instanceID).state.alertState).toBe(AlertStates.ALERT);
expect(mostRecentAction(instanceID).id).toBe(FIRED_ACTIONS.id);
expect(getState(instanceID).alertState).toBe(AlertStates.ALERT);
await execute(Comparator.LT, [0.75]);
expect(alertInstances.get(instanceID).mostRecentAction).toBe(undefined);
expect(alertInstances.get(instanceID).state.alertState).toBe(AlertStates.OK);
expect(mostRecentAction(instanceID)).toBe(undefined);
expect(getState(instanceID).alertState).toBe(AlertStates.OK);
});
test('alerts as expected with the >= comparator', async () => {
await execute(Comparator.GT_OR_EQ, [0.75]);
expect(alertInstances.get(instanceID).mostRecentAction.id).toBe(FIRED_ACTIONS.id);
expect(alertInstances.get(instanceID).state.alertState).toBe(AlertStates.ALERT);
expect(mostRecentAction(instanceID).id).toBe(FIRED_ACTIONS.id);
expect(getState(instanceID).alertState).toBe(AlertStates.ALERT);
await execute(Comparator.GT_OR_EQ, [1.0]);
expect(alertInstances.get(instanceID).mostRecentAction.id).toBe(FIRED_ACTIONS.id);
expect(alertInstances.get(instanceID).state.alertState).toBe(AlertStates.ALERT);
expect(mostRecentAction(instanceID).id).toBe(FIRED_ACTIONS.id);
expect(getState(instanceID).alertState).toBe(AlertStates.ALERT);
await execute(Comparator.GT_OR_EQ, [1.5]);
expect(alertInstances.get(instanceID).mostRecentAction).toBe(undefined);
expect(alertInstances.get(instanceID).state.alertState).toBe(AlertStates.OK);
expect(mostRecentAction(instanceID)).toBe(undefined);
expect(getState(instanceID).alertState).toBe(AlertStates.OK);
});
test('alerts as expected with the <= comparator', async () => {
await execute(Comparator.LT_OR_EQ, [1.5]);
expect(alertInstances.get(instanceID).mostRecentAction.id).toBe(FIRED_ACTIONS.id);
expect(alertInstances.get(instanceID).state.alertState).toBe(AlertStates.ALERT);
expect(mostRecentAction(instanceID).id).toBe(FIRED_ACTIONS.id);
expect(getState(instanceID).alertState).toBe(AlertStates.ALERT);
await execute(Comparator.LT_OR_EQ, [1.0]);
expect(alertInstances.get(instanceID).mostRecentAction.id).toBe(FIRED_ACTIONS.id);
expect(alertInstances.get(instanceID).state.alertState).toBe(AlertStates.ALERT);
expect(mostRecentAction(instanceID).id).toBe(FIRED_ACTIONS.id);
expect(getState(instanceID).alertState).toBe(AlertStates.ALERT);
await execute(Comparator.LT_OR_EQ, [0.75]);
expect(alertInstances.get(instanceID).mostRecentAction).toBe(undefined);
expect(alertInstances.get(instanceID).state.alertState).toBe(AlertStates.OK);
expect(mostRecentAction(instanceID)).toBe(undefined);
expect(getState(instanceID).alertState).toBe(AlertStates.OK);
});
test('alerts as expected with the between comparator', async () => {
await execute(Comparator.BETWEEN, [0, 1.5]);
expect(alertInstances.get(instanceID).mostRecentAction.id).toBe(FIRED_ACTIONS.id);
expect(alertInstances.get(instanceID).state.alertState).toBe(AlertStates.ALERT);
expect(mostRecentAction(instanceID).id).toBe(FIRED_ACTIONS.id);
expect(getState(instanceID).alertState).toBe(AlertStates.ALERT);
await execute(Comparator.BETWEEN, [0, 0.75]);
expect(alertInstances.get(instanceID).mostRecentAction).toBe(undefined);
expect(alertInstances.get(instanceID).state.alertState).toBe(AlertStates.OK);
expect(mostRecentAction(instanceID)).toBe(undefined);
expect(getState(instanceID).alertState).toBe(AlertStates.OK);
});
test('reports expected values to the action context', async () => {
await execute(Comparator.GT, [0.75]);
const mostRecentAction = alertInstances.get(instanceID).mostRecentAction;
expect(mostRecentAction.action.group).toBe('*');
expect(mostRecentAction.action.valueOf.condition0).toBe(1);
expect(mostRecentAction.action.thresholdOf.condition0).toStrictEqual([0.75]);
expect(mostRecentAction.action.metricOf.condition0).toBe('test.metric.1');
const { action } = mostRecentAction(instanceID);
expect(action.group).toBe('*');
expect(action.valueOf.condition0).toBe(1);
expect(action.thresholdOf.condition0).toStrictEqual([0.75]);
expect(action.metricOf.condition0).toBe('test.metric.1');
});
test('fetches the index pattern dynamically', async () => {
await execute(Comparator.LT, [17], 'alternate');
expect(alertInstances.get(instanceID).mostRecentAction.id).toBe(FIRED_ACTIONS.id);
expect(alertInstances.get(instanceID).state.alertState).toBe(AlertStates.ALERT);
expect(mostRecentAction(instanceID).id).toBe(FIRED_ACTIONS.id);
expect(getState(instanceID).alertState).toBe(AlertStates.ALERT);
await execute(Comparator.LT, [1.5], 'alternate');
expect(alertInstances.get(instanceID).mostRecentAction).toBe(undefined);
expect(alertInstances.get(instanceID).state.alertState).toBe(AlertStates.OK);
expect(mostRecentAction(instanceID)).toBe(undefined);
expect(getState(instanceID).alertState).toBe(AlertStates.OK);
});
});

Expand All @@ -171,29 +186,29 @@ describe('The metric threshold alert type', () => {
const instanceIdB = 'test-b';
test('sends an alert when all groups pass the threshold', async () => {
await execute(Comparator.GT, [0.75]);
expect(alertInstances.get(instanceIdA).mostRecentAction.id).toBe(FIRED_ACTIONS.id);
expect(alertInstances.get(instanceIdA).state.alertState).toBe(AlertStates.ALERT);
expect(alertInstances.get(instanceIdB).mostRecentAction.id).toBe(FIRED_ACTIONS.id);
expect(alertInstances.get(instanceIdB).state.alertState).toBe(AlertStates.ALERT);
expect(mostRecentAction(instanceIdA).id).toBe(FIRED_ACTIONS.id);
expect(getState(instanceIdA).alertState).toBe(AlertStates.ALERT);
expect(mostRecentAction(instanceIdB).id).toBe(FIRED_ACTIONS.id);
expect(getState(instanceIdB).alertState).toBe(AlertStates.ALERT);
});
test('sends an alert when only some groups pass the threshold', async () => {
await execute(Comparator.LT, [1.5]);
expect(alertInstances.get(instanceIdA).mostRecentAction.id).toBe(FIRED_ACTIONS.id);
expect(alertInstances.get(instanceIdA).state.alertState).toBe(AlertStates.ALERT);
expect(alertInstances.get(instanceIdB).mostRecentAction).toBe(undefined);
expect(alertInstances.get(instanceIdB).state.alertState).toBe(AlertStates.OK);
expect(mostRecentAction(instanceIdA).id).toBe(FIRED_ACTIONS.id);
expect(getState(instanceIdA).alertState).toBe(AlertStates.ALERT);
expect(mostRecentAction(instanceIdB)).toBe(undefined);
expect(getState(instanceIdB).alertState).toBe(AlertStates.OK);
});
test('sends no alert when no groups pass the threshold', async () => {
await execute(Comparator.GT, [5]);
expect(alertInstances.get(instanceIdA).mostRecentAction).toBe(undefined);
expect(alertInstances.get(instanceIdA).state.alertState).toBe(AlertStates.OK);
expect(alertInstances.get(instanceIdB).mostRecentAction).toBe(undefined);
expect(alertInstances.get(instanceIdB).state.alertState).toBe(AlertStates.OK);
expect(mostRecentAction(instanceIdA)).toBe(undefined);
expect(getState(instanceIdA).alertState).toBe(AlertStates.OK);
expect(mostRecentAction(instanceIdB)).toBe(undefined);
expect(getState(instanceIdB).alertState).toBe(AlertStates.OK);
});
test('reports group values to the action context', async () => {
await execute(Comparator.GT, [0.75]);
expect(alertInstances.get(instanceIdA).mostRecentAction.action.group).toBe('a');
expect(alertInstances.get(instanceIdB).mostRecentAction.action.group).toBe('b');
expect(mostRecentAction(instanceIdA).action.group).toBe('a');
expect(mostRecentAction(instanceIdB).action.group).toBe('b');
});
});

Expand Down Expand Up @@ -226,34 +241,34 @@ describe('The metric threshold alert type', () => {
test('sends an alert when all criteria cross the threshold', async () => {
const instanceID = 'test-*';
await execute(Comparator.GT_OR_EQ, [1.0], [3.0]);
expect(alertInstances.get(instanceID).mostRecentAction.id).toBe(FIRED_ACTIONS.id);
expect(alertInstances.get(instanceID).state.alertState).toBe(AlertStates.ALERT);
expect(mostRecentAction(instanceID).id).toBe(FIRED_ACTIONS.id);
expect(getState(instanceID).alertState).toBe(AlertStates.ALERT);
});
test('sends no alert when some, but not all, criteria cross the threshold', async () => {
const instanceID = 'test-*';
await execute(Comparator.LT_OR_EQ, [1.0], [3.0]);
expect(alertInstances.get(instanceID).mostRecentAction).toBe(undefined);
expect(alertInstances.get(instanceID).state.alertState).toBe(AlertStates.OK);
expect(mostRecentAction(instanceID)).toBe(undefined);
expect(getState(instanceID).alertState).toBe(AlertStates.OK);
});
test('alerts only on groups that meet all criteria when querying with a groupBy parameter', async () => {
const instanceIdA = 'test-a';
const instanceIdB = 'test-b';
await execute(Comparator.GT_OR_EQ, [1.0], [3.0], 'something');
expect(alertInstances.get(instanceIdA).mostRecentAction.id).toBe(FIRED_ACTIONS.id);
expect(alertInstances.get(instanceIdA).state.alertState).toBe(AlertStates.ALERT);
expect(alertInstances.get(instanceIdB).mostRecentAction).toBe(undefined);
expect(alertInstances.get(instanceIdB).state.alertState).toBe(AlertStates.OK);
expect(mostRecentAction(instanceIdA).id).toBe(FIRED_ACTIONS.id);
expect(getState(instanceIdA).alertState).toBe(AlertStates.ALERT);
expect(mostRecentAction(instanceIdB)).toBe(undefined);
expect(getState(instanceIdB).alertState).toBe(AlertStates.OK);
});
test('sends all criteria to the action context', async () => {
const instanceID = 'test-*';
await execute(Comparator.GT_OR_EQ, [1.0], [3.0]);
const mostRecentAction = alertInstances.get(instanceID).mostRecentAction;
expect(mostRecentAction.action.valueOf.condition0).toBe(1);
expect(mostRecentAction.action.valueOf.condition1).toBe(3.5);
expect(mostRecentAction.action.thresholdOf.condition0).toStrictEqual([1.0]);
expect(mostRecentAction.action.thresholdOf.condition1).toStrictEqual([3.0]);
expect(mostRecentAction.action.metricOf.condition0).toBe('test.metric.1');
expect(mostRecentAction.action.metricOf.condition1).toBe('test.metric.2');
const { action } = mostRecentAction(instanceID);
expect(action.valueOf.condition0).toBe(1);
expect(action.valueOf.condition1).toBe(3.5);
expect(action.thresholdOf.condition0).toStrictEqual([1.0]);
expect(action.thresholdOf.condition1).toStrictEqual([3.0]);
expect(action.metricOf.condition0).toBe('test.metric.1');
expect(action.metricOf.condition1).toBe('test.metric.2');
});
});
describe('querying with the count aggregator', () => {
Expand All @@ -275,11 +290,11 @@ describe('The metric threshold alert type', () => {
});
test('alerts based on the doc_count value instead of the aggregatedValue', async () => {
await execute(Comparator.GT, [2]);
expect(alertInstances.get(instanceID).mostRecentAction.id).toBe(FIRED_ACTIONS.id);
expect(alertInstances.get(instanceID).state.alertState).toBe(AlertStates.ALERT);
expect(mostRecentAction(instanceID).id).toBe(FIRED_ACTIONS.id);
expect(getState(instanceID).alertState).toBe(AlertStates.ALERT);
await execute(Comparator.LT, [1.5]);
expect(alertInstances.get(instanceID).mostRecentAction).toBe(undefined);
expect(alertInstances.get(instanceID).state.alertState).toBe(AlertStates.OK);
expect(mostRecentAction(instanceID)).toBe(undefined);
expect(getState(instanceID).alertState).toBe(AlertStates.OK);
});
});
});

0 comments on commit 13923bb

Please sign in to comment.