Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Onboard Inventory Metric Threshold rule type with FAAD #178506

Merged
merged 13 commits into from
Mar 22, 2024
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,7 @@ import {
AlertInstanceContext as AlertContext,
AlertInstanceState as AlertState,
} from '@kbn/alerting-plugin/server';
import {
AlertInstanceMock,
RuleExecutorServicesMock,
alertsMock,
} from '@kbn/alerting-plugin/server/mocks';
import { RuleExecutorServicesMock, alertsMock } from '@kbn/alerting-plugin/server/mocks';
import { LifecycleAlertServices } from '@kbn/rule-registry-plugin/server';
import { ruleRegistryMocks } from '@kbn/rule-registry-plugin/server/mocks';
import { createLifecycleRuleExecutorMock } from '@kbn/rule-registry-plugin/server/utils/create_lifecycle_rule_executor_mock';
Expand All @@ -34,13 +30,11 @@ import { logsSharedPluginMock } from '@kbn/logs-shared-plugin/server/mocks';
jest.mock('./evaluate_condition', () => ({ evaluateCondition: jest.fn() }));

interface AlertTestInstance {
instance: AlertInstanceMock;
actionQueue: any[];
state: any;
actionGroup: string;
payload: any[];
context: any[];
}

const persistAlertInstances = false;

const fakeLogger = <Meta extends LogMeta = LogMeta>(msg: string, meta?: Meta) => {};

const logger = {
Expand Down Expand Up @@ -138,46 +132,42 @@ const mockLibs = {
},
logger,
} as unknown as InfraBackendLibs;
const alerts = new Map<string, AlertTestInstance>();
let services: RuleExecutorServicesMock & LifecycleAlertServices<AlertState, AlertContext, string>;

const alertsServices = alertsMock.createRuleExecutorServices();
const services: RuleExecutorServicesMock &
LifecycleAlertServices<AlertState, AlertContext, string> = {
...alertsServices,
...ruleRegistryMocks.createLifecycleAlertServices(alertsServices),
};

const alertInstances = new Map<string, AlertTestInstance>();

services.alertFactory.create.mockImplementation((instanceID: string) => {
const newAlertInstance: AlertTestInstance = {
instance: alertsMock.createAlertFactory.create(),
actionQueue: [],
state: {},
const setup = () => {
const alertsServices = alertsMock.createRuleExecutorServices();
services = {
...alertsServices,
...ruleRegistryMocks.createLifecycleAlertServices(alertsServices),
};

const alertInstance: AlertTestInstance = persistAlertInstances
? alertInstances.get(instanceID) || newAlertInstance
: newAlertInstance;
alertInstances.set(instanceID, alertInstance);
services.alertsClient.report.mockImplementation((params: any) => {
alerts.set(params.id, { actionGroup: params.actionGroup, context: [], payload: [] });
return {
uuid: `uuid-${params.id}`,
start: new Date().toISOString(),
alertDoc: {},
};
});

(alertInstance.instance.scheduleActions as jest.Mock).mockImplementation(
(id: string, action: any) => {
alertInstance.actionQueue.push({ id, action });
return alertInstance.instance;
services.alertsClient.setAlertData.mockImplementation((params: any) => {
const alert = alerts.get(params.id);
if (alert) {
alert.payload.push(params.payload);
alert.context.push(params.context);
}
);

return alertInstance.instance;
});
});
};

function mostRecentAction(id: string) {
const instance = alertInstances.get(id);
const instance = alerts.get(id);
if (!instance) return undefined;
return instance.actionQueue.pop();
return instance.context.pop();
}

function clearInstances() {
alertInstances.clear();
alerts.clear();
}

const executor = createInventoryMetricThresholdExecutor(mockLibs);
Expand All @@ -194,6 +184,9 @@ const baseCriterion = {
describe('The inventory threshold alert type', () => {
describe('querying with Hosts and rule tags', () => {
afterAll(() => clearInstances());

setup();

const execute = (comparator: Comparator, threshold: number[], options?: any) =>
executor({
...mockOptions,
Expand All @@ -219,6 +212,18 @@ describe('The inventory threshold alert type', () => {
const instanceIdA = 'host-01';
const instanceIdB = 'host-02';

test('throws error when alertsClient is null', async () => {
try {
services.alertsClient = null;
await execute(Comparator.GT, [0.75]);
} catch (e) {
expect(e).toMatchInlineSnapshot(
'[Error: Expected alertsClient not to be null! There may have been an issue installing alert resources.]'
);
setup();
}
});

test('when tags are present in the source, rule tags and source tags are combined in alert context', async () => {
setEvaluationResults({
'host-01': {
Expand Down Expand Up @@ -255,13 +260,13 @@ describe('The inventory threshold alert type', () => {
},
});
await execute(Comparator.GT, [0.75]);
expect(mostRecentAction(instanceIdA).action.tags).toStrictEqual([
expect(mostRecentAction(instanceIdA).tags).toStrictEqual([
'host-01_tag1',
'host-01_tag2',
'ruleTag1',
'ruleTag2',
]);
expect(mostRecentAction(instanceIdB).action.tags).toStrictEqual([
expect(mostRecentAction(instanceIdB).tags).toStrictEqual([
'host-02_tag1',
'host-02_tag2',
'ruleTag1',
Expand Down Expand Up @@ -305,8 +310,8 @@ describe('The inventory threshold alert type', () => {
},
});
await execute(Comparator.GT, [0.75]);
expect(mostRecentAction(instanceIdA).action.tags).toStrictEqual(['ruleTag1', 'ruleTag2']);
expect(mostRecentAction(instanceIdB).action.tags).toStrictEqual(['ruleTag1', 'ruleTag2']);
expect(mostRecentAction(instanceIdA).tags).toStrictEqual(['ruleTag1', 'ruleTag2']);
expect(mostRecentAction(instanceIdB).tags).toStrictEqual(['ruleTag1', 'ruleTag2']);
});

test('should call evaluation query with delay', async () => {
Expand Down
Loading