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

[alerting] Adds an alertServices mock and uses it in siem, monitoring and uptime #63489

Merged
merged 6 commits into from
Apr 16, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,42 +4,27 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { savedObjectsClientMock } from 'src/core/server/mocks';
import { loggerMock } from 'src/core/server/logging/logger.mock';
import { getResult } from '../routes/__mocks__/request_responses';
import { rulesNotificationAlertType } from './rules_notification_alert_type';
import { buildSignalsSearchQuery } from './build_signals_query';
import { AlertInstance } from '../../../../../../../plugins/alerting/server';
import { alertsMock, AlertServicesMock } from '../../../../../../../plugins/alerting/server/mocks';
import { NotificationExecutorOptions } from './types';
jest.mock('./build_signals_query');

describe('rules_notification_alert_type', () => {
let payload: NotificationExecutorOptions;
let alert: ReturnType<typeof rulesNotificationAlertType>;
let alertInstanceMock: Record<string, jest.Mock>;
let alertInstanceFactoryMock: () => AlertInstance;
let savedObjectsClient: ReturnType<typeof savedObjectsClientMock.create>;
let logger: ReturnType<typeof loggerMock.create>;
let callClusterMock: jest.Mock;
let alertServices: AlertServicesMock;

beforeEach(() => {
alertInstanceMock = {
scheduleActions: jest.fn(),
replaceState: jest.fn(),
};
alertInstanceMock.replaceState.mockReturnValue(alertInstanceMock);
alertInstanceFactoryMock = jest.fn().mockReturnValue(alertInstanceMock);
callClusterMock = jest.fn();
savedObjectsClient = savedObjectsClientMock.create();
alertServices = alertsMock.createAlertServices();
logger = loggerMock.create();

payload = {
alertId: '1111',
services: {
savedObjectsClient,
alertInstanceFactory: alertInstanceFactoryMock,
callCluster: callClusterMock,
},
services: alertServices,
params: { ruleAlertId: '2222' },
state: {},
spaceId: '',
Expand All @@ -58,7 +43,7 @@ describe('rules_notification_alert_type', () => {

describe('executor', () => {
it('throws an error if rule alert was not found', async () => {
savedObjectsClient.get.mockResolvedValue({
alertServices.savedObjectsClient.get.mockResolvedValue({
id: 'id',
attributes: {},
type: 'type',
Expand All @@ -72,13 +57,13 @@ describe('rules_notification_alert_type', () => {

it('should call buildSignalsSearchQuery with proper params', async () => {
const ruleAlert = getResult();
savedObjectsClient.get.mockResolvedValue({
alertServices.savedObjectsClient.get.mockResolvedValue({
id: 'id',
type: 'type',
references: [],
attributes: ruleAlert,
});
callClusterMock.mockResolvedValue({
alertServices.callCluster.mockResolvedValue({
count: 0,
});

Expand All @@ -96,36 +81,38 @@ describe('rules_notification_alert_type', () => {

it('should not call alertInstanceFactory if signalsCount was 0', async () => {
const ruleAlert = getResult();
savedObjectsClient.get.mockResolvedValue({
alertServices.savedObjectsClient.get.mockResolvedValue({
id: 'id',
type: 'type',
references: [],
attributes: ruleAlert,
});
callClusterMock.mockResolvedValue({
alertServices.callCluster.mockResolvedValue({
count: 0,
});

await alert.executor(payload);

expect(alertInstanceFactoryMock).not.toHaveBeenCalled();
expect(alertServices.alertInstanceFactory).not.toHaveBeenCalled();
});

it('should call scheduleActions if signalsCount was greater than 0', async () => {
const ruleAlert = getResult();
savedObjectsClient.get.mockResolvedValue({
alertServices.savedObjectsClient.get.mockResolvedValue({
id: 'id',
type: 'type',
references: [],
attributes: ruleAlert,
});
callClusterMock.mockResolvedValue({
alertServices.callCluster.mockResolvedValue({
count: 10,
});

await alert.executor(payload);

expect(alertInstanceFactoryMock).toHaveBeenCalled();
expect(alertServices.alertInstanceFactory).toHaveBeenCalled();

const [{ value: alertInstanceMock }] = alertServices.alertInstanceFactory.mock.results;
expect(alertInstanceMock.replaceState).toHaveBeenCalledWith(
expect.objectContaining({ signals_count: 10 })
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,10 @@
*/

import moment from 'moment';
import { savedObjectsClientMock } from 'src/core/server/mocks';
import { loggerMock } from 'src/core/server/logging/logger.mock';
import { getResult, getMlResult } from '../routes/__mocks__/request_responses';
import { signalRulesAlertType } from './signal_rule_alert_type';
import { AlertInstance } from '../../../../../../../plugins/alerting/server';
import { alertsMock, AlertServicesMock } from '../../../../../../../plugins/alerting/server/mocks';
import { ruleStatusServiceFactory } from './rule_status_service';
import { getGapBetweenRuns } from './utils';
import { RuleExecutorOptions } from './types';
Expand All @@ -28,18 +27,9 @@ jest.mock('../notifications/schedule_notification_actions');
jest.mock('./find_ml_signals');
jest.mock('./bulk_create_ml_signals');

const getPayload = (
ruleAlert: RuleAlertType,
alertInstanceFactoryMock: () => AlertInstance,
savedObjectsClient: ReturnType<typeof savedObjectsClientMock.create>,
callClusterMock: jest.Mock
) => ({
const getPayload = (ruleAlert: RuleAlertType, services: AlertServicesMock) => ({
alertId: ruleAlert.id,
services: {
savedObjectsClient,
alertInstanceFactory: alertInstanceFactoryMock,
callCluster: callClusterMock,
},
services,
params: {
...ruleAlert.params,
actions: [],
Expand Down Expand Up @@ -78,24 +68,14 @@ describe('rules_notification_alert_type', () => {
modulesProvider: jest.fn(),
resultsServiceProvider: jest.fn(),
};
let payload: RuleExecutorOptions;
let payload: jest.Mocked<RuleExecutorOptions>;
let alert: ReturnType<typeof signalRulesAlertType>;
let alertInstanceMock: Record<string, jest.Mock>;
let alertInstanceFactoryMock: () => AlertInstance;
let savedObjectsClient: ReturnType<typeof savedObjectsClientMock.create>;
let logger: ReturnType<typeof loggerMock.create>;
let callClusterMock: jest.Mock;
let alertServices: AlertServicesMock;
let ruleStatusService: Record<string, jest.Mock>;

beforeEach(() => {
alertInstanceMock = {
scheduleActions: jest.fn(),
replaceState: jest.fn(),
};
alertInstanceMock.replaceState.mockReturnValue(alertInstanceMock);
alertInstanceFactoryMock = jest.fn().mockReturnValue(alertInstanceMock);
callClusterMock = jest.fn();
savedObjectsClient = savedObjectsClientMock.create();
alertServices = alertsMock.createAlertServices();
logger = loggerMock.create();
ruleStatusService = {
success: jest.fn(),
Expand All @@ -111,20 +91,20 @@ describe('rules_notification_alert_type', () => {
searchAfterTimes: [],
createdSignalsCount: 10,
});
callClusterMock.mockResolvedValue({
alertServices.callCluster.mockResolvedValue({
hits: {
total: { value: 10 },
},
});
const ruleAlert = getResult();
savedObjectsClient.get.mockResolvedValue({
alertServices.savedObjectsClient.get.mockResolvedValue({
id: 'id',
type: 'type',
references: [],
attributes: ruleAlert,
});

payload = getPayload(ruleAlert, alertInstanceFactoryMock, savedObjectsClient, callClusterMock);
payload = getPayload(ruleAlert, alertServices);

alert = signalRulesAlertType({
logger,
Expand Down Expand Up @@ -164,7 +144,7 @@ describe('rules_notification_alert_type', () => {
},
];

savedObjectsClient.get.mockResolvedValue({
alertServices.savedObjectsClient.get.mockResolvedValue({
id: 'id',
type: 'type',
references: [],
Expand Down Expand Up @@ -195,7 +175,7 @@ describe('rules_notification_alert_type', () => {
},
];

savedObjectsClient.get.mockResolvedValue({
alertServices.savedObjectsClient.get.mockResolvedValue({
id: 'id',
type: 'type',
references: [],
Expand All @@ -214,12 +194,7 @@ describe('rules_notification_alert_type', () => {
describe('ML rule', () => {
it('should throw an error if ML plugin was not available', async () => {
const ruleAlert = getMlResult();
payload = getPayload(
ruleAlert,
alertInstanceFactoryMock,
savedObjectsClient,
callClusterMock
);
payload = getPayload(ruleAlert, alertServices);
alert = signalRulesAlertType({
logger,
version,
Expand All @@ -235,12 +210,7 @@ describe('rules_notification_alert_type', () => {
it('should throw an error if machineLearningJobId or anomalyThreshold was not null', async () => {
const ruleAlert = getMlResult();
ruleAlert.params.anomalyThreshold = undefined;
payload = getPayload(
ruleAlert,
alertInstanceFactoryMock,
savedObjectsClient,
callClusterMock
);
payload = getPayload(ruleAlert, alertServices);
await alert.executor(payload);
expect(logger.error).toHaveBeenCalled();
expect(logger.error.mock.calls[0][0]).toContain(
Expand All @@ -250,12 +220,7 @@ describe('rules_notification_alert_type', () => {

it('should throw an error if Machine learning job summary was null', async () => {
const ruleAlert = getMlResult();
payload = getPayload(
ruleAlert,
alertInstanceFactoryMock,
savedObjectsClient,
callClusterMock
);
payload = getPayload(ruleAlert, alertServices);
jobsSummaryMock.mockResolvedValue([]);
await alert.executor(payload);
expect(logger.warn).toHaveBeenCalled();
Expand All @@ -268,12 +233,7 @@ describe('rules_notification_alert_type', () => {

it('should log an error if Machine learning job was not started', async () => {
const ruleAlert = getMlResult();
payload = getPayload(
ruleAlert,
alertInstanceFactoryMock,
savedObjectsClient,
callClusterMock
);
payload = getPayload(ruleAlert, alertServices);
jobsSummaryMock.mockResolvedValue([
{
id: 'some_job_id',
Expand All @@ -297,12 +257,7 @@ describe('rules_notification_alert_type', () => {

it('should not call ruleStatusService.success if no anomalies were found', async () => {
const ruleAlert = getMlResult();
payload = getPayload(
ruleAlert,
alertInstanceFactoryMock,
savedObjectsClient,
callClusterMock
);
payload = getPayload(ruleAlert, alertServices);
jobsSummaryMock.mockResolvedValue([]);
(findMlSignals as jest.Mock).mockResolvedValue({
hits: {
Expand All @@ -320,12 +275,7 @@ describe('rules_notification_alert_type', () => {

it('should call ruleStatusService.success if signals were created', async () => {
const ruleAlert = getMlResult();
payload = getPayload(
ruleAlert,
alertInstanceFactoryMock,
savedObjectsClient,
callClusterMock
);
payload = getPayload(ruleAlert, alertServices);
jobsSummaryMock.mockResolvedValue([
{
id: 'some_job_id',
Expand Down Expand Up @@ -360,13 +310,8 @@ describe('rules_notification_alert_type', () => {
id: '99403909-ca9b-49ba-9d7a-7e5320e68d05',
},
];
payload = getPayload(
ruleAlert,
alertInstanceFactoryMock,
savedObjectsClient,
callClusterMock
);
savedObjectsClient.get.mockResolvedValue({
payload = getPayload(ruleAlert, alertServices);
alertServices.savedObjectsClient.get.mockResolvedValue({
id: 'id',
type: 'type',
references: [],
Expand Down
41 changes: 41 additions & 0 deletions x-pack/plugins/alerting/server/mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@

import { alertsClientMock } from './alerts_client.mock';
import { PluginSetupContract, PluginStartContract } from './plugin';
import { savedObjectsClientMock } from '../../../../src/core/server/mocks';
import { createScopedSeachApiMock } from '../../../../src/plugins/data/server/mocks';
import { AlertInstance } from './alert_instance';

export { alertsClientMock };

Expand All @@ -24,7 +27,45 @@ const createStartMock = () => {
return mock;
};

const createAlertInstanceFactoryMock = () => {
const mock = {
hasScheduledActions: jest.fn(),
isThrottled: jest.fn(),
getScheduledActionOptions: jest.fn(),
unscheduleActions: jest.fn(),
getState: jest.fn(),
scheduleActions: jest.fn(),
replaceState: jest.fn(),
updateLastScheduledActions: jest.fn(),
toJSON: jest.fn(),
toRaw: jest.fn(),
};

// support chaining
mock.replaceState.mockReturnValue(mock);
mock.unscheduleActions.mockReturnValue(mock);
mock.scheduleActions.mockReturnValue(mock);

return (mock as unknown) as jest.Mocked<AlertInstance>;
};

const createAlertServicesMock = () => {
const alertInstanceFactoryMock = createAlertInstanceFactoryMock();
return {
alertInstanceFactory: jest
.fn<jest.Mocked<AlertInstance>, []>()
.mockReturnValue(alertInstanceFactoryMock),
callCluster: jest.fn(),
savedObjectsClient: savedObjectsClientMock.create(),
search: createScopedSeachApiMock().search,
};
};

export type AlertServicesMock = ReturnType<typeof createAlertServicesMock>;

export const alertsMock = {
createAlertInstanceFactory: createAlertInstanceFactoryMock,
createSetup: createSetupMock,
createStart: createStartMock,
createAlertServices: createAlertServicesMock,
};