From 85cd64192fecc93777a3e0096fb4438ccf874e95 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Wed, 21 Aug 2019 15:44:58 -0400 Subject: [PATCH 01/26] Create supporting API --- x-pack/legacy/plugins/alerting/mappings.json | 3 + .../alerting/server/alerts_client.mock.ts | 2 + .../alerting/server/alerts_client.test.ts | 580 ++++++++++-------- .../plugins/alerting/server/alerts_client.ts | 45 +- x-pack/legacy/plugins/alerting/server/init.ts | 4 + .../plugins/alerting/server/routes/index.ts | 2 + .../alerting/server/routes/mute.test.ts | 22 + .../plugins/alerting/server/routes/mute.ts | 32 + .../alerting/server/routes/unmute.test.ts | 22 + .../plugins/alerting/server/routes/unmute.ts | 32 + .../legacy/plugins/alerting/server/types.ts | 2 + .../tests/alerting/index.ts | 2 + .../tests/alerting/mute.ts | 113 ++++ .../tests/alerting/unmute.ts | 113 ++++ 14 files changed, 732 insertions(+), 242 deletions(-) create mode 100644 x-pack/legacy/plugins/alerting/server/routes/mute.test.ts create mode 100644 x-pack/legacy/plugins/alerting/server/routes/mute.ts create mode 100644 x-pack/legacy/plugins/alerting/server/routes/unmute.test.ts create mode 100644 x-pack/legacy/plugins/alerting/server/routes/unmute.ts create mode 100644 x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/mute.ts create mode 100644 x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/unmute.ts diff --git a/x-pack/legacy/plugins/alerting/mappings.json b/x-pack/legacy/plugins/alerting/mappings.json index c6ecbdf905719..3477c19e05282 100644 --- a/x-pack/legacy/plugins/alerting/mappings.json +++ b/x-pack/legacy/plugins/alerting/mappings.json @@ -40,6 +40,9 @@ }, "apiKey": { "type": "binary" + }, + "mutedInstanceIds": { + "type": "keyword" } } } diff --git a/x-pack/legacy/plugins/alerting/server/alerts_client.mock.ts b/x-pack/legacy/plugins/alerting/server/alerts_client.mock.ts index 481cb1662c78c..5225cb7e28bc2 100644 --- a/x-pack/legacy/plugins/alerting/server/alerts_client.mock.ts +++ b/x-pack/legacy/plugins/alerting/server/alerts_client.mock.ts @@ -17,6 +17,8 @@ const createAlertsClientMock = () => { update: jest.fn(), enable: jest.fn(), disable: jest.fn(), + mute: jest.fn(), + unmute: jest.fn(), }; return mocked; }; diff --git a/x-pack/legacy/plugins/alerting/server/alerts_client.test.ts b/x-pack/legacy/plugins/alerting/server/alerts_client.test.ts index c1ae81ee208ad..0442cca4df210 100644 --- a/x-pack/legacy/plugins/alerting/server/alerts_client.test.ts +++ b/x-pack/legacy/plugins/alerting/server/alerts_client.test.ts @@ -125,25 +125,25 @@ describe('create()', () => { }); const result = await alertsClient.create({ data }); expect(result).toMatchInlineSnapshot(` - Object { - "actions": Array [ - Object { - "group": "default", - "id": "1", - "params": Object { - "foo": true, - }, - }, - ], - "alertTypeId": "123", - "alertTypeParams": Object { - "bar": true, - }, - "id": "1", - "interval": "10s", - "scheduledTaskId": "task-123", - } - `); + Object { + "actions": Array [ + Object { + "group": "default", + "id": "1", + "params": Object { + "foo": true, + }, + }, + ], + "alertTypeId": "123", + "alertTypeParams": Object { + "bar": true, + }, + "id": "1", + "interval": "10s", + "scheduledTaskId": "task-123", + } + `); expect(savedObjectsClient.create).toHaveBeenCalledTimes(1); expect(savedObjectsClient.create.mock.calls[0]).toHaveLength(3); expect(savedObjectsClient.create.mock.calls[0][0]).toEqual('alert'); @@ -166,60 +166,61 @@ describe('create()', () => { "createdBy": "elastic", "enabled": true, "interval": "10s", + "mutedInstanceIds": Array [], "updatedBy": "elastic", } `); expect(savedObjectsClient.create.mock.calls[0][2]).toMatchInlineSnapshot(` - Object { - "references": Array [ - Object { - "id": "1", - "name": "action_0", - "type": "action", - }, - ], - } - `); + Object { + "references": Array [ + Object { + "id": "1", + "name": "action_0", + "type": "action", + }, + ], + } + `); expect(taskManager.schedule).toHaveBeenCalledTimes(1); expect(taskManager.schedule.mock.calls[0]).toMatchInlineSnapshot(` - Array [ - Object { - "params": Object { - "alertId": "1", - "spaceId": "default", - }, - "scope": Array [ - "alerting", - ], - "state": Object { - "alertInstances": Object {}, - "alertTypeState": Object {}, - "previousStartedAt": null, - }, - "taskType": "alerting:123", - }, - ] - `); + Array [ + Object { + "params": Object { + "alertId": "1", + "spaceId": "default", + }, + "scope": Array [ + "alerting", + ], + "state": Object { + "alertInstances": Object {}, + "alertTypeState": Object {}, + "previousStartedAt": null, + }, + "taskType": "alerting:123", + }, + ] + `); expect(savedObjectsClient.update).toHaveBeenCalledTimes(1); expect(savedObjectsClient.update.mock.calls[0]).toHaveLength(4); expect(savedObjectsClient.update.mock.calls[0][0]).toEqual('alert'); expect(savedObjectsClient.update.mock.calls[0][1]).toEqual('1'); expect(savedObjectsClient.update.mock.calls[0][2]).toMatchInlineSnapshot(` - Object { - "scheduledTaskId": "task-123", - } - `); + Object { + "scheduledTaskId": "task-123", + } + `); expect(savedObjectsClient.update.mock.calls[0][3]).toMatchInlineSnapshot(` - Object { - "references": Array [ - Object { - "id": "1", - "name": "action_0", - "type": "action", - }, - ], - } - `); + Object { + "references": Array [ + Object { + "id": "1", + "name": "action_0", + "type": "action", + }, + ], + } + `); }); test('creates a disabled alert', async () => { @@ -260,25 +261,25 @@ describe('create()', () => { }); const result = await alertsClient.create({ data }); expect(result).toMatchInlineSnapshot(` - Object { - "actions": Array [ - Object { - "group": "default", - "id": "1", - "params": Object { - "foo": true, - }, - }, - ], - "alertTypeId": "123", - "alertTypeParams": Object { - "bar": true, - }, - "enabled": false, - "id": "1", - "interval": 10000, - } - `); + Object { + "actions": Array [ + Object { + "group": "default", + "id": "1", + "params": Object { + "foo": true, + }, + }, + ], + "alertTypeId": "123", + "alertTypeParams": Object { + "bar": true, + }, + "enabled": false, + "id": "1", + "interval": 10000, + } + `); expect(savedObjectsClient.create).toHaveBeenCalledTimes(1); expect(taskManager.schedule).toHaveBeenCalledTimes(0); }); @@ -359,11 +360,11 @@ describe('create()', () => { ); expect(savedObjectsClient.delete).toHaveBeenCalledTimes(1); expect(savedObjectsClient.delete.mock.calls[0]).toMatchInlineSnapshot(` - Array [ - "alert", - "1", - ] - `); + Array [ + "alert", + "1", + ] + `); }); test('returns task manager error if cleanup fails, logs to console', async () => { @@ -408,14 +409,14 @@ describe('create()', () => { ); expect(alertsClientParams.log).toHaveBeenCalledTimes(1); expect(alertsClientParams.log.mock.calls[0]).toMatchInlineSnapshot(` - Array [ - Array [ - "alerting", - "error", - ], - "Failed to cleanup alert \\"1\\" after scheduling task failed. Error: Saved object delete error", - ] - `); + Array [ + Array [ + "alerting", + "error", + ], + "Failed to cleanup alert \\"1\\" after scheduling task failed. Error: Saved object delete error", + ] + `); }); test('throws an error if alert type not registerd', async () => { @@ -514,6 +515,7 @@ describe('create()', () => { updatedBy: 'elastic', enabled: true, interval: '10s', + mutedInstanceIds: [], }, { references: [ @@ -712,6 +714,102 @@ describe('disable()', () => { }); }); +describe('mute()', () => { + test('mutes an alert instance', async () => { + const alertsClient = new AlertsClient(alertsClientParams); + savedObjectsClient.get.mockResolvedValueOnce({ + id: '1', + type: 'alert', + attributes: { + interval: '10s', + alertTypeId: '2', + enabled: true, + scheduledTaskId: 'task-123', + mutedInstanceIds: [], + }, + references: [], + }); + + await alertsClient.mute({ alertId: '1', alertInstanceId: '2' }); + expect(savedObjectsClient.update).toHaveBeenCalledWith( + 'alert', + '1', + { + mutedInstanceIds: ['2'], + updatedBy: 'elastic', + }, + { version: undefined, references: [] } + ); + }); + + test('skips muting when alert instance already muted', async () => { + const alertsClient = new AlertsClient(alertsClientParams); + savedObjectsClient.get.mockResolvedValueOnce({ + id: '1', + type: 'alert', + attributes: { + interval: '10s', + alertTypeId: '2', + enabled: true, + scheduledTaskId: 'task-123', + mutedInstanceIds: ['2'], + }, + references: [], + }); + + await alertsClient.mute({ alertId: '1', alertInstanceId: '2' }); + expect(savedObjectsClient.update).not.toHaveBeenCalled(); + }); +}); + +describe('unmute()', () => { + test('unmutes an alert instance', async () => { + const alertsClient = new AlertsClient(alertsClientParams); + savedObjectsClient.get.mockResolvedValueOnce({ + id: '1', + type: 'alert', + attributes: { + interval: '10s', + alertTypeId: '2', + enabled: true, + scheduledTaskId: 'task-123', + mutedInstanceIds: ['2'], + }, + references: [], + }); + + await alertsClient.unmute({ alertId: '1', alertInstanceId: '2' }); + expect(savedObjectsClient.update).toHaveBeenCalledWith( + 'alert', + '1', + { + mutedInstanceIds: [], + updatedBy: 'elastic', + }, + { version: undefined, references: [] } + ); + }); + + test('skips unmuting when alert instance not muted', async () => { + const alertsClient = new AlertsClient(alertsClientParams); + savedObjectsClient.get.mockResolvedValueOnce({ + id: '1', + type: 'alert', + attributes: { + interval: '10s', + alertTypeId: '2', + enabled: true, + scheduledTaskId: 'task-123', + mutedInstanceIds: [], + }, + references: [], + }); + + await alertsClient.unmute({ alertId: '1', alertInstanceId: '2' }); + expect(savedObjectsClient.update).not.toHaveBeenCalled(); + }); +}); + describe('get()', () => { test('calls saved objects client with given params', async () => { const alertsClient = new AlertsClient(alertsClientParams); @@ -744,31 +842,31 @@ describe('get()', () => { }); const result = await alertsClient.get({ id: '1' }); expect(result).toMatchInlineSnapshot(` - Object { - "actions": Array [ - Object { - "group": "default", - "id": "1", - "params": Object { - "foo": true, - }, - }, - ], - "alertTypeId": "123", - "alertTypeParams": Object { - "bar": true, - }, - "id": "1", - "interval": "10s", - } - `); + Object { + "actions": Array [ + Object { + "group": "default", + "id": "1", + "params": Object { + "foo": true, + }, + }, + ], + "alertTypeId": "123", + "alertTypeParams": Object { + "bar": true, + }, + "id": "1", + "interval": "10s", + } + `); expect(savedObjectsClient.get).toHaveBeenCalledTimes(1); expect(savedObjectsClient.get.mock.calls[0]).toMatchInlineSnapshot(` - Array [ - "alert", - "1", - ] - `); + Array [ + "alert", + "1", + ] + `); }); test(`throws an error when references aren't found`, async () => { @@ -839,39 +937,39 @@ describe('find()', () => { }); const result = await alertsClient.find(); expect(result).toMatchInlineSnapshot(` - Object { - "data": Array [ - Object { - "actions": Array [ - Object { - "group": "default", - "id": "1", - "params": Object { - "foo": true, + Object { + "data": Array [ + Object { + "actions": Array [ + Object { + "group": "default", + "id": "1", + "params": Object { + "foo": true, + }, + }, + ], + "alertTypeId": "123", + "alertTypeParams": Object { + "bar": true, + }, + "id": "1", + "interval": "10s", }, - }, - ], - "alertTypeId": "123", - "alertTypeParams": Object { - "bar": true, - }, - "id": "1", - "interval": "10s", - }, - ], - "page": 1, - "perPage": 10, - "total": 1, - } - `); + ], + "page": 1, + "perPage": 10, + "total": 1, + } + `); expect(savedObjectsClient.find).toHaveBeenCalledTimes(1); expect(savedObjectsClient.find.mock.calls[0]).toMatchInlineSnapshot(` - Array [ - Object { - "type": "alert", - }, - ] - `); + Array [ + Object { + "type": "alert", + }, + ] + `); }); }); @@ -913,17 +1011,17 @@ describe('delete()', () => { expect(result).toEqual({ success: true }); expect(savedObjectsClient.delete).toHaveBeenCalledTimes(1); expect(savedObjectsClient.delete.mock.calls[0]).toMatchInlineSnapshot(` - Array [ - "alert", - "1", - ] - `); + Array [ + "alert", + "1", + ] + `); expect(taskManager.remove).toHaveBeenCalledTimes(1); expect(taskManager.remove.mock.calls[0]).toMatchInlineSnapshot(` - Array [ - "task-123", - ] - `); + Array [ + "task-123", + ] + `); }); }); @@ -995,60 +1093,60 @@ describe('update()', () => { }, }); expect(result).toMatchInlineSnapshot(` - Object { - "actions": Array [ - Object { - "group": "default", - "id": "1", - "params": Object { - "foo": true, - }, - }, - ], - "alertTypeParams": Object { - "bar": true, - }, - "enabled": true, - "id": "1", - "interval": "10s", - "scheduledTaskId": "task-123", - } - `); + Object { + "actions": Array [ + Object { + "group": "default", + "id": "1", + "params": Object { + "foo": true, + }, + }, + ], + "alertTypeParams": Object { + "bar": true, + }, + "enabled": true, + "id": "1", + "interval": "10s", + "scheduledTaskId": "task-123", + } + `); expect(savedObjectsClient.update).toHaveBeenCalledTimes(1); expect(savedObjectsClient.update.mock.calls[0]).toHaveLength(4); expect(savedObjectsClient.update.mock.calls[0][0]).toEqual('alert'); expect(savedObjectsClient.update.mock.calls[0][1]).toEqual('1'); expect(savedObjectsClient.update.mock.calls[0][2]).toMatchInlineSnapshot(` - Object { - "actions": Array [ - Object { - "actionRef": "action_0", - "group": "default", - "params": Object { - "foo": true, - }, - }, - ], - "alertTypeParams": Object { - "bar": true, - }, - "apiKey": null, - "interval": "10s", - "updatedBy": "elastic", - } - `); + Object { + "actions": Array [ + Object { + "actionRef": "action_0", + "group": "default", + "params": Object { + "foo": true, + }, + }, + ], + "alertTypeParams": Object { + "bar": true, + }, + "apiKey": null, + "interval": "10s", + "updatedBy": "elastic", + } + `); expect(savedObjectsClient.update.mock.calls[0][3]).toMatchInlineSnapshot(` - Object { - "references": Array [ - Object { - "id": "1", - "name": "action_0", - "type": "action", - }, - ], - "version": "123", - } - `); + Object { + "references": Array [ + Object { + "id": "1", + "name": "action_0", + "type": "action", + }, + ], + "version": "123", + } + `); }); it('calls the createApiKey function', async () => { @@ -1123,11 +1221,36 @@ describe('update()', () => { }, }); expect(result).toMatchInlineSnapshot(` + Object { + "actions": Array [ + Object { + "group": "default", + "id": "1", + "params": Object { + "foo": true, + }, + }, + ], + "alertTypeParams": Object { + "bar": true, + }, + "apiKey": "MTIzOmFiYw==", + "enabled": true, + "id": "1", + "interval": "10s", + "scheduledTaskId": "task-123", + } + `); + expect(savedObjectsClient.update).toHaveBeenCalledTimes(1); + expect(savedObjectsClient.update.mock.calls[0]).toHaveLength(4); + expect(savedObjectsClient.update.mock.calls[0][0]).toEqual('alert'); + expect(savedObjectsClient.update.mock.calls[0][1]).toEqual('1'); + expect(savedObjectsClient.update.mock.calls[0][2]).toMatchInlineSnapshot(` Object { "actions": Array [ Object { + "actionRef": "action_0", "group": "default", - "id": "1", "params": Object { "foo": true, }, @@ -1137,47 +1260,22 @@ describe('update()', () => { "bar": true, }, "apiKey": "MTIzOmFiYw==", - "enabled": true, - "id": "1", "interval": "10s", - "scheduledTaskId": "task-123", + "updatedBy": "elastic", } `); - expect(savedObjectsClient.update).toHaveBeenCalledTimes(1); - expect(savedObjectsClient.update.mock.calls[0]).toHaveLength(4); - expect(savedObjectsClient.update.mock.calls[0][0]).toEqual('alert'); - expect(savedObjectsClient.update.mock.calls[0][1]).toEqual('1'); - expect(savedObjectsClient.update.mock.calls[0][2]).toMatchInlineSnapshot(` - Object { - "actions": Array [ - Object { - "actionRef": "action_0", - "group": "default", - "params": Object { - "foo": true, - }, - }, - ], - "alertTypeParams": Object { - "bar": true, - }, - "apiKey": "MTIzOmFiYw==", - "interval": "10s", - "updatedBy": "elastic", - } - `); expect(savedObjectsClient.update.mock.calls[0][3]).toMatchInlineSnapshot(` - Object { - "references": Array [ - Object { - "id": "1", - "name": "action_0", - "type": "action", - }, - ], - "version": "123", - } - `); + Object { + "references": Array [ + Object { + "id": "1", + "name": "action_0", + "type": "action", + }, + ], + "version": "123", + } + `); }); it('should validate alertTypeParams', async () => { diff --git a/x-pack/legacy/plugins/alerting/server/alerts_client.ts b/x-pack/legacy/plugins/alerting/server/alerts_client.ts index 64db0c18fb12e..ee82a75fb383a 100644 --- a/x-pack/legacy/plugins/alerting/server/alerts_client.ts +++ b/x-pack/legacy/plugins/alerting/server/alerts_client.ts @@ -54,7 +54,10 @@ interface FindResult { } interface CreateOptions { - data: Pick>; + data: Pick< + Alert, + Exclude + >; options?: { migrationVersion?: Record; }; @@ -111,6 +114,7 @@ export class AlertsClient { ? Buffer.from(`${apiKey.result.id}:${apiKey.result.api_key}`).toString('base64') : undefined, alertTypeParams: validatedAlertTypeParams, + mutedInstanceIds: [], }); const createdAlert = await this.savedObjectsClient.create('alert', rawAlert, { ...options, @@ -255,6 +259,45 @@ export class AlertsClient { } } + public async mute({ alertId, alertInstanceId }: { alertId: string; alertInstanceId: string }) { + const existingObject = await this.savedObjectsClient.get('alert', alertId); + const mutedInstanceIds = existingObject.attributes.mutedInstanceIds || []; + if (!mutedInstanceIds.includes(alertInstanceId)) { + mutedInstanceIds.push(alertInstanceId); + await this.savedObjectsClient.update( + 'alert', + alertId, + { + mutedInstanceIds, + updatedBy: await this.getUserName(), + }, + { + version: existingObject.version, + references: existingObject.references, + } + ); + } + } + + public async unmute({ alertId, alertInstanceId }: { alertId: string; alertInstanceId: string }) { + const existingObject = await this.savedObjectsClient.get('alert', alertId); + const mutedInstanceIds = existingObject.attributes.mutedInstanceIds || []; + if (mutedInstanceIds.includes(alertInstanceId)) { + await this.savedObjectsClient.update( + 'alert', + alertId, + { + updatedBy: await this.getUserName(), + mutedInstanceIds: mutedInstanceIds.filter((id: string) => id !== alertInstanceId), + }, + { + version: existingObject.version, + references: existingObject.references, + } + ); + } + } + private async scheduleAlert(id: string, alertTypeId: string, interval: string) { return await this.taskManager.schedule({ taskType: `alerting:${alertTypeId}`, diff --git a/x-pack/legacy/plugins/alerting/server/init.ts b/x-pack/legacy/plugins/alerting/server/init.ts index 4c60ff6200ae0..c6cdff0990b21 100644 --- a/x-pack/legacy/plugins/alerting/server/init.ts +++ b/x-pack/legacy/plugins/alerting/server/init.ts @@ -27,6 +27,8 @@ import { updateAlertRoute, enableAlertRoute, disableAlertRoute, + muteAlertInstanceRoute, + unmuteAlertInstanceRoute, } from './routes'; // Extend PluginProperties to indicate which plugins are guaranteed to exist @@ -125,6 +127,8 @@ export function init(server: Server) { updateAlertRoute(server); enableAlertRoute(server); disableAlertRoute(server); + muteAlertInstanceRoute(server); + unmuteAlertInstanceRoute(server); // Expose functions server.decorate('request', 'getAlertsClient', function() { diff --git a/x-pack/legacy/plugins/alerting/server/routes/index.ts b/x-pack/legacy/plugins/alerting/server/routes/index.ts index 4fa1133c8d21b..91573a3590111 100644 --- a/x-pack/legacy/plugins/alerting/server/routes/index.ts +++ b/x-pack/legacy/plugins/alerting/server/routes/index.ts @@ -12,3 +12,5 @@ export { listAlertTypesRoute } from './list_alert_types'; export { updateAlertRoute } from './update'; export { enableAlertRoute } from './enable'; export { disableAlertRoute } from './disable'; +export { muteAlertInstanceRoute } from './mute'; +export { unmuteAlertInstanceRoute } from './unmute'; diff --git a/x-pack/legacy/plugins/alerting/server/routes/mute.test.ts b/x-pack/legacy/plugins/alerting/server/routes/mute.test.ts new file mode 100644 index 0000000000000..b7bb64a37ec8e --- /dev/null +++ b/x-pack/legacy/plugins/alerting/server/routes/mute.test.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { createMockServer } from './_mock_server'; +import { muteAlertInstanceRoute } from './mute'; + +const { server, alertsClient } = createMockServer(); +muteAlertInstanceRoute(server); + +test('mutes an alert instance', async () => { + const request = { + method: 'POST', + url: '/api/alert/1/alert_instance/2/_mute', + }; + + const { statusCode } = await server.inject(request); + expect(statusCode).toBe(204); + expect(alertsClient.mute).toHaveBeenCalledWith({ alertId: '1', alertInstanceId: '2' }); +}); diff --git a/x-pack/legacy/plugins/alerting/server/routes/mute.ts b/x-pack/legacy/plugins/alerting/server/routes/mute.ts new file mode 100644 index 0000000000000..d7b8421979a26 --- /dev/null +++ b/x-pack/legacy/plugins/alerting/server/routes/mute.ts @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import Hapi from 'hapi'; + +interface MuteRequest extends Hapi.Request { + params: { + alertId: string; + alertInstanceId: string; + }; +} + +export function muteAlertInstanceRoute(server: Hapi.Server) { + server.route({ + method: 'POST', + path: '/api/alert/{alertId}/alert_instance/{alertInstanceId}/_mute', + options: { + tags: ['access:alerting-all'], + response: { + emptyStatusCode: 204, + }, + }, + async handler(request: MuteRequest, h: Hapi.ResponseToolkit) { + const alertsClient = request.getAlertsClient!(); + await alertsClient.mute(request.params); + return h.response(); + }, + }); +} diff --git a/x-pack/legacy/plugins/alerting/server/routes/unmute.test.ts b/x-pack/legacy/plugins/alerting/server/routes/unmute.test.ts new file mode 100644 index 0000000000000..9874b2ab3d7a9 --- /dev/null +++ b/x-pack/legacy/plugins/alerting/server/routes/unmute.test.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { createMockServer } from './_mock_server'; +import { unmuteAlertInstanceRoute } from './unmute'; + +const { server, alertsClient } = createMockServer(); +unmuteAlertInstanceRoute(server); + +test('unmutes an alert instance', async () => { + const request = { + method: 'POST', + url: '/api/alert/1/alert_instance/2/_unmute', + }; + + const { statusCode } = await server.inject(request); + expect(statusCode).toBe(204); + expect(alertsClient.unmute).toHaveBeenCalledWith({ alertId: '1', alertInstanceId: '2' }); +}); diff --git a/x-pack/legacy/plugins/alerting/server/routes/unmute.ts b/x-pack/legacy/plugins/alerting/server/routes/unmute.ts new file mode 100644 index 0000000000000..150d1f6a87dc6 --- /dev/null +++ b/x-pack/legacy/plugins/alerting/server/routes/unmute.ts @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import Hapi from 'hapi'; + +interface MuteRequest extends Hapi.Request { + params: { + alertId: string; + alertInstanceId: string; + }; +} + +export function unmuteAlertInstanceRoute(server: Hapi.Server) { + server.route({ + method: 'POST', + path: '/api/alert/{alertId}/alert_instance/{alertInstanceId}/_unmute', + options: { + tags: ['access:alerting-all'], + response: { + emptyStatusCode: 204, + }, + }, + async handler(request: MuteRequest, h: Hapi.ResponseToolkit) { + const alertsClient = request.getAlertsClient!(); + await alertsClient.unmute(request.params); + return h.response(); + }, + }); +} diff --git a/x-pack/legacy/plugins/alerting/server/types.ts b/x-pack/legacy/plugins/alerting/server/types.ts index eb9ba56a10d2b..7c02eae82fa93 100644 --- a/x-pack/legacy/plugins/alerting/server/types.ts +++ b/x-pack/legacy/plugins/alerting/server/types.ts @@ -72,6 +72,7 @@ export interface Alert { createdBy: string | null; updatedBy: string | null; apiKey?: string; + mutedInstanceIds: string[]; } export interface RawAlert extends SavedObjectAttributes { @@ -84,6 +85,7 @@ export interface RawAlert extends SavedObjectAttributes { createdBy: string | null; updatedBy: string | null; apiKey?: string; + mutedInstanceIds: string[]; } export interface AlertingPlugin { diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/index.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/index.ts index 8db614feda937..2447bfaa0a6e3 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/index.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/index.ts @@ -16,6 +16,8 @@ export default function alertingTests({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./find')); loadTestFile(require.resolve('./get')); loadTestFile(require.resolve('./list_alert_types')); + loadTestFile(require.resolve('./mute')); + loadTestFile(require.resolve('./unmute')); loadTestFile(require.resolve('./update')); loadTestFile(require.resolve('./alerts')); }); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/mute.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/mute.ts new file mode 100644 index 0000000000000..923b76361e85c --- /dev/null +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/mute.ts @@ -0,0 +1,113 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import expect from '@kbn/expect'; +import { getTestAlertData } from './utils'; +import { UserAtSpaceScenarios } from '../../scenarios'; +import { getUrlPrefix, ObjectRemover } from '../../../common/lib'; +import { FtrProviderContext } from '../../../common/ftr_provider_context'; + +// eslint-disable-next-line import/no-default-export +export default function createMuteAlertInstanceTests({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + const supertestWithoutAuth = getService('supertestWithoutAuth'); + + describe('mute', () => { + const objectRemover = new ObjectRemover(supertest); + + after(() => objectRemover.removeAll()); + + for (const scenario of UserAtSpaceScenarios) { + const { user, space } = scenario; + describe(scenario.id, () => { + it('should handle mute alert instance request appropriately', async () => { + const { body: createdAlert } = await supertest + .post(`${getUrlPrefix(space.id)}/api/alert`) + .set('kbn-xsrf', 'foo') + .send(getTestAlertData({ enabled: false })) + .expect(200); + objectRemover.add(space.id, createdAlert.id, 'alert'); + + const response = await supertestWithoutAuth + .post(`${getUrlPrefix(space.id)}/api/alert/${createdAlert.id}/alert_instance/1/_mute`) + .set('kbn-xsrf', 'foo') + .auth(user.username, user.password); + + switch (scenario.id) { + case 'no_kibana_privileges at space1': + case 'space_1_all at space2': + case 'global_read at space1': + expect(response.statusCode).to.eql(404); + expect(response.body).to.eql({ + statusCode: 404, + error: 'Not Found', + message: 'Not Found', + }); + break; + case 'superuser at space1': + case 'space_1_all at space1': + expect(response.statusCode).to.eql(204); + expect(response.body).to.eql(''); + const { body: updatedAlert } = await supertestWithoutAuth + .get(`${getUrlPrefix(space.id)}/api/alert/${createdAlert.id}`) + .set('kbn-xsrf', 'foo') + .auth(user.username, user.password) + .expect(200); + expect(updatedAlert.mutedInstanceIds).to.eql(['1']); + break; + default: + throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`); + } + }); + + it('should handle mute alert instance request appropriately when muting an instance already muted', async () => { + const { body: createdAlert } = await supertest + .post(`${getUrlPrefix(space.id)}/api/alert`) + .set('kbn-xsrf', 'foo') + .send(getTestAlertData({ enabled: false })) + .expect(200); + objectRemover.add(space.id, createdAlert.id, 'alert'); + + await supertest + .post(`${getUrlPrefix(space.id)}/api/alert/${createdAlert.id}/alert_instance/1/_mute`) + .set('kbn-xsrf', 'foo') + .expect(204, ''); + + const response = await supertestWithoutAuth + .post(`${getUrlPrefix(space.id)}/api/alert/${createdAlert.id}/alert_instance/1/_mute`) + .set('kbn-xsrf', 'foo') + .auth(user.username, user.password); + + switch (scenario.id) { + case 'no_kibana_privileges at space1': + case 'space_1_all at space2': + case 'global_read at space1': + expect(response.statusCode).to.eql(404); + expect(response.body).to.eql({ + statusCode: 404, + error: 'Not Found', + message: 'Not Found', + }); + break; + case 'superuser at space1': + case 'space_1_all at space1': + expect(response.statusCode).to.eql(204); + expect(response.body).to.eql(''); + const { body: updatedAlert } = await supertestWithoutAuth + .get(`${getUrlPrefix(space.id)}/api/alert/${createdAlert.id}`) + .set('kbn-xsrf', 'foo') + .auth(user.username, user.password) + .expect(200); + expect(updatedAlert.mutedInstanceIds).to.eql(['1']); + break; + default: + throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`); + } + }); + }); + } + }); +} diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/unmute.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/unmute.ts new file mode 100644 index 0000000000000..bfe3ed35f4dc4 --- /dev/null +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/unmute.ts @@ -0,0 +1,113 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import expect from '@kbn/expect'; +import { getTestAlertData } from './utils'; +import { UserAtSpaceScenarios } from '../../scenarios'; +import { getUrlPrefix, ObjectRemover } from '../../../common/lib'; +import { FtrProviderContext } from '../../../common/ftr_provider_context'; + +// eslint-disable-next-line import/no-default-export +export default function createMuteAlertInstanceTests({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + const supertestWithoutAuth = getService('supertestWithoutAuth'); + + describe('unmute', () => { + const objectRemover = new ObjectRemover(supertest); + + after(() => objectRemover.removeAll()); + + for (const scenario of UserAtSpaceScenarios) { + const { user, space } = scenario; + describe(scenario.id, () => { + it('should handle unmute alert instance request appropriately', async () => { + const { body: createdAlert } = await supertest + .post(`${getUrlPrefix(space.id)}/api/alert`) + .set('kbn-xsrf', 'foo') + .send(getTestAlertData({ enabled: false })) + .expect(200); + objectRemover.add(space.id, createdAlert.id, 'alert'); + + await supertest + .post(`${getUrlPrefix(space.id)}/api/alert/${createdAlert.id}/alert_instance/1/_mute`) + .set('kbn-xsrf', 'foo') + .expect(204, ''); + + const response = await supertestWithoutAuth + .post(`${getUrlPrefix(space.id)}/api/alert/${createdAlert.id}/alert_instance/1/_unmute`) + .set('kbn-xsrf', 'foo') + .auth(user.username, user.password); + + switch (scenario.id) { + case 'no_kibana_privileges at space1': + case 'space_1_all at space2': + case 'global_read at space1': + expect(response.statusCode).to.eql(404); + expect(response.body).to.eql({ + statusCode: 404, + error: 'Not Found', + message: 'Not Found', + }); + break; + case 'superuser at space1': + case 'space_1_all at space1': + expect(response.statusCode).to.eql(204); + expect(response.body).to.eql(''); + const { body: updatedAlert } = await supertestWithoutAuth + .get(`${getUrlPrefix(space.id)}/api/alert/${createdAlert.id}`) + .set('kbn-xsrf', 'foo') + .auth(user.username, user.password) + .expect(200); + expect(updatedAlert.mutedInstanceIds).to.eql([]); + break; + default: + throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`); + } + }); + + it('should handle unmute alert instance request appropriately when an instance is already unmuted', async () => { + const { body: createdAlert } = await supertest + .post(`${getUrlPrefix(space.id)}/api/alert`) + .set('kbn-xsrf', 'foo') + .send(getTestAlertData({ enabled: false })) + .expect(200); + objectRemover.add(space.id, createdAlert.id, 'alert'); + + const response = await supertestWithoutAuth + .post(`${getUrlPrefix(space.id)}/api/alert/${createdAlert.id}/alert_instance/1/_unmute`) + .set('kbn-xsrf', 'foo') + .auth(user.username, user.password); + + switch (scenario.id) { + case 'no_kibana_privileges at space1': + case 'space_1_all at space2': + case 'global_read at space1': + expect(response.statusCode).to.eql(404); + expect(response.body).to.eql({ + statusCode: 404, + error: 'Not Found', + message: 'Not Found', + }); + break; + case 'superuser at space1': + case 'space_1_all at space1': + expect(response.statusCode).to.eql(204); + expect(response.body).to.eql(''); + const { body: updatedAlert } = await supertestWithoutAuth + .get(`${getUrlPrefix(space.id)}/api/alert/${createdAlert.id}`) + .set('kbn-xsrf', 'foo') + .auth(user.username, user.password) + .expect(200); + expect(updatedAlert.mutedInstanceIds).to.eql([]); + break; + default: + throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`); + } + }); + }); + } + }); +} From db605ac640f9743bbe95c8b91bf4b4e9c91d40df Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Mon, 23 Sep 2019 07:53:08 -0400 Subject: [PATCH 02/26] Rename mute terminology to mute instance to allow alert level muting --- x-pack/legacy/plugins/alerting/mappings.json | 3 +++ .../alerting/server/alerts_client.mock.ts | 4 ++-- .../alerting/server/alerts_client.test.ts | 12 ++++++------ .../plugins/alerting/server/alerts_client.ts | 16 ++++++++++++++-- .../plugins/alerting/server/routes/index.ts | 4 ++-- .../{mute.test.ts => mute_instance.test.ts} | 4 ++-- .../server/routes/{mute.ts => mute_instance.ts} | 2 +- .../{unmute.test.ts => unmute_instance.test.ts} | 4 ++-- .../routes/{unmute.ts => unmute_instance.ts} | 2 +- 9 files changed, 33 insertions(+), 18 deletions(-) rename x-pack/legacy/plugins/alerting/server/routes/{mute.test.ts => mute_instance.test.ts} (79%) rename x-pack/legacy/plugins/alerting/server/routes/{mute.ts => mute_instance.ts} (93%) rename x-pack/legacy/plugins/alerting/server/routes/{unmute.test.ts => unmute_instance.test.ts} (79%) rename x-pack/legacy/plugins/alerting/server/routes/{unmute.ts => unmute_instance.ts} (93%) diff --git a/x-pack/legacy/plugins/alerting/mappings.json b/x-pack/legacy/plugins/alerting/mappings.json index 5b5959e7b05de..84d6b67642a05 100644 --- a/x-pack/legacy/plugins/alerting/mappings.json +++ b/x-pack/legacy/plugins/alerting/mappings.json @@ -47,6 +47,9 @@ "throttle": { "type": "keyword" }, + "muted": { + "type": "boolean" + }, "mutedInstanceIds": { "type": "keyword" } diff --git a/x-pack/legacy/plugins/alerting/server/alerts_client.mock.ts b/x-pack/legacy/plugins/alerting/server/alerts_client.mock.ts index 7fca72477b21b..5342a9ffb6388 100644 --- a/x-pack/legacy/plugins/alerting/server/alerts_client.mock.ts +++ b/x-pack/legacy/plugins/alerting/server/alerts_client.mock.ts @@ -18,8 +18,8 @@ const createAlertsClientMock = () => { enable: jest.fn(), disable: jest.fn(), updateApiKey: jest.fn(), - mute: jest.fn(), - unmute: jest.fn(), + muteInstance: jest.fn(), + unmuteInstance: jest.fn(), }; return mocked; }; diff --git a/x-pack/legacy/plugins/alerting/server/alerts_client.test.ts b/x-pack/legacy/plugins/alerting/server/alerts_client.test.ts index 98b46ba374678..8877f8c15f647 100644 --- a/x-pack/legacy/plugins/alerting/server/alerts_client.test.ts +++ b/x-pack/legacy/plugins/alerting/server/alerts_client.test.ts @@ -729,7 +729,7 @@ describe('disable()', () => { }); }); -describe('mute()', () => { +describe('muteInstance()', () => { test('mutes an alert instance', async () => { const alertsClient = new AlertsClient(alertsClientParams); savedObjectsClient.get.mockResolvedValueOnce({ @@ -745,7 +745,7 @@ describe('mute()', () => { references: [], }); - await alertsClient.mute({ alertId: '1', alertInstanceId: '2' }); + await alertsClient.muteInstance({ alertId: '1', alertInstanceId: '2' }); expect(savedObjectsClient.update).toHaveBeenCalledWith( 'alert', '1', @@ -772,12 +772,12 @@ describe('mute()', () => { references: [], }); - await alertsClient.mute({ alertId: '1', alertInstanceId: '2' }); + await alertsClient.muteInstance({ alertId: '1', alertInstanceId: '2' }); expect(savedObjectsClient.update).not.toHaveBeenCalled(); }); }); -describe('unmute()', () => { +describe('unmuteInstance()', () => { test('unmutes an alert instance', async () => { const alertsClient = new AlertsClient(alertsClientParams); savedObjectsClient.get.mockResolvedValueOnce({ @@ -793,7 +793,7 @@ describe('unmute()', () => { references: [], }); - await alertsClient.unmute({ alertId: '1', alertInstanceId: '2' }); + await alertsClient.unmuteInstance({ alertId: '1', alertInstanceId: '2' }); expect(savedObjectsClient.update).toHaveBeenCalledWith( 'alert', '1', @@ -820,7 +820,7 @@ describe('unmute()', () => { references: [], }); - await alertsClient.unmute({ alertId: '1', alertInstanceId: '2' }); + await alertsClient.unmuteInstance({ alertId: '1', alertInstanceId: '2' }); expect(savedObjectsClient.update).not.toHaveBeenCalled(); }); }); diff --git a/x-pack/legacy/plugins/alerting/server/alerts_client.ts b/x-pack/legacy/plugins/alerting/server/alerts_client.ts index 7de55217e0c28..231dfb6df34ef 100644 --- a/x-pack/legacy/plugins/alerting/server/alerts_client.ts +++ b/x-pack/legacy/plugins/alerting/server/alerts_client.ts @@ -289,7 +289,13 @@ export class AlertsClient { } } - public async mute({ alertId, alertInstanceId }: { alertId: string; alertInstanceId: string }) { + public async muteInstance({ + alertId, + alertInstanceId, + }: { + alertId: string; + alertInstanceId: string; + }) { const existingObject = await this.savedObjectsClient.get('alert', alertId); const mutedInstanceIds = existingObject.attributes.mutedInstanceIds || []; if (!mutedInstanceIds.includes(alertInstanceId)) { @@ -309,7 +315,13 @@ export class AlertsClient { } } - public async unmute({ alertId, alertInstanceId }: { alertId: string; alertInstanceId: string }) { + public async unmuteInstance({ + alertId, + alertInstanceId, + }: { + alertId: string; + alertInstanceId: string; + }) { const existingObject = await this.savedObjectsClient.get('alert', alertId); const mutedInstanceIds = existingObject.attributes.mutedInstanceIds || []; if (mutedInstanceIds.includes(alertInstanceId)) { diff --git a/x-pack/legacy/plugins/alerting/server/routes/index.ts b/x-pack/legacy/plugins/alerting/server/routes/index.ts index 24402fe82a1e4..8f38d8bab2031 100644 --- a/x-pack/legacy/plugins/alerting/server/routes/index.ts +++ b/x-pack/legacy/plugins/alerting/server/routes/index.ts @@ -13,5 +13,5 @@ export { updateAlertRoute } from './update'; export { enableAlertRoute } from './enable'; export { disableAlertRoute } from './disable'; export { updateApiKeyRoute } from './update_api_key'; -export { muteAlertInstanceRoute } from './mute'; -export { unmuteAlertInstanceRoute } from './unmute'; +export { muteAlertInstanceRoute } from './mute_instance'; +export { unmuteAlertInstanceRoute } from './unmute_instance'; diff --git a/x-pack/legacy/plugins/alerting/server/routes/mute.test.ts b/x-pack/legacy/plugins/alerting/server/routes/mute_instance.test.ts similarity index 79% rename from x-pack/legacy/plugins/alerting/server/routes/mute.test.ts rename to x-pack/legacy/plugins/alerting/server/routes/mute_instance.test.ts index b7bb64a37ec8e..9ab46562d12f2 100644 --- a/x-pack/legacy/plugins/alerting/server/routes/mute.test.ts +++ b/x-pack/legacy/plugins/alerting/server/routes/mute_instance.test.ts @@ -5,7 +5,7 @@ */ import { createMockServer } from './_mock_server'; -import { muteAlertInstanceRoute } from './mute'; +import { muteAlertInstanceRoute } from './mute_instance'; const { server, alertsClient } = createMockServer(); muteAlertInstanceRoute(server); @@ -18,5 +18,5 @@ test('mutes an alert instance', async () => { const { statusCode } = await server.inject(request); expect(statusCode).toBe(204); - expect(alertsClient.mute).toHaveBeenCalledWith({ alertId: '1', alertInstanceId: '2' }); + expect(alertsClient.muteInstance).toHaveBeenCalledWith({ alertId: '1', alertInstanceId: '2' }); }); diff --git a/x-pack/legacy/plugins/alerting/server/routes/mute.ts b/x-pack/legacy/plugins/alerting/server/routes/mute_instance.ts similarity index 93% rename from x-pack/legacy/plugins/alerting/server/routes/mute.ts rename to x-pack/legacy/plugins/alerting/server/routes/mute_instance.ts index d7b8421979a26..d500c17a72b79 100644 --- a/x-pack/legacy/plugins/alerting/server/routes/mute.ts +++ b/x-pack/legacy/plugins/alerting/server/routes/mute_instance.ts @@ -25,7 +25,7 @@ export function muteAlertInstanceRoute(server: Hapi.Server) { }, async handler(request: MuteRequest, h: Hapi.ResponseToolkit) { const alertsClient = request.getAlertsClient!(); - await alertsClient.mute(request.params); + await alertsClient.muteInstance(request.params); return h.response(); }, }); diff --git a/x-pack/legacy/plugins/alerting/server/routes/unmute.test.ts b/x-pack/legacy/plugins/alerting/server/routes/unmute_instance.test.ts similarity index 79% rename from x-pack/legacy/plugins/alerting/server/routes/unmute.test.ts rename to x-pack/legacy/plugins/alerting/server/routes/unmute_instance.test.ts index 9874b2ab3d7a9..002cfdd3d8051 100644 --- a/x-pack/legacy/plugins/alerting/server/routes/unmute.test.ts +++ b/x-pack/legacy/plugins/alerting/server/routes/unmute_instance.test.ts @@ -5,7 +5,7 @@ */ import { createMockServer } from './_mock_server'; -import { unmuteAlertInstanceRoute } from './unmute'; +import { unmuteAlertInstanceRoute } from './unmute_instance'; const { server, alertsClient } = createMockServer(); unmuteAlertInstanceRoute(server); @@ -18,5 +18,5 @@ test('unmutes an alert instance', async () => { const { statusCode } = await server.inject(request); expect(statusCode).toBe(204); - expect(alertsClient.unmute).toHaveBeenCalledWith({ alertId: '1', alertInstanceId: '2' }); + expect(alertsClient.unmuteInstance).toHaveBeenCalledWith({ alertId: '1', alertInstanceId: '2' }); }); diff --git a/x-pack/legacy/plugins/alerting/server/routes/unmute.ts b/x-pack/legacy/plugins/alerting/server/routes/unmute_instance.ts similarity index 93% rename from x-pack/legacy/plugins/alerting/server/routes/unmute.ts rename to x-pack/legacy/plugins/alerting/server/routes/unmute_instance.ts index 150d1f6a87dc6..8d8ec9a2f0ecc 100644 --- a/x-pack/legacy/plugins/alerting/server/routes/unmute.ts +++ b/x-pack/legacy/plugins/alerting/server/routes/unmute_instance.ts @@ -25,7 +25,7 @@ export function unmuteAlertInstanceRoute(server: Hapi.Server) { }, async handler(request: MuteRequest, h: Hapi.ResponseToolkit) { const alertsClient = request.getAlertsClient!(); - await alertsClient.unmute(request.params); + await alertsClient.unmuteInstance(request.params); return h.response(); }, }); From a92a58d947065f5c9ee9e83082164558ea1ce3cc Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Mon, 23 Sep 2019 08:37:31 -0400 Subject: [PATCH 03/26] Add alert mute and unmute APIs --- .../alerting/server/alerts_client.mock.ts | 2 + .../alerting/server/alerts_client.test.ts | 582 ++++++++++-------- .../plugins/alerting/server/alerts_client.ts | 45 +- x-pack/legacy/plugins/alerting/server/init.ts | 4 + .../plugins/alerting/server/routes/index.ts | 2 + .../alerting/server/routes/mute.test.ts | 22 + .../plugins/alerting/server/routes/mute.ts | 31 + .../alerting/server/routes/unmute.test.ts | 22 + .../plugins/alerting/server/routes/unmute.ts | 31 + .../legacy/plugins/alerting/server/types.ts | 2 + 10 files changed, 489 insertions(+), 254 deletions(-) create mode 100644 x-pack/legacy/plugins/alerting/server/routes/mute.test.ts create mode 100644 x-pack/legacy/plugins/alerting/server/routes/mute.ts create mode 100644 x-pack/legacy/plugins/alerting/server/routes/unmute.test.ts create mode 100644 x-pack/legacy/plugins/alerting/server/routes/unmute.ts diff --git a/x-pack/legacy/plugins/alerting/server/alerts_client.mock.ts b/x-pack/legacy/plugins/alerting/server/alerts_client.mock.ts index 5342a9ffb6388..b6b6311d04e05 100644 --- a/x-pack/legacy/plugins/alerting/server/alerts_client.mock.ts +++ b/x-pack/legacy/plugins/alerting/server/alerts_client.mock.ts @@ -18,6 +18,8 @@ const createAlertsClientMock = () => { enable: jest.fn(), disable: jest.fn(), updateApiKey: jest.fn(), + mute: jest.fn(), + unmute: jest.fn(), muteInstance: jest.fn(), unmuteInstance: jest.fn(), }; diff --git a/x-pack/legacy/plugins/alerting/server/alerts_client.test.ts b/x-pack/legacy/plugins/alerting/server/alerts_client.test.ts index 8877f8c15f647..f722adc7ef089 100644 --- a/x-pack/legacy/plugins/alerting/server/alerts_client.test.ts +++ b/x-pack/legacy/plugins/alerting/server/alerts_client.test.ts @@ -127,25 +127,25 @@ describe('create()', () => { }); const result = await alertsClient.create({ data }); expect(result).toMatchInlineSnapshot(` - Object { - "actions": Array [ - Object { - "group": "default", - "id": "1", - "params": Object { - "foo": true, - }, - }, - ], - "alertTypeId": "123", - "alertTypeParams": Object { - "bar": true, - }, - "id": "1", - "interval": "10s", - "scheduledTaskId": "task-123", - } - `); + Object { + "actions": Array [ + Object { + "group": "default", + "id": "1", + "params": Object { + "foo": true, + }, + }, + ], + "alertTypeId": "123", + "alertTypeParams": Object { + "bar": true, + }, + "id": "1", + "interval": "10s", + "scheduledTaskId": "task-123", + } + `); expect(savedObjectsClient.create).toHaveBeenCalledTimes(1); expect(savedObjectsClient.create.mock.calls[0]).toHaveLength(3); expect(savedObjectsClient.create.mock.calls[0][0]).toEqual('alert'); @@ -169,62 +169,63 @@ describe('create()', () => { "createdBy": "elastic", "enabled": true, "interval": "10s", + "muted": false, "mutedInstanceIds": Array [], "throttle": null, "updatedBy": "elastic", } `); expect(savedObjectsClient.create.mock.calls[0][2]).toMatchInlineSnapshot(` - Object { - "references": Array [ - Object { - "id": "1", - "name": "action_0", - "type": "action", - }, - ], - } - `); + Object { + "references": Array [ + Object { + "id": "1", + "name": "action_0", + "type": "action", + }, + ], + } + `); expect(taskManager.schedule).toHaveBeenCalledTimes(1); expect(taskManager.schedule.mock.calls[0]).toMatchInlineSnapshot(` - Array [ - Object { - "params": Object { - "alertId": "1", - "spaceId": "default", - }, - "scope": Array [ - "alerting", - ], - "state": Object { - "alertInstances": Object {}, - "alertTypeState": Object {}, - "previousStartedAt": null, - }, - "taskType": "alerting:123", - }, - ] - `); + Array [ + Object { + "params": Object { + "alertId": "1", + "spaceId": "default", + }, + "scope": Array [ + "alerting", + ], + "state": Object { + "alertInstances": Object {}, + "alertTypeState": Object {}, + "previousStartedAt": null, + }, + "taskType": "alerting:123", + }, + ] + `); expect(savedObjectsClient.update).toHaveBeenCalledTimes(1); expect(savedObjectsClient.update.mock.calls[0]).toHaveLength(4); expect(savedObjectsClient.update.mock.calls[0][0]).toEqual('alert'); expect(savedObjectsClient.update.mock.calls[0][1]).toEqual('1'); expect(savedObjectsClient.update.mock.calls[0][2]).toMatchInlineSnapshot(` - Object { - "scheduledTaskId": "task-123", - } - `); + Object { + "scheduledTaskId": "task-123", + } + `); expect(savedObjectsClient.update.mock.calls[0][3]).toMatchInlineSnapshot(` - Object { - "references": Array [ - Object { - "id": "1", - "name": "action_0", - "type": "action", - }, - ], - } - `); + Object { + "references": Array [ + Object { + "id": "1", + "name": "action_0", + "type": "action", + }, + ], + } + `); }); test('creates a disabled alert', async () => { @@ -266,25 +267,25 @@ describe('create()', () => { }); const result = await alertsClient.create({ data }); expect(result).toMatchInlineSnapshot(` - Object { - "actions": Array [ - Object { - "group": "default", - "id": "1", - "params": Object { - "foo": true, - }, - }, - ], - "alertTypeId": "123", - "alertTypeParams": Object { - "bar": true, - }, - "enabled": false, - "id": "1", - "interval": 10000, - } - `); + Object { + "actions": Array [ + Object { + "group": "default", + "id": "1", + "params": Object { + "foo": true, + }, + }, + ], + "alertTypeId": "123", + "alertTypeParams": Object { + "bar": true, + }, + "enabled": false, + "id": "1", + "interval": 10000, + } + `); expect(savedObjectsClient.create).toHaveBeenCalledTimes(1); expect(taskManager.schedule).toHaveBeenCalledTimes(0); }); @@ -368,11 +369,11 @@ describe('create()', () => { ); expect(savedObjectsClient.delete).toHaveBeenCalledTimes(1); expect(savedObjectsClient.delete.mock.calls[0]).toMatchInlineSnapshot(` - Array [ - "alert", - "1", - ] - `); + Array [ + "alert", + "1", + ] + `); }); test('returns task manager error if cleanup fails, logs to console', async () => { @@ -418,14 +419,14 @@ describe('create()', () => { ); expect(alertsClientParams.log).toHaveBeenCalledTimes(1); expect(alertsClientParams.log.mock.calls[0]).toMatchInlineSnapshot(` - Array [ - Array [ - "alerting", - "error", - ], - "Failed to cleanup alert \\"1\\" after scheduling task failed. Error: Saved object delete error", - ] - `); + Array [ + Array [ + "alerting", + "error", + ], + "Failed to cleanup alert \\"1\\" after scheduling task failed. Error: Saved object delete error", + ] + `); }); test('throws an error if alert type not registerd', async () => { @@ -527,6 +528,7 @@ describe('create()', () => { enabled: true, interval: '10s', throttle: null, + muted: false, mutedInstanceIds: [], }, { @@ -729,6 +731,80 @@ describe('disable()', () => { }); }); +describe('mute()', () => { + test('mutes an alert', async () => { + const alertsClient = new AlertsClient(alertsClientParams); + savedObjectsClient.get.mockResolvedValueOnce({ + id: '1', + type: 'alert', + attributes: { + muted: false, + }, + references: [], + }); + + await alertsClient.mute({ id: '1' }); + expect(savedObjectsClient.update).toHaveBeenCalledWith( + 'alert', + '1', + { muted: true, updatedBy: 'elastic' }, + { references: [] } + ); + }); + + test('skips muting when alert already muted', async () => { + const alertsClient = new AlertsClient(alertsClientParams); + savedObjectsClient.get.mockResolvedValueOnce({ + id: '1', + type: 'alert', + attributes: { + muted: true, + }, + references: [], + }); + + await alertsClient.mute({ id: '1' }); + expect(savedObjectsClient.update).not.toHaveBeenCalled(); + }); +}); + +describe('unmute()', () => { + test('unmutes an alert', async () => { + const alertsClient = new AlertsClient(alertsClientParams); + savedObjectsClient.get.mockResolvedValueOnce({ + id: '1', + type: 'alert', + attributes: { + muted: true, + }, + references: [], + }); + + await alertsClient.unmute({ id: '1' }); + expect(savedObjectsClient.update).toHaveBeenCalledWith( + 'alert', + '1', + { muted: false, updatedBy: 'elastic' }, + { references: [] } + ); + }); + + test(`skips unmuting when alert isn't unmuted`, async () => { + const alertsClient = new AlertsClient(alertsClientParams); + savedObjectsClient.get.mockResolvedValueOnce({ + id: '1', + type: 'alert', + attributes: { + muted: false, + }, + references: [], + }); + + await alertsClient.unmute({ id: '1' }); + expect(savedObjectsClient.update).not.toHaveBeenCalled(); + }); +}); + describe('muteInstance()', () => { test('mutes an alert instance', async () => { const alertsClient = new AlertsClient(alertsClientParams); @@ -857,31 +933,31 @@ describe('get()', () => { }); const result = await alertsClient.get({ id: '1' }); expect(result).toMatchInlineSnapshot(` - Object { - "actions": Array [ - Object { - "group": "default", - "id": "1", - "params": Object { - "foo": true, - }, - }, - ], - "alertTypeId": "123", - "alertTypeParams": Object { - "bar": true, - }, - "id": "1", - "interval": "10s", - } - `); + Object { + "actions": Array [ + Object { + "group": "default", + "id": "1", + "params": Object { + "foo": true, + }, + }, + ], + "alertTypeId": "123", + "alertTypeParams": Object { + "bar": true, + }, + "id": "1", + "interval": "10s", + } + `); expect(savedObjectsClient.get).toHaveBeenCalledTimes(1); expect(savedObjectsClient.get.mock.calls[0]).toMatchInlineSnapshot(` - Array [ - "alert", - "1", - ] - `); + Array [ + "alert", + "1", + ] + `); }); test(`throws an error when references aren't found`, async () => { @@ -952,39 +1028,39 @@ describe('find()', () => { }); const result = await alertsClient.find(); expect(result).toMatchInlineSnapshot(` - Object { - "data": Array [ - Object { - "actions": Array [ - Object { - "group": "default", - "id": "1", - "params": Object { - "foo": true, + Object { + "data": Array [ + Object { + "actions": Array [ + Object { + "group": "default", + "id": "1", + "params": Object { + "foo": true, + }, + }, + ], + "alertTypeId": "123", + "alertTypeParams": Object { + "bar": true, + }, + "id": "1", + "interval": "10s", }, - }, - ], - "alertTypeId": "123", - "alertTypeParams": Object { - "bar": true, - }, - "id": "1", - "interval": "10s", - }, - ], - "page": 1, - "perPage": 10, - "total": 1, - } - `); + ], + "page": 1, + "perPage": 10, + "total": 1, + } + `); expect(savedObjectsClient.find).toHaveBeenCalledTimes(1); expect(savedObjectsClient.find.mock.calls[0]).toMatchInlineSnapshot(` - Array [ - Object { - "type": "alert", - }, - ] - `); + Array [ + Object { + "type": "alert", + }, + ] + `); }); }); @@ -1026,17 +1102,17 @@ describe('delete()', () => { expect(result).toEqual({ success: true }); expect(savedObjectsClient.delete).toHaveBeenCalledTimes(1); expect(savedObjectsClient.delete.mock.calls[0]).toMatchInlineSnapshot(` - Array [ - "alert", - "1", - ] - `); + Array [ + "alert", + "1", + ] + `); expect(taskManager.remove).toHaveBeenCalledTimes(1); expect(taskManager.remove.mock.calls[0]).toMatchInlineSnapshot(` - Array [ - "task-123", - ] - `); + Array [ + "task-123", + ] + `); }); }); @@ -1109,61 +1185,61 @@ describe('update()', () => { }, }); expect(result).toMatchInlineSnapshot(` - Object { - "actions": Array [ - Object { - "group": "default", - "id": "1", - "params": Object { - "foo": true, - }, - }, - ], - "alertTypeParams": Object { - "bar": true, - }, - "enabled": true, - "id": "1", - "interval": "10s", - "scheduledTaskId": "task-123", - } - `); + Object { + "actions": Array [ + Object { + "group": "default", + "id": "1", + "params": Object { + "foo": true, + }, + }, + ], + "alertTypeParams": Object { + "bar": true, + }, + "enabled": true, + "id": "1", + "interval": "10s", + "scheduledTaskId": "task-123", + } + `); expect(savedObjectsClient.update).toHaveBeenCalledTimes(1); expect(savedObjectsClient.update.mock.calls[0]).toHaveLength(4); expect(savedObjectsClient.update.mock.calls[0][0]).toEqual('alert'); expect(savedObjectsClient.update.mock.calls[0][1]).toEqual('1'); expect(savedObjectsClient.update.mock.calls[0][2]).toMatchInlineSnapshot(` - Object { - "actions": Array [ - Object { - "actionRef": "action_0", - "group": "default", - "params": Object { - "foo": true, - }, - }, - ], - "alertTypeParams": Object { - "bar": true, - }, - "apiKey": null, - "apiKeyOwner": null, - "interval": "10s", - "updatedBy": "elastic", - } - `); + Object { + "actions": Array [ + Object { + "actionRef": "action_0", + "group": "default", + "params": Object { + "foo": true, + }, + }, + ], + "alertTypeParams": Object { + "bar": true, + }, + "apiKey": null, + "apiKeyOwner": null, + "interval": "10s", + "updatedBy": "elastic", + } + `); expect(savedObjectsClient.update.mock.calls[0][3]).toMatchInlineSnapshot(` - Object { - "references": Array [ - Object { - "id": "1", - "name": "action_0", - "type": "action", - }, - ], - "version": "123", - } - `); + Object { + "references": Array [ + Object { + "id": "1", + "name": "action_0", + "type": "action", + }, + ], + "version": "123", + } + `); }); it('calls the createApiKey function', async () => { @@ -1239,62 +1315,62 @@ describe('update()', () => { }, }); expect(result).toMatchInlineSnapshot(` - Object { - "actions": Array [ - Object { - "group": "default", - "id": "1", - "params": Object { - "foo": true, - }, - }, - ], - "alertTypeParams": Object { - "bar": true, - }, - "apiKey": "MTIzOmFiYw==", - "enabled": true, - "id": "1", - "interval": "10s", - "scheduledTaskId": "task-123", - } - `); - expect(savedObjectsClient.update).toHaveBeenCalledTimes(1); - expect(savedObjectsClient.update.mock.calls[0]).toHaveLength(4); - expect(savedObjectsClient.update.mock.calls[0][0]).toEqual('alert'); - expect(savedObjectsClient.update.mock.calls[0][1]).toEqual('1'); - expect(savedObjectsClient.update.mock.calls[0][2]).toMatchInlineSnapshot(` - Object { - "actions": Array [ - Object { - "actionRef": "action_0", - "group": "default", - "params": Object { - "foo": true, - }, - }, - ], - "alertTypeParams": Object { - "bar": true, - }, - "apiKey": "MTIzOmFiYw==", - "apiKeyOwner": "elastic", - "interval": "10s", - "updatedBy": "elastic", - } - `); - expect(savedObjectsClient.update.mock.calls[0][3]).toMatchInlineSnapshot(` Object { - "references": Array [ + "actions": Array [ Object { + "group": "default", "id": "1", - "name": "action_0", - "type": "action", + "params": Object { + "foo": true, + }, }, ], - "version": "123", + "alertTypeParams": Object { + "bar": true, + }, + "apiKey": "MTIzOmFiYw==", + "enabled": true, + "id": "1", + "interval": "10s", + "scheduledTaskId": "task-123", } `); + expect(savedObjectsClient.update).toHaveBeenCalledTimes(1); + expect(savedObjectsClient.update.mock.calls[0]).toHaveLength(4); + expect(savedObjectsClient.update.mock.calls[0][0]).toEqual('alert'); + expect(savedObjectsClient.update.mock.calls[0][1]).toEqual('1'); + expect(savedObjectsClient.update.mock.calls[0][2]).toMatchInlineSnapshot(` + Object { + "actions": Array [ + Object { + "actionRef": "action_0", + "group": "default", + "params": Object { + "foo": true, + }, + }, + ], + "alertTypeParams": Object { + "bar": true, + }, + "apiKey": "MTIzOmFiYw==", + "apiKeyOwner": "elastic", + "interval": "10s", + "updatedBy": "elastic", + } + `); + expect(savedObjectsClient.update.mock.calls[0][3]).toMatchInlineSnapshot(` + Object { + "references": Array [ + Object { + "id": "1", + "name": "action_0", + "type": "action", + }, + ], + "version": "123", + } + `); }); it('should validate alertTypeParams', async () => { diff --git a/x-pack/legacy/plugins/alerting/server/alerts_client.ts b/x-pack/legacy/plugins/alerting/server/alerts_client.ts index 231dfb6df34ef..7650bfa039b8e 100644 --- a/x-pack/legacy/plugins/alerting/server/alerts_client.ts +++ b/x-pack/legacy/plugins/alerting/server/alerts_client.ts @@ -56,7 +56,13 @@ interface FindResult { } interface CreateOptions { - data: Pick>; + data: Pick< + Alert, + Exclude< + keyof Alert, + 'createdBy' | 'updatedBy' | 'apiKey' | 'apiKeyOwner' | 'muted' | 'mutedInstanceIds' + > + >; options?: { migrationVersion?: Record; }; @@ -117,6 +123,7 @@ export class AlertsClient { ? Buffer.from(`${apiKey.result.id}:${apiKey.result.api_key}`).toString('base64') : undefined, alertTypeParams: validatedAlertTypeParams, + muted: false, mutedInstanceIds: [], }); const createdAlert = await this.savedObjectsClient.create('alert', rawAlert, { @@ -289,6 +296,42 @@ export class AlertsClient { } } + public async mute({ id }: { id: string }) { + const { + references, + attributes: { muted }, + } = await this.savedObjectsClient.get('alert', id); + if (!muted) { + await this.savedObjectsClient.update( + 'alert', + id, + { + muted: true, + updatedBy: await this.getUserName(), + }, + { references } + ); + } + } + + public async unmute({ id }: { id: string }) { + const { + references, + attributes: { muted }, + } = await this.savedObjectsClient.get('alert', id); + if (muted) { + await this.savedObjectsClient.update( + 'alert', + id, + { + muted: false, + updatedBy: await this.getUserName(), + }, + { references } + ); + } + } + public async muteInstance({ alertId, alertInstanceId, diff --git a/x-pack/legacy/plugins/alerting/server/init.ts b/x-pack/legacy/plugins/alerting/server/init.ts index e896289eb0206..f62277b0508c1 100644 --- a/x-pack/legacy/plugins/alerting/server/init.ts +++ b/x-pack/legacy/plugins/alerting/server/init.ts @@ -28,6 +28,8 @@ import { enableAlertRoute, disableAlertRoute, updateApiKeyRoute, + muteAlertRoute, + unmuteAlertRoute, muteAlertInstanceRoute, unmuteAlertInstanceRoute, } from './routes'; @@ -129,6 +131,8 @@ export function init(server: Server) { enableAlertRoute(server); disableAlertRoute(server); updateApiKeyRoute(server); + muteAlertRoute(server); + unmuteAlertRoute(server); muteAlertInstanceRoute(server); unmuteAlertInstanceRoute(server); diff --git a/x-pack/legacy/plugins/alerting/server/routes/index.ts b/x-pack/legacy/plugins/alerting/server/routes/index.ts index 8f38d8bab2031..db359a672cda1 100644 --- a/x-pack/legacy/plugins/alerting/server/routes/index.ts +++ b/x-pack/legacy/plugins/alerting/server/routes/index.ts @@ -15,3 +15,5 @@ export { disableAlertRoute } from './disable'; export { updateApiKeyRoute } from './update_api_key'; export { muteAlertInstanceRoute } from './mute_instance'; export { unmuteAlertInstanceRoute } from './unmute_instance'; +export { muteAlertRoute } from './mute'; +export { unmuteAlertRoute } from './unmute'; diff --git a/x-pack/legacy/plugins/alerting/server/routes/mute.test.ts b/x-pack/legacy/plugins/alerting/server/routes/mute.test.ts new file mode 100644 index 0000000000000..6bf9ca3b938b9 --- /dev/null +++ b/x-pack/legacy/plugins/alerting/server/routes/mute.test.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { createMockServer } from './_mock_server'; +import { muteAlertRoute } from './mute'; + +const { server, alertsClient } = createMockServer(); +muteAlertRoute(server); + +test('mutes an alert', async () => { + const request = { + method: 'POST', + url: '/api/alert/1/_mute', + }; + + const { statusCode } = await server.inject(request); + expect(statusCode).toBe(204); + expect(alertsClient.mute).toHaveBeenCalledWith({ id: '1' }); +}); diff --git a/x-pack/legacy/plugins/alerting/server/routes/mute.ts b/x-pack/legacy/plugins/alerting/server/routes/mute.ts new file mode 100644 index 0000000000000..c0fa88b8632ea --- /dev/null +++ b/x-pack/legacy/plugins/alerting/server/routes/mute.ts @@ -0,0 +1,31 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import Hapi from 'hapi'; + +interface MuteRequest extends Hapi.Request { + params: { + id: string; + }; +} + +export function muteAlertRoute(server: Hapi.Server) { + server.route({ + method: 'POST', + path: '/api/alert/{id}/_mute', + options: { + tags: ['access:alerting-all'], + response: { + emptyStatusCode: 204, + }, + }, + async handler(request: MuteRequest, h: Hapi.ResponseToolkit) { + const alertsClient = request.getAlertsClient!(); + await alertsClient.mute(request.params); + return h.response(); + }, + }); +} diff --git a/x-pack/legacy/plugins/alerting/server/routes/unmute.test.ts b/x-pack/legacy/plugins/alerting/server/routes/unmute.test.ts new file mode 100644 index 0000000000000..99cb89a08665b --- /dev/null +++ b/x-pack/legacy/plugins/alerting/server/routes/unmute.test.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { createMockServer } from './_mock_server'; +import { unmuteAlertRoute } from './unmute'; + +const { server, alertsClient } = createMockServer(); +unmuteAlertRoute(server); + +test('unmutes an alert', async () => { + const request = { + method: 'POST', + url: '/api/alert/1/_unmute', + }; + + const { statusCode } = await server.inject(request); + expect(statusCode).toBe(204); + expect(alertsClient.unmute).toHaveBeenCalledWith({ id: '1' }); +}); diff --git a/x-pack/legacy/plugins/alerting/server/routes/unmute.ts b/x-pack/legacy/plugins/alerting/server/routes/unmute.ts new file mode 100644 index 0000000000000..011f122550f8f --- /dev/null +++ b/x-pack/legacy/plugins/alerting/server/routes/unmute.ts @@ -0,0 +1,31 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import Hapi from 'hapi'; + +interface UnmuteRequest extends Hapi.Request { + params: { + id: string; + }; +} + +export function unmuteAlertRoute(server: Hapi.Server) { + server.route({ + method: 'POST', + path: '/api/alert/{id}/_unmute', + options: { + tags: ['access:alerting-all'], + response: { + emptyStatusCode: 204, + }, + }, + async handler(request: UnmuteRequest, h: Hapi.ResponseToolkit) { + const alertsClient = request.getAlertsClient!(); + await alertsClient.unmute(request.params); + return h.response(); + }, + }); +} diff --git a/x-pack/legacy/plugins/alerting/server/types.ts b/x-pack/legacy/plugins/alerting/server/types.ts index 3e8716c4c965b..5b11135f85a4a 100644 --- a/x-pack/legacy/plugins/alerting/server/types.ts +++ b/x-pack/legacy/plugins/alerting/server/types.ts @@ -75,6 +75,7 @@ export interface Alert { apiKey?: string; apiKeyOwner?: string; throttle: string | null; + muted: boolean; mutedInstanceIds: string[]; } @@ -90,6 +91,7 @@ export interface RawAlert extends SavedObjectAttributes { apiKey?: string; apiKeyOwner?: string; throttle: string | null; + muted: boolean; mutedInstanceIds: string[]; } From ddcdf6edda1afa6afca19bbbb36faa3d39cd5212 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Mon, 23 Sep 2019 08:41:18 -0400 Subject: [PATCH 04/26] Add logic to handle alert muting --- .../alerting/server/lib/get_create_task_runner_function.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/x-pack/legacy/plugins/alerting/server/lib/get_create_task_runner_function.ts b/x-pack/legacy/plugins/alerting/server/lib/get_create_task_runner_function.ts index 5b5a32cfa5210..acd42292b6f17 100644 --- a/x-pack/legacy/plugins/alerting/server/lib/get_create_task_runner_function.ts +++ b/x-pack/legacy/plugins/alerting/server/lib/get_create_task_runner_function.ts @@ -74,7 +74,7 @@ export function getCreateTaskRunnerFunction({ const services = getServices(fakeRequest); // Ensure API key is still valid and user has access const { - attributes: { alertTypeParams, actions, interval, throttle }, + attributes: { alertTypeParams, actions, interval, throttle, muted, mutedInstanceIds }, references, } = await services.savedObjectsClient.get('alert', alertId); @@ -128,6 +128,10 @@ export function getCreateTaskRunnerFunction({ Object.keys(alertInstances).map(alertInstanceId => { const alertInstance = alertInstances[alertInstanceId]; if (alertInstance.hasScheduledActions(throttle)) { + if (muted || mutedInstanceIds.includes(alertInstanceId)) { + // TODO: Only log the activity, skip executing actions + return; + } const { actionGroup, context, state } = alertInstance.getSechduledActionOptions()!; alertInstance.updateLastScheduledActions(actionGroup); alertInstance.unscheduleActions(); From e6a22d4b3117981cc06953ea05a4ca045019091f Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Mon, 23 Sep 2019 09:26:33 -0400 Subject: [PATCH 05/26] Add integration tests + fix AAD breaking the object --- .../plugins/alerting/server/alerts_client.ts | 24 +++- x-pack/legacy/plugins/alerting/server/init.ts | 7 +- .../tests/alerting/alerts.ts | 134 ++++++++++++++++++ 3 files changed, 157 insertions(+), 8 deletions(-) diff --git a/x-pack/legacy/plugins/alerting/server/alerts_client.ts b/x-pack/legacy/plugins/alerting/server/alerts_client.ts index 7650bfa039b8e..8ee78719b0a66 100644 --- a/x-pack/legacy/plugins/alerting/server/alerts_client.ts +++ b/x-pack/legacy/plugins/alerting/server/alerts_client.ts @@ -75,7 +75,6 @@ interface UpdateOptions { actions: AlertAction[]; alertTypeParams: Record; }; - options?: { version?: string }; } export class AlertsClient { @@ -196,7 +195,7 @@ export class AlertsClient { return removeResult; } - public async update({ id, data, options = {} }: UpdateOptions) { + public async update({ id, data }: UpdateOptions) { const existingObject = await this.savedObjectsClient.get('alert', id); const { alertTypeId } = existingObject.attributes; const alertType = this.alertTypeRegistry.get(alertTypeId); @@ -212,6 +211,7 @@ export class AlertsClient { 'alert', id, { + ...existingObject.attributes, ...data, alertTypeParams: validatedAlertTypeParams, actions, @@ -222,15 +222,15 @@ export class AlertsClient { : null, }, { - ...options, references, + version: existingObject.version, } ); return this.getAlertFromRaw(id, updatedObject.attributes, updatedObject.references); } public async updateApiKey({ id }: { id: string }) { - const { references } = await this.savedObjectsClient.get('alert', id); + const existingObject = await this.savedObjectsClient.get('alert', id); const apiKey = await this.createAPIKey(); const username = await this.getUserName(); @@ -238,6 +238,7 @@ export class AlertsClient { 'alert', id, { + ...existingObject.attributes, updatedBy: username, apiKeyOwner: apiKey.created ? username : null, apiKey: apiKey.created @@ -245,7 +246,8 @@ export class AlertsClient { : null, }, { - references, + version: existingObject.version, + references: existingObject.references, } ); } @@ -264,6 +266,7 @@ export class AlertsClient { 'alert', id, { + ...existingObject.attributes, enabled: true, updatedBy: username, apiKeyOwner: apiKey.created ? username : null, @@ -272,7 +275,10 @@ export class AlertsClient { ? Buffer.from(`${apiKey.result.id}:${apiKey.result.api_key}`).toString('base64') : null, }, - { references: existingObject.references } + { + version: existingObject.version, + references: existingObject.references, + } ); } } @@ -284,13 +290,17 @@ export class AlertsClient { 'alert', id, { + ...existingObject.attributes, enabled: false, scheduledTaskId: null, apiKey: null, apiKeyOwner: null, updatedBy: await this.getUserName(), }, - { references: existingObject.references } + { + version: existingObject.version, + references: existingObject.references, + } ); await this.taskManager.remove(existingObject.attributes.scheduledTaskId); } diff --git a/x-pack/legacy/plugins/alerting/server/init.ts b/x-pack/legacy/plugins/alerting/server/init.ts index f62277b0508c1..b245f5d64254c 100644 --- a/x-pack/legacy/plugins/alerting/server/init.ts +++ b/x-pack/legacy/plugins/alerting/server/init.ts @@ -92,7 +92,12 @@ export function init(server: Server) { server.plugins.encrypted_saved_objects.registerType({ type: 'alert', attributesToEncrypt: new Set(['apiKey']), - attributesToExcludeFromAAD: new Set(['scheduledTaskId']), + attributesToExcludeFromAAD: new Set([ + 'scheduledTaskId', + 'muted', + 'mutedInstanceIds', + 'updatedBy', + ]), }); function getServices(request: any): Services { diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/alerts.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/alerts.ts index b29e7302189fa..0e9513b65febb 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/alerts.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/alerts.ts @@ -603,6 +603,140 @@ export default function alertTests({ getService }: FtrProviderContext) { throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`); } }); + + it(`shouldn't schedule actions when alert is muted`, async () => { + const reference = `create-test-8:${user.username}`; + const createdAction = await createIndexRecordAction(space.id); + const response = await supertestWithoutAuth + .post(`${getUrlPrefix(space.id)}/api/alert`) + .set('kbn-xsrf', 'foo') + .auth(user.username, user.password) + .send( + getTestAlertData({ + enabled: false, + interval: '1s', + alertTypeId: 'test.always-firing', + alertTypeParams: { + index: ES_TEST_INDEX_NAME, + reference, + }, + actions: [ + { + group: 'default', + id: createdAction.id, + params: { + index: ES_TEST_INDEX_NAME, + reference, + message: 'from:default', + }, + }, + ], + }) + ); + + switch (scenario.id) { + case 'no_kibana_privileges at space1': + case 'space_1_all at space2': + case 'global_read at space1': + expect(response.statusCode).to.eql(404); + expect(response.body).to.eql({ + statusCode: 404, + error: 'Not Found', + message: 'Not Found', + }); + break; + case 'space_1_all at space1': + case 'superuser at space1': + await supertestWithoutAuth + .post(`${getUrlPrefix(space.id)}/api/alert/${response.body.id}/_mute`) + .set('kbn-xsrf', 'foo') + .auth(user.username, user.password) + .expect(204, ''); + await supertestWithoutAuth + .post(`${getUrlPrefix(space.id)}/api/alert/${response.body.id}/_enable`) + .set('kbn-xsrf', 'foo') + .auth(user.username, user.password) + .expect(204, ''); + // Wait until alerts scheduled actions twice to ensure actions had a chance to execute once + await esTestIndexTool.waitForDocs('alert:test.always-firing', reference, 2); + const executedActionsResult = await esTestIndexTool.search( + 'action:test.index-record', + reference + ); + expect(executedActionsResult.hits.total.value).to.eql(0); + break; + default: + throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`); + } + }); + + it(`shouldn't schedule actions when alert instance is muted`, async () => { + const reference = `create-test-9:${user.username}`; + const createdAction = await createIndexRecordAction(space.id); + const response = await supertestWithoutAuth + .post(`${getUrlPrefix(space.id)}/api/alert`) + .set('kbn-xsrf', 'foo') + .auth(user.username, user.password) + .send( + getTestAlertData({ + enabled: false, + interval: '1s', + alertTypeId: 'test.always-firing', + alertTypeParams: { + index: ES_TEST_INDEX_NAME, + reference, + }, + actions: [ + { + group: 'default', + id: createdAction.id, + params: { + index: ES_TEST_INDEX_NAME, + reference, + message: 'from:default', + }, + }, + ], + }) + ); + + switch (scenario.id) { + case 'no_kibana_privileges at space1': + case 'space_1_all at space2': + case 'global_read at space1': + expect(response.statusCode).to.eql(404); + expect(response.body).to.eql({ + statusCode: 404, + error: 'Not Found', + message: 'Not Found', + }); + break; + case 'space_1_all at space1': + case 'superuser at space1': + await supertestWithoutAuth + .post( + `${getUrlPrefix(space.id)}/api/alert/${response.body.id}/alert_instance/1/_mute` + ) + .set('kbn-xsrf', 'foo') + .auth(user.username, user.password) + .expect(204, ''); + await supertestWithoutAuth + .post(`${getUrlPrefix(space.id)}/api/alert/${response.body.id}/_enable`) + .set('kbn-xsrf', 'foo') + .auth(user.username, user.password) + .expect(204, ''); + // Wait until alerts scheduled actions twice to ensure actions had a chance to execute once + await esTestIndexTool.waitForDocs('alert:test.always-firing', reference, 2); + const executedActionsResult = await esTestIndexTool.search( + 'action:test.index-record', + reference + ); + expect(executedActionsResult.hits.total.value).to.eql(0); + break; + default: + throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`); + } + }); }); } }); From b9527d9f04b4fd242ce6dc6ca3ef752043aa0e42 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Mon, 23 Sep 2019 10:10:39 -0400 Subject: [PATCH 06/26] Fix failing jest tests --- .../alerting/server/alerts_client.test.ts | 582 +++++++++--------- .../get_create_task_runner_function.test.ts | 1 + 2 files changed, 296 insertions(+), 287 deletions(-) diff --git a/x-pack/legacy/plugins/alerting/server/alerts_client.test.ts b/x-pack/legacy/plugins/alerting/server/alerts_client.test.ts index f722adc7ef089..71295b404af91 100644 --- a/x-pack/legacy/plugins/alerting/server/alerts_client.test.ts +++ b/x-pack/legacy/plugins/alerting/server/alerts_client.test.ts @@ -127,105 +127,105 @@ describe('create()', () => { }); const result = await alertsClient.create({ data }); expect(result).toMatchInlineSnapshot(` - Object { - "actions": Array [ - Object { - "group": "default", - "id": "1", - "params": Object { - "foo": true, - }, - }, - ], - "alertTypeId": "123", - "alertTypeParams": Object { - "bar": true, - }, - "id": "1", - "interval": "10s", - "scheduledTaskId": "task-123", - } - `); + Object { + "actions": Array [ + Object { + "group": "default", + "id": "1", + "params": Object { + "foo": true, + }, + }, + ], + "alertTypeId": "123", + "alertTypeParams": Object { + "bar": true, + }, + "id": "1", + "interval": "10s", + "scheduledTaskId": "task-123", + } + `); expect(savedObjectsClient.create).toHaveBeenCalledTimes(1); expect(savedObjectsClient.create.mock.calls[0]).toHaveLength(3); expect(savedObjectsClient.create.mock.calls[0][0]).toEqual('alert'); expect(savedObjectsClient.create.mock.calls[0][1]).toMatchInlineSnapshot(` - Object { - "actions": Array [ - Object { - "actionRef": "action_0", - "group": "default", - "params": Object { - "foo": true, - }, - }, - ], - "alertTypeId": "123", - "alertTypeParams": Object { - "bar": true, - }, - "apiKey": undefined, - "apiKeyOwner": undefined, - "createdBy": "elastic", - "enabled": true, - "interval": "10s", - "muted": false, - "mutedInstanceIds": Array [], - "throttle": null, - "updatedBy": "elastic", - } - `); + Object { + "actions": Array [ + Object { + "actionRef": "action_0", + "group": "default", + "params": Object { + "foo": true, + }, + }, + ], + "alertTypeId": "123", + "alertTypeParams": Object { + "bar": true, + }, + "apiKey": undefined, + "apiKeyOwner": undefined, + "createdBy": "elastic", + "enabled": true, + "interval": "10s", + "muted": false, + "mutedInstanceIds": Array [], + "throttle": null, + "updatedBy": "elastic", + } + `); expect(savedObjectsClient.create.mock.calls[0][2]).toMatchInlineSnapshot(` - Object { - "references": Array [ - Object { - "id": "1", - "name": "action_0", - "type": "action", - }, - ], - } - `); + Object { + "references": Array [ + Object { + "id": "1", + "name": "action_0", + "type": "action", + }, + ], + } + `); expect(taskManager.schedule).toHaveBeenCalledTimes(1); expect(taskManager.schedule.mock.calls[0]).toMatchInlineSnapshot(` - Array [ - Object { - "params": Object { - "alertId": "1", - "spaceId": "default", - }, - "scope": Array [ - "alerting", - ], - "state": Object { - "alertInstances": Object {}, - "alertTypeState": Object {}, - "previousStartedAt": null, - }, - "taskType": "alerting:123", - }, - ] - `); + Array [ + Object { + "params": Object { + "alertId": "1", + "spaceId": "default", + }, + "scope": Array [ + "alerting", + ], + "state": Object { + "alertInstances": Object {}, + "alertTypeState": Object {}, + "previousStartedAt": null, + }, + "taskType": "alerting:123", + }, + ] + `); expect(savedObjectsClient.update).toHaveBeenCalledTimes(1); expect(savedObjectsClient.update.mock.calls[0]).toHaveLength(4); expect(savedObjectsClient.update.mock.calls[0][0]).toEqual('alert'); expect(savedObjectsClient.update.mock.calls[0][1]).toEqual('1'); expect(savedObjectsClient.update.mock.calls[0][2]).toMatchInlineSnapshot(` - Object { - "scheduledTaskId": "task-123", - } - `); + Object { + "scheduledTaskId": "task-123", + } + `); expect(savedObjectsClient.update.mock.calls[0][3]).toMatchInlineSnapshot(` - Object { - "references": Array [ - Object { - "id": "1", - "name": "action_0", - "type": "action", - }, - ], - } - `); + Object { + "references": Array [ + Object { + "id": "1", + "name": "action_0", + "type": "action", + }, + ], + } + `); }); test('creates a disabled alert', async () => { @@ -267,25 +267,25 @@ describe('create()', () => { }); const result = await alertsClient.create({ data }); expect(result).toMatchInlineSnapshot(` - Object { - "actions": Array [ - Object { - "group": "default", - "id": "1", - "params": Object { - "foo": true, - }, - }, - ], - "alertTypeId": "123", - "alertTypeParams": Object { - "bar": true, - }, - "enabled": false, - "id": "1", - "interval": 10000, - } - `); + Object { + "actions": Array [ + Object { + "group": "default", + "id": "1", + "params": Object { + "foo": true, + }, + }, + ], + "alertTypeId": "123", + "alertTypeParams": Object { + "bar": true, + }, + "enabled": false, + "id": "1", + "interval": 10000, + } + `); expect(savedObjectsClient.create).toHaveBeenCalledTimes(1); expect(taskManager.schedule).toHaveBeenCalledTimes(0); }); @@ -369,11 +369,11 @@ describe('create()', () => { ); expect(savedObjectsClient.delete).toHaveBeenCalledTimes(1); expect(savedObjectsClient.delete.mock.calls[0]).toMatchInlineSnapshot(` - Array [ - "alert", - "1", - ] - `); + Array [ + "alert", + "1", + ] + `); }); test('returns task manager error if cleanup fails, logs to console', async () => { @@ -419,14 +419,14 @@ describe('create()', () => { ); expect(alertsClientParams.log).toHaveBeenCalledTimes(1); expect(alertsClientParams.log.mock.calls[0]).toMatchInlineSnapshot(` - Array [ - Array [ - "alerting", - "error", - ], - "Failed to cleanup alert \\"1\\" after scheduling task failed. Error: Saved object delete error", - ] - `); + Array [ + Array [ + "alerting", + "error", + ], + "Failed to cleanup alert \\"1\\" after scheduling task failed. Error: Saved object delete error", + ] + `); }); test('throws an error if alert type not registerd', async () => { @@ -575,6 +575,8 @@ describe('enable()', () => { 'alert', '1', { + interval: '10s', + alertTypeId: '2', enabled: true, scheduledTaskId: 'task-123', updatedBy: 'elastic', @@ -652,6 +654,8 @@ describe('enable()', () => { 'alert', '1', { + interval: '10s', + alertTypeId: '2', enabled: true, scheduledTaskId: 'task-123', apiKey: Buffer.from('123:abc').toString('base64'), @@ -698,6 +702,8 @@ describe('disable()', () => { 'alert', '1', { + interval: '10s', + alertTypeId: '2', apiKey: null, apiKeyOwner: null, enabled: false, @@ -933,31 +939,31 @@ describe('get()', () => { }); const result = await alertsClient.get({ id: '1' }); expect(result).toMatchInlineSnapshot(` - Object { - "actions": Array [ - Object { - "group": "default", - "id": "1", - "params": Object { - "foo": true, - }, - }, - ], - "alertTypeId": "123", - "alertTypeParams": Object { - "bar": true, - }, - "id": "1", - "interval": "10s", - } - `); + Object { + "actions": Array [ + Object { + "group": "default", + "id": "1", + "params": Object { + "foo": true, + }, + }, + ], + "alertTypeId": "123", + "alertTypeParams": Object { + "bar": true, + }, + "id": "1", + "interval": "10s", + } + `); expect(savedObjectsClient.get).toHaveBeenCalledTimes(1); expect(savedObjectsClient.get.mock.calls[0]).toMatchInlineSnapshot(` - Array [ - "alert", - "1", - ] - `); + Array [ + "alert", + "1", + ] + `); }); test(`throws an error when references aren't found`, async () => { @@ -1028,39 +1034,39 @@ describe('find()', () => { }); const result = await alertsClient.find(); expect(result).toMatchInlineSnapshot(` - Object { - "data": Array [ - Object { - "actions": Array [ - Object { - "group": "default", - "id": "1", - "params": Object { - "foo": true, + Object { + "data": Array [ + Object { + "actions": Array [ + Object { + "group": "default", + "id": "1", + "params": Object { + "foo": true, + }, + }, + ], + "alertTypeId": "123", + "alertTypeParams": Object { + "bar": true, + }, + "id": "1", + "interval": "10s", }, - }, - ], - "alertTypeId": "123", - "alertTypeParams": Object { - "bar": true, - }, - "id": "1", - "interval": "10s", - }, - ], - "page": 1, - "perPage": 10, - "total": 1, - } - `); + ], + "page": 1, + "perPage": 10, + "total": 1, + } + `); expect(savedObjectsClient.find).toHaveBeenCalledTimes(1); expect(savedObjectsClient.find.mock.calls[0]).toMatchInlineSnapshot(` - Array [ - Object { - "type": "alert", - }, - ] - `); + Array [ + Object { + "type": "alert", + }, + ] + `); }); }); @@ -1102,17 +1108,17 @@ describe('delete()', () => { expect(result).toEqual({ success: true }); expect(savedObjectsClient.delete).toHaveBeenCalledTimes(1); expect(savedObjectsClient.delete.mock.calls[0]).toMatchInlineSnapshot(` - Array [ - "alert", - "1", - ] - `); + Array [ + "alert", + "1", + ] + `); expect(taskManager.remove).toHaveBeenCalledTimes(1); expect(taskManager.remove.mock.calls[0]).toMatchInlineSnapshot(` - Array [ - "task-123", - ] - `); + Array [ + "task-123", + ] + `); }); }); @@ -1134,6 +1140,7 @@ describe('update()', () => { scheduledTaskId: 'task-123', }, references: [], + version: '123', }); savedObjectsClient.update.mockResolvedValueOnce({ id: '1', @@ -1180,66 +1187,66 @@ describe('update()', () => { }, ], }, - options: { - version: '123', - }, }); expect(result).toMatchInlineSnapshot(` - Object { - "actions": Array [ - Object { - "group": "default", - "id": "1", - "params": Object { - "foo": true, - }, - }, - ], - "alertTypeParams": Object { - "bar": true, - }, - "enabled": true, - "id": "1", - "interval": "10s", - "scheduledTaskId": "task-123", - } - `); + Object { + "actions": Array [ + Object { + "group": "default", + "id": "1", + "params": Object { + "foo": true, + }, + }, + ], + "alertTypeParams": Object { + "bar": true, + }, + "enabled": true, + "id": "1", + "interval": "10s", + "scheduledTaskId": "task-123", + } + `); expect(savedObjectsClient.update).toHaveBeenCalledTimes(1); expect(savedObjectsClient.update.mock.calls[0]).toHaveLength(4); expect(savedObjectsClient.update.mock.calls[0][0]).toEqual('alert'); expect(savedObjectsClient.update.mock.calls[0][1]).toEqual('1'); expect(savedObjectsClient.update.mock.calls[0][2]).toMatchInlineSnapshot(` - Object { - "actions": Array [ - Object { - "actionRef": "action_0", - "group": "default", - "params": Object { - "foo": true, - }, - }, - ], - "alertTypeParams": Object { - "bar": true, - }, - "apiKey": null, - "apiKeyOwner": null, - "interval": "10s", - "updatedBy": "elastic", - } - `); + Object { + "actions": Array [ + Object { + "actionRef": "action_0", + "group": "default", + "params": Object { + "foo": true, + }, + }, + ], + "alertTypeId": "123", + "alertTypeParams": Object { + "bar": true, + }, + "apiKey": null, + "apiKeyOwner": null, + "enabled": true, + "interval": "10s", + "scheduledTaskId": "task-123", + "updatedBy": "elastic", + } + `); expect(savedObjectsClient.update.mock.calls[0][3]).toMatchInlineSnapshot(` - Object { - "references": Array [ - Object { - "id": "1", - "name": "action_0", - "type": "action", - }, - ], - "version": "123", - } - `); + Object { + "references": Array [ + Object { + "id": "1", + "name": "action_0", + "type": "action", + }, + ], + "version": "123", + } + `); }); it('calls the createApiKey function', async () => { @@ -1259,6 +1266,7 @@ describe('update()', () => { scheduledTaskId: 'task-123', }, references: [], + version: '123', }); alertsClientParams.createAPIKey.mockResolvedValueOnce({ created: true, @@ -1310,67 +1318,67 @@ describe('update()', () => { }, ], }, - options: { - version: '123', - }, }); expect(result).toMatchInlineSnapshot(` - Object { - "actions": Array [ - Object { - "group": "default", - "id": "1", - "params": Object { - "foo": true, - }, - }, - ], - "alertTypeParams": Object { - "bar": true, - }, - "apiKey": "MTIzOmFiYw==", - "enabled": true, - "id": "1", - "interval": "10s", - "scheduledTaskId": "task-123", - } - `); - expect(savedObjectsClient.update).toHaveBeenCalledTimes(1); - expect(savedObjectsClient.update.mock.calls[0]).toHaveLength(4); - expect(savedObjectsClient.update.mock.calls[0][0]).toEqual('alert'); - expect(savedObjectsClient.update.mock.calls[0][1]).toEqual('1'); - expect(savedObjectsClient.update.mock.calls[0][2]).toMatchInlineSnapshot(` - Object { - "actions": Array [ - Object { - "actionRef": "action_0", - "group": "default", - "params": Object { - "foo": true, - }, - }, - ], - "alertTypeParams": Object { - "bar": true, - }, - "apiKey": "MTIzOmFiYw==", - "apiKeyOwner": "elastic", - "interval": "10s", - "updatedBy": "elastic", - } - `); - expect(savedObjectsClient.update.mock.calls[0][3]).toMatchInlineSnapshot(` Object { - "references": Array [ + "actions": Array [ Object { + "group": "default", "id": "1", - "name": "action_0", - "type": "action", + "params": Object { + "foo": true, + }, }, ], - "version": "123", + "alertTypeParams": Object { + "bar": true, + }, + "apiKey": "MTIzOmFiYw==", + "enabled": true, + "id": "1", + "interval": "10s", + "scheduledTaskId": "task-123", } `); + expect(savedObjectsClient.update).toHaveBeenCalledTimes(1); + expect(savedObjectsClient.update.mock.calls[0]).toHaveLength(4); + expect(savedObjectsClient.update.mock.calls[0][0]).toEqual('alert'); + expect(savedObjectsClient.update.mock.calls[0][1]).toEqual('1'); + expect(savedObjectsClient.update.mock.calls[0][2]).toMatchInlineSnapshot(` + Object { + "actions": Array [ + Object { + "actionRef": "action_0", + "group": "default", + "params": Object { + "foo": true, + }, + }, + ], + "alertTypeId": "123", + "alertTypeParams": Object { + "bar": true, + }, + "apiKey": "MTIzOmFiYw==", + "apiKeyOwner": "elastic", + "enabled": true, + "interval": "10s", + "scheduledTaskId": "task-123", + "updatedBy": "elastic", + } + `); + expect(savedObjectsClient.update.mock.calls[0][3]).toMatchInlineSnapshot(` + Object { + "references": Array [ + Object { + "id": "1", + "name": "action_0", + "type": "action", + }, + ], + "version": "123", + } + `); }); it('should validate alertTypeParams', async () => { @@ -1412,9 +1420,6 @@ describe('update()', () => { }, ], }, - options: { - version: '123', - }, }) ).rejects.toThrowErrorMatchingInlineSnapshot( `"alertTypeParams invalid: [param1]: expected value of type [string] but got [undefined]"` @@ -1445,6 +1450,9 @@ describe('updateApiKey()', () => { 'alert', '1', { + interval: '10s', + alertTypeId: '2', + enabled: true, apiKey: Buffer.from('123:abc').toString('base64'), apiKeyOwner: 'elastic', updatedBy: 'elastic', diff --git a/x-pack/legacy/plugins/alerting/server/lib/get_create_task_runner_function.test.ts b/x-pack/legacy/plugins/alerting/server/lib/get_create_task_runner_function.test.ts index b99e206c81034..2490a187ee458 100644 --- a/x-pack/legacy/plugins/alerting/server/lib/get_create_task_runner_function.test.ts +++ b/x-pack/legacy/plugins/alerting/server/lib/get_create_task_runner_function.test.ts @@ -68,6 +68,7 @@ const mockedAlertTypeSavedObject = { enabled: true, alertTypeId: '123', interval: '10s', + mutedInstanceIds: [], alertTypeParams: { bar: true, }, From 0b62a8f3f549476f46af70e97e4004cb3e046904 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Mon, 23 Sep 2019 11:17:07 -0400 Subject: [PATCH 07/26] Fix test failures --- .../security_and_spaces/tests/alerting/create.ts | 2 ++ .../security_and_spaces/tests/alerting/find.ts | 2 ++ .../security_and_spaces/tests/alerting/get.ts | 2 ++ .../security_and_spaces/tests/alerting/update.ts | 6 ++++++ .../spaces_only/tests/alerting/create.ts | 2 ++ .../spaces_only/tests/alerting/find.ts | 2 ++ .../spaces_only/tests/alerting/get.ts | 2 ++ .../spaces_only/tests/alerting/update.ts | 6 ++++++ 8 files changed, 24 insertions(+) diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/create.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/create.ts index f92ea085cdbfa..af793fed1cccf 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/create.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/create.ts @@ -64,6 +64,8 @@ export default function createAlertTests({ getService }: FtrProviderContext) { throttle: '1m', updatedBy: user.username, apiKeyOwner: user.username, + muted: false, + mutedInstanceIds: [], }); expect(typeof response.body.scheduledTaskId).to.be('string'); const { _source: taskRecord } = await getScheduledTask(response.body.scheduledTaskId); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/find.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/find.ts index 429c43b3c44d6..fe77b02e10558 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/find.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/find.ts @@ -66,6 +66,8 @@ export default function createFindTests({ getService }: FtrProviderContext) { throttle: '1m', updatedBy: 'elastic', apiKeyOwner: 'elastic', + muted: false, + mutedInstanceIds: [], }); break; default: diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/get.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/get.ts index d189844dc4be8..250695d3a943b 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/get.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/get.ts @@ -60,6 +60,8 @@ export default function createGetTests({ getService }: FtrProviderContext) { throttle: '1m', updatedBy: 'elastic', apiKeyOwner: 'elastic', + muted: false, + mutedInstanceIds: [], }); break; default: diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/update.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/update.ts index c6fe9ca6da9b4..468e70e26d795 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/update.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/update.ts @@ -61,8 +61,14 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { expect(response.body).to.eql({ ...updatedData, id: createdAlert.id, + alertTypeId: 'test.noop', + createdBy: 'elastic', + enabled: true, updatedBy: user.username, apiKeyOwner: user.username, + muted: false, + mutedInstanceIds: [], + scheduledTaskId: createdAlert.scheduledTaskId, }); break; default: diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/create.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/create.ts index ebd82a819c502..7dcc4d0ba5c19 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/create.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/create.ts @@ -45,6 +45,8 @@ export default function createAlertTests({ getService }: FtrProviderContext) { scheduledTaskId: response.body.scheduledTaskId, updatedBy: null, throttle: '1m', + muted: false, + mutedInstanceIds: [], }); expect(typeof response.body.scheduledTaskId).to.be('string'); const { _source: taskRecord } = await getScheduledTask(response.body.scheduledTaskId); diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/find.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/find.ts index e90475f8cf80b..4b4c29ee51754 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/find.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/find.ts @@ -48,6 +48,8 @@ export default function createFindTests({ getService }: FtrProviderContext) { scheduledTaskId: match.scheduledTaskId, updatedBy: null, throttle: '1m', + muted: false, + mutedInstanceIds: [], }); }); diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/get.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/get.ts index 3848bac4c44ef..062b5f4048512 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/get.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/get.ts @@ -42,6 +42,8 @@ export default function createGetTests({ getService }: FtrProviderContext) { scheduledTaskId: response.body.scheduledTaskId, updatedBy: null, throttle: '1m', + muted: false, + mutedInstanceIds: [], }); }); diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/update.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/update.ts index 97311daac2099..80cac9507d354 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/update.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/update.ts @@ -40,8 +40,14 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { .expect(200, { ...updatedData, id: createdAlert.id, + alertTypeId: 'test.noop', + createdBy: null, + enabled: true, updatedBy: null, apiKeyOwner: null, + muted: false, + mutedInstanceIds: [], + scheduledTaskId: createdAlert.scheduledTaskId, }); }); From a0266f82d7d91e059da2fe123e5c292c0f1815f9 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Mon, 23 Sep 2019 14:43:45 -0400 Subject: [PATCH 08/26] Clear out mutedInstanceIds when muting / unmuting an alert --- x-pack/legacy/plugins/alerting/server/alerts_client.test.ts | 4 ++-- x-pack/legacy/plugins/alerting/server/alerts_client.ts | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/x-pack/legacy/plugins/alerting/server/alerts_client.test.ts b/x-pack/legacy/plugins/alerting/server/alerts_client.test.ts index 71295b404af91..78e4db5f63d20 100644 --- a/x-pack/legacy/plugins/alerting/server/alerts_client.test.ts +++ b/x-pack/legacy/plugins/alerting/server/alerts_client.test.ts @@ -753,7 +753,7 @@ describe('mute()', () => { expect(savedObjectsClient.update).toHaveBeenCalledWith( 'alert', '1', - { muted: true, updatedBy: 'elastic' }, + { muted: true, mutedInstanceIds: [], updatedBy: 'elastic' }, { references: [] } ); }); @@ -790,7 +790,7 @@ describe('unmute()', () => { expect(savedObjectsClient.update).toHaveBeenCalledWith( 'alert', '1', - { muted: false, updatedBy: 'elastic' }, + { muted: false, mutedInstanceIds: [], updatedBy: 'elastic' }, { references: [] } ); }); diff --git a/x-pack/legacy/plugins/alerting/server/alerts_client.ts b/x-pack/legacy/plugins/alerting/server/alerts_client.ts index 8ee78719b0a66..01bf50c126143 100644 --- a/x-pack/legacy/plugins/alerting/server/alerts_client.ts +++ b/x-pack/legacy/plugins/alerting/server/alerts_client.ts @@ -317,6 +317,7 @@ export class AlertsClient { id, { muted: true, + mutedInstanceIds: [], updatedBy: await this.getUserName(), }, { references } @@ -335,6 +336,7 @@ export class AlertsClient { id, { muted: false, + mutedInstanceIds: [], updatedBy: await this.getUserName(), }, { references } From 45aebfdda906ce9074e35c2742c5c4f53883afa7 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Mon, 23 Sep 2019 15:37:54 -0400 Subject: [PATCH 09/26] Skip muting / unmuting instances when alert is muted --- .../alerting/server/alerts_client.test.ts | 40 +++++++++++++++++++ .../plugins/alerting/server/alerts_client.ts | 4 +- 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/x-pack/legacy/plugins/alerting/server/alerts_client.test.ts b/x-pack/legacy/plugins/alerting/server/alerts_client.test.ts index 78e4db5f63d20..f8f8d34148c7f 100644 --- a/x-pack/legacy/plugins/alerting/server/alerts_client.test.ts +++ b/x-pack/legacy/plugins/alerting/server/alerts_client.test.ts @@ -857,6 +857,26 @@ describe('muteInstance()', () => { await alertsClient.muteInstance({ alertId: '1', alertInstanceId: '2' }); expect(savedObjectsClient.update).not.toHaveBeenCalled(); }); + + test('skips muting when alert is muted', async () => { + const alertsClient = new AlertsClient(alertsClientParams); + savedObjectsClient.get.mockResolvedValueOnce({ + id: '1', + type: 'alert', + attributes: { + interval: '10s', + alertTypeId: '2', + enabled: true, + scheduledTaskId: 'task-123', + mutedInstanceIds: [], + muted: true, + }, + references: [], + }); + + await alertsClient.muteInstance({ alertId: '1', alertInstanceId: '2' }); + expect(savedObjectsClient.update).not.toHaveBeenCalled(); + }); }); describe('unmuteInstance()', () => { @@ -905,6 +925,26 @@ describe('unmuteInstance()', () => { await alertsClient.unmuteInstance({ alertId: '1', alertInstanceId: '2' }); expect(savedObjectsClient.update).not.toHaveBeenCalled(); }); + + test('skips unmuting when alert is muted', async () => { + const alertsClient = new AlertsClient(alertsClientParams); + savedObjectsClient.get.mockResolvedValueOnce({ + id: '1', + type: 'alert', + attributes: { + interval: '10s', + alertTypeId: '2', + enabled: true, + scheduledTaskId: 'task-123', + mutedInstanceIds: [], + muted: true, + }, + references: [], + }); + + await alertsClient.unmuteInstance({ alertId: '1', alertInstanceId: '2' }); + expect(savedObjectsClient.update).not.toHaveBeenCalled(); + }); }); describe('get()', () => { diff --git a/x-pack/legacy/plugins/alerting/server/alerts_client.ts b/x-pack/legacy/plugins/alerting/server/alerts_client.ts index 01bf50c126143..ba383771ee58f 100644 --- a/x-pack/legacy/plugins/alerting/server/alerts_client.ts +++ b/x-pack/legacy/plugins/alerting/server/alerts_client.ts @@ -353,7 +353,7 @@ export class AlertsClient { }) { const existingObject = await this.savedObjectsClient.get('alert', alertId); const mutedInstanceIds = existingObject.attributes.mutedInstanceIds || []; - if (!mutedInstanceIds.includes(alertInstanceId)) { + if (!existingObject.attributes.muted && !mutedInstanceIds.includes(alertInstanceId)) { mutedInstanceIds.push(alertInstanceId); await this.savedObjectsClient.update( 'alert', @@ -379,7 +379,7 @@ export class AlertsClient { }) { const existingObject = await this.savedObjectsClient.get('alert', alertId); const mutedInstanceIds = existingObject.attributes.mutedInstanceIds || []; - if (mutedInstanceIds.includes(alertInstanceId)) { + if (!existingObject.attributes.muted && mutedInstanceIds.includes(alertInstanceId)) { await this.savedObjectsClient.update( 'alert', alertId, From 4c63dd2f140d1b071d5a8c859231e7ee68f119fb Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Mon, 23 Sep 2019 15:59:55 -0400 Subject: [PATCH 10/26] Rename interface for alert instance --- x-pack/legacy/plugins/alerting/server/routes/mute_instance.ts | 4 ++-- .../legacy/plugins/alerting/server/routes/unmute_instance.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/x-pack/legacy/plugins/alerting/server/routes/mute_instance.ts b/x-pack/legacy/plugins/alerting/server/routes/mute_instance.ts index d500c17a72b79..90d3b116f6617 100644 --- a/x-pack/legacy/plugins/alerting/server/routes/mute_instance.ts +++ b/x-pack/legacy/plugins/alerting/server/routes/mute_instance.ts @@ -6,7 +6,7 @@ import Hapi from 'hapi'; -interface MuteRequest extends Hapi.Request { +interface MuteInstanceRequest extends Hapi.Request { params: { alertId: string; alertInstanceId: string; @@ -23,7 +23,7 @@ export function muteAlertInstanceRoute(server: Hapi.Server) { emptyStatusCode: 204, }, }, - async handler(request: MuteRequest, h: Hapi.ResponseToolkit) { + async handler(request: MuteInstanceRequest, h: Hapi.ResponseToolkit) { const alertsClient = request.getAlertsClient!(); await alertsClient.muteInstance(request.params); return h.response(); diff --git a/x-pack/legacy/plugins/alerting/server/routes/unmute_instance.ts b/x-pack/legacy/plugins/alerting/server/routes/unmute_instance.ts index 8d8ec9a2f0ecc..2adc847d02629 100644 --- a/x-pack/legacy/plugins/alerting/server/routes/unmute_instance.ts +++ b/x-pack/legacy/plugins/alerting/server/routes/unmute_instance.ts @@ -6,7 +6,7 @@ import Hapi from 'hapi'; -interface MuteRequest extends Hapi.Request { +interface UnmuteInstanceRequest extends Hapi.Request { params: { alertId: string; alertInstanceId: string; @@ -23,7 +23,7 @@ export function unmuteAlertInstanceRoute(server: Hapi.Server) { emptyStatusCode: 204, }, }, - async handler(request: MuteRequest, h: Hapi.ResponseToolkit) { + async handler(request: UnmuteInstanceRequest, h: Hapi.ResponseToolkit) { const alertsClient = request.getAlertsClient!(); await alertsClient.unmuteInstance(request.params); return h.response(); From 68eb6e9b2cdd586f7c3f76346a10837499bf3a2f Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Mon, 23 Sep 2019 16:08:51 -0400 Subject: [PATCH 11/26] Rename functional tests to alert instance terminology --- .../tests/alerting/index.ts | 4 +- .../alerting/{mute.ts => mute_instance.ts} | 2 +- .../{unmute.ts => unmute_instance.ts} | 2 +- .../spaces_only/tests/alerting/index.ts | 2 + .../tests/alerting/mute_instance.ts | 43 ++++++++++++++++ .../tests/alerting/unmute_instance.ts | 50 +++++++++++++++++++ 6 files changed, 99 insertions(+), 4 deletions(-) rename x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/{mute.ts => mute_instance.ts} (99%) rename x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/{unmute.ts => unmute_instance.ts} (99%) create mode 100644 x-pack/test/alerting_api_integration/spaces_only/tests/alerting/mute_instance.ts create mode 100644 x-pack/test/alerting_api_integration/spaces_only/tests/alerting/unmute_instance.ts diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/index.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/index.ts index debdc724a0a1b..7fdbb57bba1d6 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/index.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/index.ts @@ -16,8 +16,8 @@ export default function alertingTests({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./find')); loadTestFile(require.resolve('./get')); loadTestFile(require.resolve('./list_alert_types')); - loadTestFile(require.resolve('./mute')); - loadTestFile(require.resolve('./unmute')); + loadTestFile(require.resolve('./mute_instance')); + loadTestFile(require.resolve('./unmute_instance')); loadTestFile(require.resolve('./update')); loadTestFile(require.resolve('./update_api_key')); loadTestFile(require.resolve('./alerts')); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/mute.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/mute_instance.ts similarity index 99% rename from x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/mute.ts rename to x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/mute_instance.ts index 437cca556fa2e..f03d5d6021a93 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/mute.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/mute_instance.ts @@ -14,7 +14,7 @@ export default function createMuteAlertInstanceTests({ getService }: FtrProvider const supertest = getService('supertest'); const supertestWithoutAuth = getService('supertestWithoutAuth'); - describe('mute', () => { + describe('mute_instance', () => { const objectRemover = new ObjectRemover(supertest); after(() => objectRemover.removeAll()); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/unmute.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/unmute_instance.ts similarity index 99% rename from x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/unmute.ts rename to x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/unmute_instance.ts index ac649ddcc4ff0..c2718bb670eae 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/unmute.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/unmute_instance.ts @@ -14,7 +14,7 @@ export default function createMuteAlertInstanceTests({ getService }: FtrProvider const supertest = getService('supertest'); const supertestWithoutAuth = getService('supertestWithoutAuth'); - describe('unmute', () => { + describe('unmute_instance', () => { const objectRemover = new ObjectRemover(supertest); after(() => objectRemover.removeAll()); diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/index.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/index.ts index 0774bdc17fd22..7fdbb57bba1d6 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/index.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/index.ts @@ -16,6 +16,8 @@ export default function alertingTests({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./find')); loadTestFile(require.resolve('./get')); loadTestFile(require.resolve('./list_alert_types')); + loadTestFile(require.resolve('./mute_instance')); + loadTestFile(require.resolve('./unmute_instance')); loadTestFile(require.resolve('./update')); loadTestFile(require.resolve('./update_api_key')); loadTestFile(require.resolve('./alerts')); diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/mute_instance.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/mute_instance.ts new file mode 100644 index 0000000000000..f9bc602c62fda --- /dev/null +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/mute_instance.ts @@ -0,0 +1,43 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import expect from '@kbn/expect'; +import { Spaces } from '../../scenarios'; +import { getUrlPrefix, getTestAlertData, ObjectRemover } from '../../../common/lib'; +import { FtrProviderContext } from '../../../common/ftr_provider_context'; + +// eslint-disable-next-line import/no-default-export +export default function createMuteInstanceTests({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + + describe('mute_instance', () => { + const objectRemover = new ObjectRemover(supertest); + + after(() => objectRemover.removeAll()); + + it('should handle mute alert instance request appropriately', async () => { + const { body: createdAlert } = await supertest + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alert`) + .set('kbn-xsrf', 'foo') + .send(getTestAlertData({ enabled: false })) + .expect(200); + objectRemover.add(Spaces.space1.id, createdAlert.id, 'alert'); + + await supertest + .post( + `${getUrlPrefix(Spaces.space1.id)}/api/alert/${createdAlert.id}/alert_instance/1/_mute` + ) + .set('kbn-xsrf', 'foo') + .expect(204, ''); + + const { body: updatedAlert } = await supertest + .get(`${getUrlPrefix(Spaces.space1.id)}/api/alert/${createdAlert.id}`) + .set('kbn-xsrf', 'foo') + .expect(200); + expect(updatedAlert.mutedInstanceIds).to.eql(['1']); + }); + }); +} diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/unmute_instance.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/unmute_instance.ts new file mode 100644 index 0000000000000..68858ded0111c --- /dev/null +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/unmute_instance.ts @@ -0,0 +1,50 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import expect from '@kbn/expect'; +import { Spaces } from '../../scenarios'; +import { getUrlPrefix, getTestAlertData, ObjectRemover } from '../../../common/lib'; +import { FtrProviderContext } from '../../../common/ftr_provider_context'; + +// eslint-disable-next-line import/no-default-export +export default function createUnmuteInstanceTests({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + + describe('unmute_instance', () => { + const objectRemover = new ObjectRemover(supertest); + + after(() => objectRemover.removeAll()); + + it('should handle unmute alert instance request appropriately', async () => { + const { body: createdAlert } = await supertest + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alert`) + .set('kbn-xsrf', 'foo') + .send(getTestAlertData({ enabled: false })) + .expect(200); + objectRemover.add(Spaces.space1.id, createdAlert.id, 'alert'); + + await supertest + .post( + `${getUrlPrefix(Spaces.space1.id)}/api/alert/${createdAlert.id}/alert_instance/1/_mute` + ) + .set('kbn-xsrf', 'foo') + .expect(204, ''); + + await supertest + .post( + `${getUrlPrefix(Spaces.space1.id)}/api/alert/${createdAlert.id}/alert_instance/1/_unmute` + ) + .set('kbn-xsrf', 'foo') + .expect(204, ''); + + const { body: updatedAlert } = await supertest + .get(`${getUrlPrefix(Spaces.space1.id)}/api/alert/${createdAlert.id}`) + .set('kbn-xsrf', 'foo') + .expect(200); + expect(updatedAlert.mutedInstanceIds).to.eql([]); + }); + }); +} From 5116398e5ffe1a3907a024cb24b5ad097c0acac3 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Mon, 23 Sep 2019 16:23:34 -0400 Subject: [PATCH 12/26] Add API integration tests for alert muting / unmuting --- .../tests/alerting/index.ts | 2 + .../tests/alerting/mute.ts | 67 +++++++++++++++++ .../tests/alerting/unmute.ts | 71 +++++++++++++++++++ .../spaces_only/tests/alerting/index.ts | 2 + .../spaces_only/tests/alerting/mute.ts | 41 +++++++++++ .../spaces_only/tests/alerting/unmute.ts | 46 ++++++++++++ 6 files changed, 229 insertions(+) create mode 100644 x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/mute.ts create mode 100644 x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/unmute.ts create mode 100644 x-pack/test/alerting_api_integration/spaces_only/tests/alerting/mute.ts create mode 100644 x-pack/test/alerting_api_integration/spaces_only/tests/alerting/unmute.ts diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/index.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/index.ts index 7fdbb57bba1d6..fe0714b8eb36c 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/index.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/index.ts @@ -16,7 +16,9 @@ export default function alertingTests({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./find')); loadTestFile(require.resolve('./get')); loadTestFile(require.resolve('./list_alert_types')); + loadTestFile(require.resolve('./mute')); loadTestFile(require.resolve('./mute_instance')); + loadTestFile(require.resolve('./unmute')); loadTestFile(require.resolve('./unmute_instance')); loadTestFile(require.resolve('./update')); loadTestFile(require.resolve('./update_api_key')); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/mute.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/mute.ts new file mode 100644 index 0000000000000..7b11bc0f0488c --- /dev/null +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/mute.ts @@ -0,0 +1,67 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import expect from '@kbn/expect'; +import { UserAtSpaceScenarios } from '../../scenarios'; +import { getUrlPrefix, getTestAlertData, ObjectRemover } from '../../../common/lib'; +import { FtrProviderContext } from '../../../common/ftr_provider_context'; + +// eslint-disable-next-line import/no-default-export +export default function createMuteAlertTests({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + const supertestWithoutAuth = getService('supertestWithoutAuth'); + + describe('mute', () => { + const objectRemover = new ObjectRemover(supertest); + + after(() => objectRemover.removeAll()); + + for (const scenario of UserAtSpaceScenarios) { + const { user, space } = scenario; + describe(scenario.id, () => { + it('should handle mute alert request appropriately', async () => { + const { body: createdAlert } = await supertest + .post(`${getUrlPrefix(space.id)}/api/alert`) + .set('kbn-xsrf', 'foo') + .send(getTestAlertData({ enabled: false })) + .expect(200); + objectRemover.add(space.id, createdAlert.id, 'alert'); + + const response = await supertestWithoutAuth + .post(`${getUrlPrefix(space.id)}/api/alert/${createdAlert.id}/_mute`) + .set('kbn-xsrf', 'foo') + .auth(user.username, user.password); + + switch (scenario.id) { + case 'no_kibana_privileges at space1': + case 'space_1_all at space2': + case 'global_read at space1': + expect(response.statusCode).to.eql(404); + expect(response.body).to.eql({ + statusCode: 404, + error: 'Not Found', + message: 'Not Found', + }); + break; + case 'superuser at space1': + case 'space_1_all at space1': + expect(response.statusCode).to.eql(204); + expect(response.body).to.eql(''); + const { body: updatedAlert } = await supertestWithoutAuth + .get(`${getUrlPrefix(space.id)}/api/alert/${createdAlert.id}`) + .set('kbn-xsrf', 'foo') + .auth(user.username, user.password) + .expect(200); + expect(updatedAlert.muted).to.eql(true); + break; + default: + throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`); + } + }); + }); + } + }); +} diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/unmute.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/unmute.ts new file mode 100644 index 0000000000000..1d3e4af1c4bf3 --- /dev/null +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/unmute.ts @@ -0,0 +1,71 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import expect from '@kbn/expect'; +import { UserAtSpaceScenarios } from '../../scenarios'; +import { getUrlPrefix, getTestAlertData, ObjectRemover } from '../../../common/lib'; +import { FtrProviderContext } from '../../../common/ftr_provider_context'; + +// eslint-disable-next-line import/no-default-export +export default function createUnmuteAlertTests({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + const supertestWithoutAuth = getService('supertestWithoutAuth'); + + describe('unmute', () => { + const objectRemover = new ObjectRemover(supertest); + + after(() => objectRemover.removeAll()); + + for (const scenario of UserAtSpaceScenarios) { + const { user, space } = scenario; + describe(scenario.id, () => { + it('should handle unmute alert request appropriately', async () => { + const { body: createdAlert } = await supertest + .post(`${getUrlPrefix(space.id)}/api/alert`) + .set('kbn-xsrf', 'foo') + .send(getTestAlertData({ enabled: false })) + .expect(200); + objectRemover.add(space.id, createdAlert.id, 'alert'); + + await supertest + .post(`${getUrlPrefix(space.id)}/api/alert/${createdAlert.id}/_mute`) + .set('kbn-xsrf', 'foo'); + + const response = await supertestWithoutAuth + .post(`${getUrlPrefix(space.id)}/api/alert/${createdAlert.id}/_unmute`) + .set('kbn-xsrf', 'foo') + .auth(user.username, user.password); + + switch (scenario.id) { + case 'no_kibana_privileges at space1': + case 'space_1_all at space2': + case 'global_read at space1': + expect(response.statusCode).to.eql(404); + expect(response.body).to.eql({ + statusCode: 404, + error: 'Not Found', + message: 'Not Found', + }); + break; + case 'superuser at space1': + case 'space_1_all at space1': + expect(response.statusCode).to.eql(204); + expect(response.body).to.eql(''); + const { body: updatedAlert } = await supertestWithoutAuth + .get(`${getUrlPrefix(space.id)}/api/alert/${createdAlert.id}`) + .set('kbn-xsrf', 'foo') + .auth(user.username, user.password) + .expect(200); + expect(updatedAlert.muted).to.eql(false); + break; + default: + throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`); + } + }); + }); + } + }); +} diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/index.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/index.ts index 7fdbb57bba1d6..fe0714b8eb36c 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/index.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/index.ts @@ -16,7 +16,9 @@ export default function alertingTests({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./find')); loadTestFile(require.resolve('./get')); loadTestFile(require.resolve('./list_alert_types')); + loadTestFile(require.resolve('./mute')); loadTestFile(require.resolve('./mute_instance')); + loadTestFile(require.resolve('./unmute')); loadTestFile(require.resolve('./unmute_instance')); loadTestFile(require.resolve('./update')); loadTestFile(require.resolve('./update_api_key')); diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/mute.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/mute.ts new file mode 100644 index 0000000000000..aaadc7000814a --- /dev/null +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/mute.ts @@ -0,0 +1,41 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import expect from '@kbn/expect'; +import { Spaces } from '../../scenarios'; +import { getUrlPrefix, getTestAlertData, ObjectRemover } from '../../../common/lib'; +import { FtrProviderContext } from '../../../common/ftr_provider_context'; + +// eslint-disable-next-line import/no-default-export +export default function createMuteTests({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + + describe('mute', () => { + const objectRemover = new ObjectRemover(supertest); + + after(() => objectRemover.removeAll()); + + it('should handle mute alert request appropriately', async () => { + const { body: createdAlert } = await supertest + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alert`) + .set('kbn-xsrf', 'foo') + .send(getTestAlertData({ enabled: false })) + .expect(200); + objectRemover.add(Spaces.space1.id, createdAlert.id, 'alert'); + + await supertest + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alert/${createdAlert.id}/_mute`) + .set('kbn-xsrf', 'foo') + .expect(204, ''); + + const { body: updatedAlert } = await supertest + .get(`${getUrlPrefix(Spaces.space1.id)}/api/alert/${createdAlert.id}`) + .set('kbn-xsrf', 'foo') + .expect(200); + expect(updatedAlert.muted).to.eql(true); + }); + }); +} diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/unmute.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/unmute.ts new file mode 100644 index 0000000000000..f050fb12b01cd --- /dev/null +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/unmute.ts @@ -0,0 +1,46 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import expect from '@kbn/expect'; +import { Spaces } from '../../scenarios'; +import { getUrlPrefix, getTestAlertData, ObjectRemover } from '../../../common/lib'; +import { FtrProviderContext } from '../../../common/ftr_provider_context'; + +// eslint-disable-next-line import/no-default-export +export default function createUnmuteTests({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + + describe('unmute', () => { + const objectRemover = new ObjectRemover(supertest); + + after(() => objectRemover.removeAll()); + + it('should handle unmute alert request appropriately', async () => { + const { body: createdAlert } = await supertest + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alert`) + .set('kbn-xsrf', 'foo') + .send(getTestAlertData({ enabled: false })) + .expect(200); + objectRemover.add(Spaces.space1.id, createdAlert.id, 'alert'); + + await supertest + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alert/${createdAlert.id}/_mute`) + .set('kbn-xsrf', 'foo') + .expect(204, ''); + + await supertest + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alert/${createdAlert.id}/_unmute`) + .set('kbn-xsrf', 'foo') + .expect(204, ''); + + const { body: updatedAlert } = await supertest + .get(`${getUrlPrefix(Spaces.space1.id)}/api/alert/${createdAlert.id}`) + .set('kbn-xsrf', 'foo') + .expect(200); + expect(updatedAlert.muted).to.eql(false); + }); + }); +} From 5c147c1a74f36963170504579d67cded32b5fab1 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Tue, 24 Sep 2019 10:50:46 -0400 Subject: [PATCH 13/26] Apply PR feedback pt1 --- .../lib/get_create_task_runner_function.ts | 1 - .../tests/alerting/alerts.ts | 87 ++++++++++++++++++- .../tests/alerting/mute_instance.ts | 2 +- .../tests/alerting/unmute_instance.ts | 40 --------- 4 files changed, 87 insertions(+), 43 deletions(-) diff --git a/x-pack/legacy/plugins/alerting/server/lib/get_create_task_runner_function.ts b/x-pack/legacy/plugins/alerting/server/lib/get_create_task_runner_function.ts index acd42292b6f17..c856403765024 100644 --- a/x-pack/legacy/plugins/alerting/server/lib/get_create_task_runner_function.ts +++ b/x-pack/legacy/plugins/alerting/server/lib/get_create_task_runner_function.ts @@ -129,7 +129,6 @@ export function getCreateTaskRunnerFunction({ const alertInstance = alertInstances[alertInstanceId]; if (alertInstance.hasScheduledActions(throttle)) { if (muted || mutedInstanceIds.includes(alertInstanceId)) { - // TODO: Only log the activity, skip executing actions return; } const { actionGroup, context, state } = alertInstance.getSechduledActionOptions()!; diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/alerts.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/alerts.ts index 0e9513b65febb..d850ecb5fdc5f 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/alerts.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/alerts.ts @@ -657,7 +657,7 @@ export default function alertTests({ getService }: FtrProviderContext) { .set('kbn-xsrf', 'foo') .auth(user.username, user.password) .expect(204, ''); - // Wait until alerts scheduled actions twice to ensure actions had a chance to execute once + // Wait until alerts schedule actions twice to ensure actions had a chance to skip execution once await esTestIndexTool.waitForDocs('alert:test.always-firing', reference, 2); const executedActionsResult = await esTestIndexTool.search( 'action:test.index-record', @@ -737,6 +737,91 @@ export default function alertTests({ getService }: FtrProviderContext) { throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`); } }); + + it(`should unmute all instances when unmuting an alert`, async () => { + const reference = `create-test-10:${user.username}`; + const createdAction = await createIndexRecordAction(space.id); + const response = await supertestWithoutAuth + .post(`${getUrlPrefix(space.id)}/api/alert`) + .set('kbn-xsrf', 'foo') + .auth(user.username, user.password) + .send( + getTestAlertData({ + enabled: false, + interval: '1s', + alertTypeId: 'test.always-firing', + alertTypeParams: { + index: ES_TEST_INDEX_NAME, + reference, + }, + actions: [ + { + group: 'default', + id: createdAction.id, + params: { + index: ES_TEST_INDEX_NAME, + reference, + message: 'from:default', + }, + }, + ], + }) + ); + + switch (scenario.id) { + case 'no_kibana_privileges at space1': + case 'space_1_all at space2': + case 'global_read at space1': + expect(response.statusCode).to.eql(404); + expect(response.body).to.eql({ + statusCode: 404, + error: 'Not Found', + message: 'Not Found', + }); + break; + case 'space_1_all at space1': + case 'superuser at space1': + // Mute the alert instance "1" that "test.always-firing" always schedules actions for + await supertestWithoutAuth + .post( + `${getUrlPrefix(space.id)}/api/alert/${response.body.id}/alert_instance/1/_mute` + ) + .set('kbn-xsrf', 'foo') + .auth(user.username, user.password) + .expect(204, ''); + // Mute the alert + await supertestWithoutAuth + .post( + `${getUrlPrefix(space.id)}/api/alert/${response.body.id}/alert_instance/1/_mute` + ) + .set('kbn-xsrf', 'foo') + .auth(user.username, user.password) + .expect(204, ''); + // Unmute the alert + await supertestWithoutAuth + .post( + `${getUrlPrefix(space.id)}/api/alert/${response.body.id}/alert_instance/1/_unmute` + ) + .set('kbn-xsrf', 'foo') + .auth(user.username, user.password) + .expect(204, ''); + await supertestWithoutAuth + .post(`${getUrlPrefix(space.id)}/api/alert/${response.body.id}/_enable`) + .set('kbn-xsrf', 'foo') + .auth(user.username, user.password) + .expect(204, ''); + // Wait until alerts scheduled actions twice to ensure actions had a chance to execute once + await esTestIndexTool.waitForDocs('alert:test.always-firing', reference, 2); + const executedActionsResult = await esTestIndexTool.search( + 'action:test.index-record', + reference + ); + expect(executedActionsResult.hits.total.value).to.eql(1); + break; + default: + throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`); + } + }); }); } }); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/mute_instance.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/mute_instance.ts index f03d5d6021a93..d02073d4a5018 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/mute_instance.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/mute_instance.ts @@ -62,7 +62,7 @@ export default function createMuteAlertInstanceTests({ getService }: FtrProvider } }); - it('should handle mute alert instance request appropriately when muting an instance already muted', async () => { + it('should handle mute alert instance request appropriately and not duplicate mutedInstanceIds when muting an instance already muted', async () => { const { body: createdAlert } = await supertest .post(`${getUrlPrefix(space.id)}/api/alert`) .set('kbn-xsrf', 'foo') diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/unmute_instance.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/unmute_instance.ts index c2718bb670eae..f417012db2a9d 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/unmute_instance.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/unmute_instance.ts @@ -66,46 +66,6 @@ export default function createMuteAlertInstanceTests({ getService }: FtrProvider throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`); } }); - - it('should handle unmute alert instance request appropriately when an instance is already unmuted', async () => { - const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alert`) - .set('kbn-xsrf', 'foo') - .send(getTestAlertData({ enabled: false })) - .expect(200); - objectRemover.add(space.id, createdAlert.id, 'alert'); - - const response = await supertestWithoutAuth - .post(`${getUrlPrefix(space.id)}/api/alert/${createdAlert.id}/alert_instance/1/_unmute`) - .set('kbn-xsrf', 'foo') - .auth(user.username, user.password); - - switch (scenario.id) { - case 'no_kibana_privileges at space1': - case 'space_1_all at space2': - case 'global_read at space1': - expect(response.statusCode).to.eql(404); - expect(response.body).to.eql({ - statusCode: 404, - error: 'Not Found', - message: 'Not Found', - }); - break; - case 'superuser at space1': - case 'space_1_all at space1': - expect(response.statusCode).to.eql(204); - expect(response.body).to.eql(''); - const { body: updatedAlert } = await supertestWithoutAuth - .get(`${getUrlPrefix(space.id)}/api/alert/${createdAlert.id}`) - .set('kbn-xsrf', 'foo') - .auth(user.username, user.password) - .expect(200); - expect(updatedAlert.mutedInstanceIds).to.eql([]); - break; - default: - throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`); - } - }); }); } }); From 413e67aa3bcbda1baeefbdbaaf8422e7b108a9c4 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Tue, 24 Sep 2019 13:07:50 -0400 Subject: [PATCH 14/26] Create single index record action --- .../tests/alerting/alerts.ts | 64 +++++++++---------- 1 file changed, 30 insertions(+), 34 deletions(-) diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/alerts.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/alerts.ts index d850ecb5fdc5f..0509c51fea1a0 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/alerts.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/alerts.ts @@ -38,31 +38,33 @@ export default function alertTests({ getService }: FtrProviderContext) { await es.indices.delete({ index: authorizationIndex }); }); - async function createIndexRecordAction(spaceId: string) { - const { body: createdAction } = await supertest - .post(`${getUrlPrefix(spaceId)}/api/action`) - .set('kbn-xsrf', 'foo') - .send({ - description: 'My action', - actionTypeId: 'test.index-record', - config: { - unencrypted: `This value shouldn't get encrypted`, - }, - secrets: { - encrypted: 'This value should be encrypted', - }, - }) - .expect(200); - objectRemover.add(spaceId, createdAction.id, 'action'); - return createdAction; - } - for (const scenario of UserAtSpaceScenarios) { const { user, space } = scenario; + describe(scenario.id, () => { + let indexRecordActionId: string; + + before(async () => { + const { body: createdAction } = await supertest + .post(`${getUrlPrefix(space.id)}/api/action`) + .set('kbn-xsrf', 'foo') + .send({ + description: 'My action', + actionTypeId: 'test.index-record', + config: { + unencrypted: `This value shouldn't get encrypted`, + }, + secrets: { + encrypted: 'This value should be encrypted', + }, + }) + .expect(200); + objectRemover.add(space.id, createdAction.id, 'action'); + indexRecordActionId = createdAction.id; + }); + it('should schedule task, run alert and schedule actions when appropriate', async () => { const reference = `create-test-1:${user.username}`; - const createdAction = await createIndexRecordAction(space.id); const response = await supertestWithoutAuth .post(`${getUrlPrefix(space.id)}/api/alert`) .set('kbn-xsrf', 'foo') @@ -78,7 +80,7 @@ export default function alertTests({ getService }: FtrProviderContext) { actions: [ { group: 'default', - id: createdAction.id, + id: indexRecordActionId, params: { index: ES_TEST_INDEX_NAME, reference, @@ -423,7 +425,6 @@ export default function alertTests({ getService }: FtrProviderContext) { it('should throttle alerts when appropriate', async () => { const reference = `create-test-5:${user.username}`; - const createdAction = await createIndexRecordAction(space.id); const response = await supertestWithoutAuth .post(`${getUrlPrefix(space.id)}/api/alert`) .set('kbn-xsrf', 'foo') @@ -440,7 +441,7 @@ export default function alertTests({ getService }: FtrProviderContext) { actions: [ { group: 'default', - id: createdAction.id, + id: indexRecordActionId, params: { index: ES_TEST_INDEX_NAME, reference, @@ -479,7 +480,6 @@ export default function alertTests({ getService }: FtrProviderContext) { it('should not throttle when changing groups', async () => { const reference = `create-test-6:${user.username}`; - const createdAction = await createIndexRecordAction(space.id); const response = await supertestWithoutAuth .post(`${getUrlPrefix(space.id)}/api/alert`) .set('kbn-xsrf', 'foo') @@ -497,7 +497,7 @@ export default function alertTests({ getService }: FtrProviderContext) { actions: [ { group: 'default', - id: createdAction.id, + id: indexRecordActionId, params: { index: ES_TEST_INDEX_NAME, reference, @@ -506,7 +506,7 @@ export default function alertTests({ getService }: FtrProviderContext) { }, { group: 'other', - id: createdAction.id, + id: indexRecordActionId, params: { index: ES_TEST_INDEX_NAME, reference, @@ -549,7 +549,6 @@ export default function alertTests({ getService }: FtrProviderContext) { it('should reset throttle window when not firing', async () => { const reference = `create-test-7:${user.username}`; - const createdAction = await createIndexRecordAction(space.id); const response = await supertestWithoutAuth .post(`${getUrlPrefix(space.id)}/api/alert`) .set('kbn-xsrf', 'foo') @@ -567,7 +566,7 @@ export default function alertTests({ getService }: FtrProviderContext) { actions: [ { group: 'default', - id: createdAction.id, + id: indexRecordActionId, params: { index: ES_TEST_INDEX_NAME, reference, @@ -606,7 +605,6 @@ export default function alertTests({ getService }: FtrProviderContext) { it(`shouldn't schedule actions when alert is muted`, async () => { const reference = `create-test-8:${user.username}`; - const createdAction = await createIndexRecordAction(space.id); const response = await supertestWithoutAuth .post(`${getUrlPrefix(space.id)}/api/alert`) .set('kbn-xsrf', 'foo') @@ -623,7 +621,7 @@ export default function alertTests({ getService }: FtrProviderContext) { actions: [ { group: 'default', - id: createdAction.id, + id: indexRecordActionId, params: { index: ES_TEST_INDEX_NAME, reference, @@ -672,7 +670,6 @@ export default function alertTests({ getService }: FtrProviderContext) { it(`shouldn't schedule actions when alert instance is muted`, async () => { const reference = `create-test-9:${user.username}`; - const createdAction = await createIndexRecordAction(space.id); const response = await supertestWithoutAuth .post(`${getUrlPrefix(space.id)}/api/alert`) .set('kbn-xsrf', 'foo') @@ -689,7 +686,7 @@ export default function alertTests({ getService }: FtrProviderContext) { actions: [ { group: 'default', - id: createdAction.id, + id: indexRecordActionId, params: { index: ES_TEST_INDEX_NAME, reference, @@ -740,7 +737,6 @@ export default function alertTests({ getService }: FtrProviderContext) { it(`should unmute all instances when unmuting an alert`, async () => { const reference = `create-test-10:${user.username}`; - const createdAction = await createIndexRecordAction(space.id); const response = await supertestWithoutAuth .post(`${getUrlPrefix(space.id)}/api/alert`) .set('kbn-xsrf', 'foo') @@ -757,7 +753,7 @@ export default function alertTests({ getService }: FtrProviderContext) { actions: [ { group: 'default', - id: createdAction.id, + id: indexRecordActionId, params: { index: ES_TEST_INDEX_NAME, reference, From 491887f15cf3d636467b9b54b9196ce881c9240b Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Tue, 24 Sep 2019 14:01:01 -0400 Subject: [PATCH 15/26] Function to create always firing alerts and function to generate reference --- .../tests/alerting/alerts.ts | 293 ++++++------------ 1 file changed, 95 insertions(+), 198 deletions(-) diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/alerts.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/alerts.ts index 0509c51fea1a0..c45b2aaa8c356 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/alerts.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/alerts.ts @@ -42,6 +42,7 @@ export default function alertTests({ getService }: FtrProviderContext) { const { user, space } = scenario; describe(scenario.id, () => { + let referenceCounter = 1; let indexRecordActionId: string; before(async () => { @@ -59,38 +60,51 @@ export default function alertTests({ getService }: FtrProviderContext) { }, }) .expect(200); - objectRemover.add(space.id, createdAction.id, 'action'); indexRecordActionId = createdAction.id; }); + after(() => objectRemover.add(space.id, indexRecordActionId, 'action')); - it('should schedule task, run alert and schedule actions when appropriate', async () => { - const reference = `create-test-1:${user.username}`; + function generateReference() { + return `create-test-${referenceCounter++}:${user.username}`; + } + + async function createAlwaysFiringAction(reference: string, overwrites = {}) { const response = await supertestWithoutAuth .post(`${getUrlPrefix(space.id)}/api/alert`) .set('kbn-xsrf', 'foo') .auth(user.username, user.password) - .send( - getTestAlertData({ - interval: '1m', - alertTypeId: 'test.always-firing', - alertTypeParams: { - index: ES_TEST_INDEX_NAME, - reference, - }, - actions: [ - { - group: 'default', - id: indexRecordActionId, - params: { - index: ES_TEST_INDEX_NAME, - reference, - message: - 'instanceContextValue: {{context.instanceContextValue}}, instanceStateValue: {{state.instanceStateValue}}', - }, + .send({ + enabled: true, + interval: '1m', + throttle: '1m', + alertTypeId: 'test.always-firing', + alertTypeParams: { + index: ES_TEST_INDEX_NAME, + reference, + }, + actions: [ + { + group: 'default', + id: indexRecordActionId, + params: { + index: ES_TEST_INDEX_NAME, + reference, + message: + 'instanceContextValue: {{context.instanceContextValue}}, instanceStateValue: {{state.instanceStateValue}}', }, - ], - }) - ); + }, + ], + ...overwrites, + }); + if (response.statusCode === 200) { + objectRemover.add(space.id, response.body.id, 'alert'); + } + return response; + } + + it('should schedule task, run alert and schedule actions when appropriate', async () => { + const reference = generateReference(); + const response = await createAlwaysFiringAction(reference); switch (scenario.id) { case 'no_kibana_privileges at space1': @@ -106,7 +120,6 @@ export default function alertTests({ getService }: FtrProviderContext) { case 'superuser at space1': case 'space_1_all at space1': expect(response.statusCode).to.eql(200); - objectRemover.add(space.id, response.body.id, 'alert'); const alertTestRecord = (await esTestIndexTool.waitForDocs( 'alert:test.always-firing', reference @@ -162,7 +175,7 @@ export default function alertTests({ getService }: FtrProviderContext) { .expect(200); objectRemover.add(space.id, createdAction.id, 'action'); - const reference = `create-test-2:${user.username}`; + const reference = generateReference(); const response = await supertestWithoutAuth .post(`${getUrlPrefix(space.id)}/api/alert`) .set('kbn-xsrf', 'foo') @@ -250,7 +263,7 @@ export default function alertTests({ getService }: FtrProviderContext) { it('should have proper callCluster and savedObjectsClient authorization for alert type executor when appropriate', async () => { let alertTestRecord: any; - const reference = `create-test-3:${user.username}`; + const reference = generateReference(); const response = await supertestWithoutAuth .post(`${getUrlPrefix(space.id)}/api/alert`) .set('kbn-xsrf', 'foo') @@ -328,7 +341,7 @@ export default function alertTests({ getService }: FtrProviderContext) { it('should have proper callCluster and savedObjectsClient authorization for action type executor when appropriate', async () => { let actionTestRecord: any; - const reference = `create-test-4:${user.username}`; + const reference = generateReference(); const { body: createdAction } = await supertest .post(`${getUrlPrefix(space.id)}/api/action`) .set('kbn-xsrf', 'foo') @@ -424,33 +437,10 @@ export default function alertTests({ getService }: FtrProviderContext) { }); it('should throttle alerts when appropriate', async () => { - const reference = `create-test-5:${user.username}`; - const response = await supertestWithoutAuth - .post(`${getUrlPrefix(space.id)}/api/alert`) - .set('kbn-xsrf', 'foo') - .auth(user.username, user.password) - .send( - getTestAlertData({ - interval: '1s', - throttle: '1m', - alertTypeId: 'test.always-firing', - alertTypeParams: { - index: ES_TEST_INDEX_NAME, - reference, - }, - actions: [ - { - group: 'default', - id: indexRecordActionId, - params: { - index: ES_TEST_INDEX_NAME, - reference, - message: '', - }, - }, - ], - }) - ); + const reference = generateReference(); + const response = await createAlwaysFiringAction(reference, { + interval: '1s', + }); switch (scenario.id) { case 'no_kibana_privileges at space1': @@ -479,43 +469,35 @@ export default function alertTests({ getService }: FtrProviderContext) { }); it('should not throttle when changing groups', async () => { - const reference = `create-test-6:${user.username}`; - const response = await supertestWithoutAuth - .post(`${getUrlPrefix(space.id)}/api/alert`) - .set('kbn-xsrf', 'foo') - .auth(user.username, user.password) - .send( - getTestAlertData({ - interval: '1s', - throttle: '1m', - alertTypeId: 'test.always-firing', - alertTypeParams: { + const reference = generateReference(); + const response = await createAlwaysFiringAction(reference, { + interval: '1s', + alertTypeParams: { + index: ES_TEST_INDEX_NAME, + reference, + groupsToScheduleActionsInSeries: ['default', 'other'], + }, + actions: [ + { + group: 'default', + id: indexRecordActionId, + params: { index: ES_TEST_INDEX_NAME, reference, - groupsToScheduleActionsInSeries: ['default', 'other'], + message: 'from:default', }, - actions: [ - { - group: 'default', - id: indexRecordActionId, - params: { - index: ES_TEST_INDEX_NAME, - reference, - message: 'from:default', - }, - }, - { - group: 'other', - id: indexRecordActionId, - params: { - index: ES_TEST_INDEX_NAME, - reference, - message: 'from:other', - }, - }, - ], - }) - ); + }, + { + group: 'other', + id: indexRecordActionId, + params: { + index: ES_TEST_INDEX_NAME, + reference, + message: 'from:other', + }, + }, + ], + }); switch (scenario.id) { case 'no_kibana_privileges at space1': @@ -548,34 +530,15 @@ export default function alertTests({ getService }: FtrProviderContext) { }); it('should reset throttle window when not firing', async () => { - const reference = `create-test-7:${user.username}`; - const response = await supertestWithoutAuth - .post(`${getUrlPrefix(space.id)}/api/alert`) - .set('kbn-xsrf', 'foo') - .auth(user.username, user.password) - .send( - getTestAlertData({ - interval: '1s', - throttle: '1m', - alertTypeId: 'test.always-firing', - alertTypeParams: { - index: ES_TEST_INDEX_NAME, - reference, - groupsToScheduleActionsInSeries: ['default', null, 'default'], - }, - actions: [ - { - group: 'default', - id: indexRecordActionId, - params: { - index: ES_TEST_INDEX_NAME, - reference, - message: 'from:default', - }, - }, - ], - }) - ); + const reference = generateReference(); + const response = await createAlwaysFiringAction(reference, { + interval: '1s', + alertTypeParams: { + index: ES_TEST_INDEX_NAME, + reference, + groupsToScheduleActionsInSeries: ['default', null, 'default'], + }, + }); switch (scenario.id) { case 'no_kibana_privileges at space1': @@ -604,33 +567,11 @@ export default function alertTests({ getService }: FtrProviderContext) { }); it(`shouldn't schedule actions when alert is muted`, async () => { - const reference = `create-test-8:${user.username}`; - const response = await supertestWithoutAuth - .post(`${getUrlPrefix(space.id)}/api/alert`) - .set('kbn-xsrf', 'foo') - .auth(user.username, user.password) - .send( - getTestAlertData({ - enabled: false, - interval: '1s', - alertTypeId: 'test.always-firing', - alertTypeParams: { - index: ES_TEST_INDEX_NAME, - reference, - }, - actions: [ - { - group: 'default', - id: indexRecordActionId, - params: { - index: ES_TEST_INDEX_NAME, - reference, - message: 'from:default', - }, - }, - ], - }) - ); + const reference = generateReference(); + const response = await createAlwaysFiringAction(reference, { + enabled: false, + interval: '1s', + }); switch (scenario.id) { case 'no_kibana_privileges at space1': @@ -669,33 +610,11 @@ export default function alertTests({ getService }: FtrProviderContext) { }); it(`shouldn't schedule actions when alert instance is muted`, async () => { - const reference = `create-test-9:${user.username}`; - const response = await supertestWithoutAuth - .post(`${getUrlPrefix(space.id)}/api/alert`) - .set('kbn-xsrf', 'foo') - .auth(user.username, user.password) - .send( - getTestAlertData({ - enabled: false, - interval: '1s', - alertTypeId: 'test.always-firing', - alertTypeParams: { - index: ES_TEST_INDEX_NAME, - reference, - }, - actions: [ - { - group: 'default', - id: indexRecordActionId, - params: { - index: ES_TEST_INDEX_NAME, - reference, - message: 'from:default', - }, - }, - ], - }) - ); + const reference = generateReference(); + const response = await createAlwaysFiringAction(reference, { + enabled: false, + interval: '1s', + }); switch (scenario.id) { case 'no_kibana_privileges at space1': @@ -736,33 +655,11 @@ export default function alertTests({ getService }: FtrProviderContext) { }); it(`should unmute all instances when unmuting an alert`, async () => { - const reference = `create-test-10:${user.username}`; - const response = await supertestWithoutAuth - .post(`${getUrlPrefix(space.id)}/api/alert`) - .set('kbn-xsrf', 'foo') - .auth(user.username, user.password) - .send( - getTestAlertData({ - enabled: false, - interval: '1s', - alertTypeId: 'test.always-firing', - alertTypeParams: { - index: ES_TEST_INDEX_NAME, - reference, - }, - actions: [ - { - group: 'default', - id: indexRecordActionId, - params: { - index: ES_TEST_INDEX_NAME, - reference, - message: 'from:default', - }, - }, - ], - }) - ); + const reference = generateReference(); + const response = await createAlwaysFiringAction(reference, { + enabled: false, + interval: '1s', + }); switch (scenario.id) { case 'no_kibana_privileges at space1': From 8d00147d65c659a2fc10821d2d90153760a60185 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Tue, 24 Sep 2019 14:35:50 -0400 Subject: [PATCH 16/26] Make tests use alert utils --- .../common/lib/alert_utils.ts | 131 ++++++++++++++++ .../common/lib/index.ts | 1 + .../tests/alerting/alerts.ts | 141 +++++------------- 3 files changed, 166 insertions(+), 107 deletions(-) create mode 100644 x-pack/test/alerting_api_integration/common/lib/alert_utils.ts diff --git a/x-pack/test/alerting_api_integration/common/lib/alert_utils.ts b/x-pack/test/alerting_api_integration/common/lib/alert_utils.ts new file mode 100644 index 0000000000000..95943ac1f1523 --- /dev/null +++ b/x-pack/test/alerting_api_integration/common/lib/alert_utils.ts @@ -0,0 +1,131 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { Space, User } from '../types'; +import { ObjectRemover } from './object_remover'; +import { getUrlPrefix } from './space_test_utils'; +import { ES_TEST_INDEX_NAME } from './es_test_index_tool'; + +export interface AlertUtilsOpts { + user: User; + space: Space; + supertestWithoutAuth: any; + indexRecordActionId: string; + objectRemover: ObjectRemover; +} + +export class AlertUtils { + private referenceCounter = 1; + private readonly user: User; + private readonly space: Space; + private readonly supertestWithoutAuth: any; + private readonly indexRecordActionId: string; + private readonly objectRemover: ObjectRemover; + + constructor({ + indexRecordActionId, + objectRemover, + space, + supertestWithoutAuth, + user, + }: AlertUtilsOpts) { + this.user = user; + this.space = space; + this.objectRemover = objectRemover; + this.indexRecordActionId = indexRecordActionId; + this.supertestWithoutAuth = supertestWithoutAuth; + } + + public generateReference() { + return `alert-utils-ref-${this.referenceCounter++}:${this.user.username}`; + } + + public async enable(alertId: string) { + await this.supertestWithoutAuth + .post(`${getUrlPrefix(this.space.id)}/api/alert/${alertId}/_enable`) + .set('kbn-xsrf', 'foo') + .auth(this.user.username, this.user.password) + .expect(204, ''); + } + + public async disable(alertId: string) { + await this.supertestWithoutAuth + .post(`${getUrlPrefix(this.space.id)}/api/alert/${alertId}/_disable`) + .set('kbn-xsrf', 'foo') + .auth(this.user.username, this.user.password) + .expect(204, ''); + } + + public async mute(alertId: string) { + return await this.supertestWithoutAuth + .post(`${getUrlPrefix(this.space.id)}/api/alert/${alertId}/_mute`) + .set('kbn-xsrf', 'foo') + .auth(this.user.username, this.user.password) + .expect(204, ''); + } + + public async unmute(alertId: string) { + await this.supertestWithoutAuth + .post(`${getUrlPrefix(this.space.id)}/api/alert/${alertId}/_unmute`) + .set('kbn-xsrf', 'foo') + .auth(this.user.username, this.user.password) + .expect(204, ''); + } + + public async muteInstance(alertId: string, instanceId: string) { + return await this.supertestWithoutAuth + .post( + `${getUrlPrefix(this.space.id)}/api/alert/${alertId}/alert_instance/${instanceId}/_mute` + ) + .set('kbn-xsrf', 'foo') + .auth(this.user.username, this.user.password) + .expect(204, ''); + } + + public async unmuteInstance(alertId: string, instanceId: string) { + return await this.supertestWithoutAuth + .post( + `${getUrlPrefix(this.space.id)}/api/alert/${alertId}/alert_instance/${instanceId}/_unmute` + ) + .set('kbn-xsrf', 'foo') + .auth(this.user.username, this.user.password) + .expect(204, ''); + } + + public async createAlwaysFiringAction(reference: string, overwrites = {}) { + const response = await this.supertestWithoutAuth + .post(`${getUrlPrefix(this.space.id)}/api/alert`) + .set('kbn-xsrf', 'foo') + .auth(this.user.username, this.user.password) + .send({ + enabled: true, + interval: '1m', + throttle: '1m', + alertTypeId: 'test.always-firing', + alertTypeParams: { + index: ES_TEST_INDEX_NAME, + reference, + }, + actions: [ + { + group: 'default', + id: this.indexRecordActionId, + params: { + index: ES_TEST_INDEX_NAME, + reference, + message: + 'instanceContextValue: {{context.instanceContextValue}}, instanceStateValue: {{state.instanceStateValue}}', + }, + }, + ], + ...overwrites, + }); + if (response.statusCode === 200) { + this.objectRemover.add(this.space.id, response.body.id, 'alert'); + } + return response; + } +} diff --git a/x-pack/test/alerting_api_integration/common/lib/index.ts b/x-pack/test/alerting_api_integration/common/lib/index.ts index 6c80cbd043f4f..444b767456bde 100644 --- a/x-pack/test/alerting_api_integration/common/lib/index.ts +++ b/x-pack/test/alerting_api_integration/common/lib/index.ts @@ -8,3 +8,4 @@ export { ObjectRemover } from './object_remover'; export { getUrlPrefix } from './space_test_utils'; export { ES_TEST_INDEX_NAME, ESTestIndexTool } from './es_test_index_tool'; export { getTestAlertData } from './get_test_alert_data'; +export { AlertUtils } from './alert_utils'; diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/alerts.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/alerts.ts index c45b2aaa8c356..c914709c81635 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/alerts.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/alerts.ts @@ -13,6 +13,7 @@ import { getUrlPrefix, getTestAlertData, ObjectRemover, + AlertUtils, } from '../../../common/lib'; // eslint-disable-next-line import/no-default-export @@ -42,7 +43,7 @@ export default function alertTests({ getService }: FtrProviderContext) { const { user, space } = scenario; describe(scenario.id, () => { - let referenceCounter = 1; + let alertUtils: AlertUtils; let indexRecordActionId: string; before(async () => { @@ -61,50 +62,19 @@ export default function alertTests({ getService }: FtrProviderContext) { }) .expect(200); indexRecordActionId = createdAction.id; + alertUtils = new AlertUtils({ + user, + space, + supertestWithoutAuth, + indexRecordActionId, + objectRemover, + }); }); after(() => objectRemover.add(space.id, indexRecordActionId, 'action')); - function generateReference() { - return `create-test-${referenceCounter++}:${user.username}`; - } - - async function createAlwaysFiringAction(reference: string, overwrites = {}) { - const response = await supertestWithoutAuth - .post(`${getUrlPrefix(space.id)}/api/alert`) - .set('kbn-xsrf', 'foo') - .auth(user.username, user.password) - .send({ - enabled: true, - interval: '1m', - throttle: '1m', - alertTypeId: 'test.always-firing', - alertTypeParams: { - index: ES_TEST_INDEX_NAME, - reference, - }, - actions: [ - { - group: 'default', - id: indexRecordActionId, - params: { - index: ES_TEST_INDEX_NAME, - reference, - message: - 'instanceContextValue: {{context.instanceContextValue}}, instanceStateValue: {{state.instanceStateValue}}', - }, - }, - ], - ...overwrites, - }); - if (response.statusCode === 200) { - objectRemover.add(space.id, response.body.id, 'alert'); - } - return response; - } - it('should schedule task, run alert and schedule actions when appropriate', async () => { - const reference = generateReference(); - const response = await createAlwaysFiringAction(reference); + const reference = alertUtils.generateReference(); + const response = await alertUtils.createAlwaysFiringAction(reference); switch (scenario.id) { case 'no_kibana_privileges at space1': @@ -175,7 +145,7 @@ export default function alertTests({ getService }: FtrProviderContext) { .expect(200); objectRemover.add(space.id, createdAction.id, 'action'); - const reference = generateReference(); + const reference = alertUtils.generateReference(); const response = await supertestWithoutAuth .post(`${getUrlPrefix(space.id)}/api/alert`) .set('kbn-xsrf', 'foo') @@ -263,7 +233,7 @@ export default function alertTests({ getService }: FtrProviderContext) { it('should have proper callCluster and savedObjectsClient authorization for alert type executor when appropriate', async () => { let alertTestRecord: any; - const reference = generateReference(); + const reference = alertUtils.generateReference(); const response = await supertestWithoutAuth .post(`${getUrlPrefix(space.id)}/api/alert`) .set('kbn-xsrf', 'foo') @@ -341,7 +311,7 @@ export default function alertTests({ getService }: FtrProviderContext) { it('should have proper callCluster and savedObjectsClient authorization for action type executor when appropriate', async () => { let actionTestRecord: any; - const reference = generateReference(); + const reference = alertUtils.generateReference(); const { body: createdAction } = await supertest .post(`${getUrlPrefix(space.id)}/api/action`) .set('kbn-xsrf', 'foo') @@ -437,8 +407,8 @@ export default function alertTests({ getService }: FtrProviderContext) { }); it('should throttle alerts when appropriate', async () => { - const reference = generateReference(); - const response = await createAlwaysFiringAction(reference, { + const reference = alertUtils.generateReference(); + const response = await alertUtils.createAlwaysFiringAction(reference, { interval: '1s', }); @@ -469,8 +439,8 @@ export default function alertTests({ getService }: FtrProviderContext) { }); it('should not throttle when changing groups', async () => { - const reference = generateReference(); - const response = await createAlwaysFiringAction(reference, { + const reference = alertUtils.generateReference(); + const response = await alertUtils.createAlwaysFiringAction(reference, { interval: '1s', alertTypeParams: { index: ES_TEST_INDEX_NAME, @@ -530,8 +500,8 @@ export default function alertTests({ getService }: FtrProviderContext) { }); it('should reset throttle window when not firing', async () => { - const reference = generateReference(); - const response = await createAlwaysFiringAction(reference, { + const reference = alertUtils.generateReference(); + const response = await alertUtils.createAlwaysFiringAction(reference, { interval: '1s', alertTypeParams: { index: ES_TEST_INDEX_NAME, @@ -567,8 +537,8 @@ export default function alertTests({ getService }: FtrProviderContext) { }); it(`shouldn't schedule actions when alert is muted`, async () => { - const reference = generateReference(); - const response = await createAlwaysFiringAction(reference, { + const reference = alertUtils.generateReference(); + const response = await alertUtils.createAlwaysFiringAction(reference, { enabled: false, interval: '1s', }); @@ -586,16 +556,8 @@ export default function alertTests({ getService }: FtrProviderContext) { break; case 'space_1_all at space1': case 'superuser at space1': - await supertestWithoutAuth - .post(`${getUrlPrefix(space.id)}/api/alert/${response.body.id}/_mute`) - .set('kbn-xsrf', 'foo') - .auth(user.username, user.password) - .expect(204, ''); - await supertestWithoutAuth - .post(`${getUrlPrefix(space.id)}/api/alert/${response.body.id}/_enable`) - .set('kbn-xsrf', 'foo') - .auth(user.username, user.password) - .expect(204, ''); + await alertUtils.mute(response.body.id); + await alertUtils.enable(response.body.id); // Wait until alerts schedule actions twice to ensure actions had a chance to skip execution once await esTestIndexTool.waitForDocs('alert:test.always-firing', reference, 2); const executedActionsResult = await esTestIndexTool.search( @@ -610,8 +572,8 @@ export default function alertTests({ getService }: FtrProviderContext) { }); it(`shouldn't schedule actions when alert instance is muted`, async () => { - const reference = generateReference(); - const response = await createAlwaysFiringAction(reference, { + const reference = alertUtils.generateReference(); + const response = await alertUtils.createAlwaysFiringAction(reference, { enabled: false, interval: '1s', }); @@ -629,18 +591,8 @@ export default function alertTests({ getService }: FtrProviderContext) { break; case 'space_1_all at space1': case 'superuser at space1': - await supertestWithoutAuth - .post( - `${getUrlPrefix(space.id)}/api/alert/${response.body.id}/alert_instance/1/_mute` - ) - .set('kbn-xsrf', 'foo') - .auth(user.username, user.password) - .expect(204, ''); - await supertestWithoutAuth - .post(`${getUrlPrefix(space.id)}/api/alert/${response.body.id}/_enable`) - .set('kbn-xsrf', 'foo') - .auth(user.username, user.password) - .expect(204, ''); + await alertUtils.muteInstance(response.body.id, '1'); + await alertUtils.enable(response.body.id); // Wait until alerts scheduled actions twice to ensure actions had a chance to execute once await esTestIndexTool.waitForDocs('alert:test.always-firing', reference, 2); const executedActionsResult = await esTestIndexTool.search( @@ -655,8 +607,8 @@ export default function alertTests({ getService }: FtrProviderContext) { }); it(`should unmute all instances when unmuting an alert`, async () => { - const reference = generateReference(); - const response = await createAlwaysFiringAction(reference, { + const reference = alertUtils.generateReference(); + const response = await alertUtils.createAlwaysFiringAction(reference, { enabled: false, interval: '1s', }); @@ -674,35 +626,10 @@ export default function alertTests({ getService }: FtrProviderContext) { break; case 'space_1_all at space1': case 'superuser at space1': - // Mute the alert instance "1" that "test.always-firing" always schedules actions for - await supertestWithoutAuth - .post( - `${getUrlPrefix(space.id)}/api/alert/${response.body.id}/alert_instance/1/_mute` - ) - .set('kbn-xsrf', 'foo') - .auth(user.username, user.password) - .expect(204, ''); - // Mute the alert - await supertestWithoutAuth - .post( - `${getUrlPrefix(space.id)}/api/alert/${response.body.id}/alert_instance/1/_mute` - ) - .set('kbn-xsrf', 'foo') - .auth(user.username, user.password) - .expect(204, ''); - // Unmute the alert - await supertestWithoutAuth - .post( - `${getUrlPrefix(space.id)}/api/alert/${response.body.id}/alert_instance/1/_unmute` - ) - .set('kbn-xsrf', 'foo') - .auth(user.username, user.password) - .expect(204, ''); - await supertestWithoutAuth - .post(`${getUrlPrefix(space.id)}/api/alert/${response.body.id}/_enable`) - .set('kbn-xsrf', 'foo') - .auth(user.username, user.password) - .expect(204, ''); + await alertUtils.muteInstance(response.body.id, '1'); + await alertUtils.mute(response.body.id); + await alertUtils.unmute(response.body.id); + await alertUtils.enable(response.body.id); // Wait until alerts scheduled actions twice to ensure actions had a chance to execute once await esTestIndexTool.waitForDocs('alert:test.always-firing', reference, 2); const executedActionsResult = await esTestIndexTool.search( From 0508bac8ee96d0565284d91198dc477526d3ede1 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Wed, 25 Sep 2019 08:52:06 -0400 Subject: [PATCH 17/26] Rename mute / unmute alert routes --- x-pack/legacy/plugins/alerting/server/routes/mute.test.ts | 2 +- x-pack/legacy/plugins/alerting/server/routes/mute.ts | 2 +- x-pack/legacy/plugins/alerting/server/routes/unmute.test.ts | 2 +- x-pack/legacy/plugins/alerting/server/routes/unmute.ts | 2 +- .../test/alerting_api_integration/common/lib/alert_utils.ts | 4 ++-- .../security_and_spaces/tests/alerting/mute.ts | 2 +- .../security_and_spaces/tests/alerting/unmute.ts | 4 ++-- .../spaces_only/tests/alerting/mute.ts | 2 +- .../spaces_only/tests/alerting/unmute.ts | 4 ++-- 9 files changed, 12 insertions(+), 12 deletions(-) diff --git a/x-pack/legacy/plugins/alerting/server/routes/mute.test.ts b/x-pack/legacy/plugins/alerting/server/routes/mute.test.ts index 6bf9ca3b938b9..d7b2a01947e25 100644 --- a/x-pack/legacy/plugins/alerting/server/routes/mute.test.ts +++ b/x-pack/legacy/plugins/alerting/server/routes/mute.test.ts @@ -13,7 +13,7 @@ muteAlertRoute(server); test('mutes an alert', async () => { const request = { method: 'POST', - url: '/api/alert/1/_mute', + url: '/api/alert/1/_mute_all', }; const { statusCode } = await server.inject(request); diff --git a/x-pack/legacy/plugins/alerting/server/routes/mute.ts b/x-pack/legacy/plugins/alerting/server/routes/mute.ts index c0fa88b8632ea..686af10247d48 100644 --- a/x-pack/legacy/plugins/alerting/server/routes/mute.ts +++ b/x-pack/legacy/plugins/alerting/server/routes/mute.ts @@ -15,7 +15,7 @@ interface MuteRequest extends Hapi.Request { export function muteAlertRoute(server: Hapi.Server) { server.route({ method: 'POST', - path: '/api/alert/{id}/_mute', + path: '/api/alert/{id}/_mute_all', options: { tags: ['access:alerting-all'], response: { diff --git a/x-pack/legacy/plugins/alerting/server/routes/unmute.test.ts b/x-pack/legacy/plugins/alerting/server/routes/unmute.test.ts index 99cb89a08665b..fb9946bf8b730 100644 --- a/x-pack/legacy/plugins/alerting/server/routes/unmute.test.ts +++ b/x-pack/legacy/plugins/alerting/server/routes/unmute.test.ts @@ -13,7 +13,7 @@ unmuteAlertRoute(server); test('unmutes an alert', async () => { const request = { method: 'POST', - url: '/api/alert/1/_unmute', + url: '/api/alert/1/_unmute_all', }; const { statusCode } = await server.inject(request); diff --git a/x-pack/legacy/plugins/alerting/server/routes/unmute.ts b/x-pack/legacy/plugins/alerting/server/routes/unmute.ts index 011f122550f8f..355aa8d0fb4d8 100644 --- a/x-pack/legacy/plugins/alerting/server/routes/unmute.ts +++ b/x-pack/legacy/plugins/alerting/server/routes/unmute.ts @@ -15,7 +15,7 @@ interface UnmuteRequest extends Hapi.Request { export function unmuteAlertRoute(server: Hapi.Server) { server.route({ method: 'POST', - path: '/api/alert/{id}/_unmute', + path: '/api/alert/{id}/_unmute_all', options: { tags: ['access:alerting-all'], response: { diff --git a/x-pack/test/alerting_api_integration/common/lib/alert_utils.ts b/x-pack/test/alerting_api_integration/common/lib/alert_utils.ts index 95943ac1f1523..7c077e5f11f94 100644 --- a/x-pack/test/alerting_api_integration/common/lib/alert_utils.ts +++ b/x-pack/test/alerting_api_integration/common/lib/alert_utils.ts @@ -61,7 +61,7 @@ export class AlertUtils { public async mute(alertId: string) { return await this.supertestWithoutAuth - .post(`${getUrlPrefix(this.space.id)}/api/alert/${alertId}/_mute`) + .post(`${getUrlPrefix(this.space.id)}/api/alert/${alertId}/_mute_all`) .set('kbn-xsrf', 'foo') .auth(this.user.username, this.user.password) .expect(204, ''); @@ -69,7 +69,7 @@ export class AlertUtils { public async unmute(alertId: string) { await this.supertestWithoutAuth - .post(`${getUrlPrefix(this.space.id)}/api/alert/${alertId}/_unmute`) + .post(`${getUrlPrefix(this.space.id)}/api/alert/${alertId}/_unmute_all`) .set('kbn-xsrf', 'foo') .auth(this.user.username, this.user.password) .expect(204, ''); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/mute.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/mute.ts index 7b11bc0f0488c..66a6de101002a 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/mute.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/mute.ts @@ -31,7 +31,7 @@ export default function createMuteAlertTests({ getService }: FtrProviderContext) objectRemover.add(space.id, createdAlert.id, 'alert'); const response = await supertestWithoutAuth - .post(`${getUrlPrefix(space.id)}/api/alert/${createdAlert.id}/_mute`) + .post(`${getUrlPrefix(space.id)}/api/alert/${createdAlert.id}/_mute_all`) .set('kbn-xsrf', 'foo') .auth(user.username, user.password); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/unmute.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/unmute.ts index 1d3e4af1c4bf3..fcc5774319209 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/unmute.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/unmute.ts @@ -31,11 +31,11 @@ export default function createUnmuteAlertTests({ getService }: FtrProviderContex objectRemover.add(space.id, createdAlert.id, 'alert'); await supertest - .post(`${getUrlPrefix(space.id)}/api/alert/${createdAlert.id}/_mute`) + .post(`${getUrlPrefix(space.id)}/api/alert/${createdAlert.id}/_mute_all`) .set('kbn-xsrf', 'foo'); const response = await supertestWithoutAuth - .post(`${getUrlPrefix(space.id)}/api/alert/${createdAlert.id}/_unmute`) + .post(`${getUrlPrefix(space.id)}/api/alert/${createdAlert.id}/_unmute_all`) .set('kbn-xsrf', 'foo') .auth(user.username, user.password); diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/mute.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/mute.ts index aaadc7000814a..e2c861a7e2e17 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/mute.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/mute.ts @@ -27,7 +27,7 @@ export default function createMuteTests({ getService }: FtrProviderContext) { objectRemover.add(Spaces.space1.id, createdAlert.id, 'alert'); await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alert/${createdAlert.id}/_mute`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alert/${createdAlert.id}/_mute_all`) .set('kbn-xsrf', 'foo') .expect(204, ''); diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/unmute.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/unmute.ts index f050fb12b01cd..5cee11f8e1188 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/unmute.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/unmute.ts @@ -27,12 +27,12 @@ export default function createUnmuteTests({ getService }: FtrProviderContext) { objectRemover.add(Spaces.space1.id, createdAlert.id, 'alert'); await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alert/${createdAlert.id}/_mute`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alert/${createdAlert.id}/_mute_all`) .set('kbn-xsrf', 'foo') .expect(204, ''); await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alert/${createdAlert.id}/_unmute`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alert/${createdAlert.id}/_unmute_all`) .set('kbn-xsrf', 'foo') .expect(204, ''); From 1a97fc24bf9a98e736166a4736fc3384832e0125 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Wed, 25 Sep 2019 11:31:37 -0400 Subject: [PATCH 18/26] Make alerts.ts integration test use alertUtils for both spaces_only and security_and_spaces --- .../common/lib/alert_utils.ts | 120 +++++++++-------- .../spaces_only/tests/alerting/alerts.ts | 124 +++++------------- 2 files changed, 104 insertions(+), 140 deletions(-) diff --git a/x-pack/test/alerting_api_integration/common/lib/alert_utils.ts b/x-pack/test/alerting_api_integration/common/lib/alert_utils.ts index 7c077e5f11f94..03b2a6c978d72 100644 --- a/x-pack/test/alerting_api_integration/common/lib/alert_utils.ts +++ b/x-pack/test/alerting_api_integration/common/lib/alert_utils.ts @@ -10,7 +10,7 @@ import { getUrlPrefix } from './space_test_utils'; import { ES_TEST_INDEX_NAME } from './es_test_index_tool'; export interface AlertUtilsOpts { - user: User; + user?: User; space: Space; supertestWithoutAuth: any; indexRecordActionId: string; @@ -19,7 +19,7 @@ export interface AlertUtilsOpts { export class AlertUtils { private referenceCounter = 1; - private readonly user: User; + private readonly user?: User; private readonly space: Space; private readonly supertestWithoutAuth: any; private readonly indexRecordActionId: string; @@ -40,89 +40,105 @@ export class AlertUtils { } public generateReference() { - return `alert-utils-ref-${this.referenceCounter++}:${this.user.username}`; + return ['alert-utils-ref', this.referenceCounter++, this.user ? this.user.username : ''].join( + ':' + ); } public async enable(alertId: string) { - await this.supertestWithoutAuth + let request = this.supertestWithoutAuth .post(`${getUrlPrefix(this.space.id)}/api/alert/${alertId}/_enable`) - .set('kbn-xsrf', 'foo') - .auth(this.user.username, this.user.password) - .expect(204, ''); + .set('kbn-xsrf', 'foo'); + if (this.user) { + request = request.auth(this.user.username, this.user.password); + } + await request.expect(204, ''); } public async disable(alertId: string) { - await this.supertestWithoutAuth + let request = this.supertestWithoutAuth .post(`${getUrlPrefix(this.space.id)}/api/alert/${alertId}/_disable`) - .set('kbn-xsrf', 'foo') - .auth(this.user.username, this.user.password) - .expect(204, ''); + .set('kbn-xsrf', 'foo'); + if (this.user) { + request = request.auth(this.user.username, this.user.password); + } + await request.expect(204, ''); } public async mute(alertId: string) { - return await this.supertestWithoutAuth + let request = this.supertestWithoutAuth .post(`${getUrlPrefix(this.space.id)}/api/alert/${alertId}/_mute_all`) - .set('kbn-xsrf', 'foo') - .auth(this.user.username, this.user.password) - .expect(204, ''); + .set('kbn-xsrf', 'foo'); + if (this.user) { + request = request.auth(this.user.username, this.user.password); + } + await request.expect(204, ''); } public async unmute(alertId: string) { - await this.supertestWithoutAuth + let request = this.supertestWithoutAuth .post(`${getUrlPrefix(this.space.id)}/api/alert/${alertId}/_unmute_all`) - .set('kbn-xsrf', 'foo') - .auth(this.user.username, this.user.password) - .expect(204, ''); + .set('kbn-xsrf', 'foo'); + if (this.user) { + request = request.auth(this.user.username, this.user.password); + } + await request.expect(204, ''); } public async muteInstance(alertId: string, instanceId: string) { - return await this.supertestWithoutAuth + let request = this.supertestWithoutAuth .post( `${getUrlPrefix(this.space.id)}/api/alert/${alertId}/alert_instance/${instanceId}/_mute` ) - .set('kbn-xsrf', 'foo') - .auth(this.user.username, this.user.password) - .expect(204, ''); + .set('kbn-xsrf', 'foo'); + if (this.user) { + request = request.auth(this.user.username, this.user.password); + } + await request.expect(204, ''); } public async unmuteInstance(alertId: string, instanceId: string) { - return await this.supertestWithoutAuth + let request = this.supertestWithoutAuth .post( `${getUrlPrefix(this.space.id)}/api/alert/${alertId}/alert_instance/${instanceId}/_unmute` ) - .set('kbn-xsrf', 'foo') - .auth(this.user.username, this.user.password) - .expect(204, ''); + .set('kbn-xsrf', 'foo'); + if (this.user) { + request = request.auth(this.user.username, this.user.password); + } + await request.expect(204, ''); } public async createAlwaysFiringAction(reference: string, overwrites = {}) { - const response = await this.supertestWithoutAuth + let request = this.supertestWithoutAuth .post(`${getUrlPrefix(this.space.id)}/api/alert`) - .set('kbn-xsrf', 'foo') - .auth(this.user.username, this.user.password) - .send({ - enabled: true, - interval: '1m', - throttle: '1m', - alertTypeId: 'test.always-firing', - alertTypeParams: { - index: ES_TEST_INDEX_NAME, - reference, - }, - actions: [ - { - group: 'default', - id: this.indexRecordActionId, - params: { - index: ES_TEST_INDEX_NAME, - reference, - message: - 'instanceContextValue: {{context.instanceContextValue}}, instanceStateValue: {{state.instanceStateValue}}', - }, + .set('kbn-xsrf', 'foo'); + if (this.user) { + request = request.auth(this.user.username, this.user.password); + } + const response = await request.send({ + enabled: true, + interval: '1m', + throttle: '1m', + alertTypeId: 'test.always-firing', + alertTypeParams: { + index: ES_TEST_INDEX_NAME, + reference, + }, + actions: [ + { + group: 'default', + id: this.indexRecordActionId, + params: { + index: ES_TEST_INDEX_NAME, + reference, + message: + 'instanceContextValue: {{context.instanceContextValue}}, instanceStateValue: {{state.instanceStateValue}}', }, - ], - ...overwrites, - }); + }, + ], + ...overwrites, + }); if (response.statusCode === 200) { this.objectRemover.add(this.space.id, response.body.id, 'alert'); } diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/alerts.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/alerts.ts index 07f6fbfc395c3..8a69dedcd11db 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/alerts.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/alerts.ts @@ -13,65 +13,28 @@ import { getUrlPrefix, getTestAlertData, ObjectRemover, + AlertUtils, } from '../../../common/lib'; // eslint-disable-next-line import/no-default-export export default function alertTests({ getService }: FtrProviderContext) { - const supertest = getService('supertest'); + const supertestWithoutAuth = getService('supertestWithoutAuth'); const es = getService('es'); const retry = getService('retry'); const esTestIndexTool = new ESTestIndexTool(es, retry); describe('alerts', () => { + let alertUtils: AlertUtils; + let indexRecordActionId: string; const authorizationIndex = '.kibana-test-authorization'; - const objectRemover = new ObjectRemover(supertest); + const objectRemover = new ObjectRemover(supertestWithoutAuth); before(async () => { await esTestIndexTool.destroy(); await esTestIndexTool.setup(); await es.indices.create({ index: authorizationIndex }); - }); - afterEach(() => objectRemover.removeAll()); - after(async () => { - await esTestIndexTool.destroy(); - await es.indices.delete({ index: authorizationIndex }); - }); - - async function searchTestIndexDocs(source: string, reference: string) { - return await es.search({ - index: ES_TEST_INDEX_NAME, - body: { - query: { - bool: { - must: [ - { - term: { - source, - }, - }, - { - term: { - reference, - }, - }, - ], - }, - }, - }, - }); - } - - async function waitForTestIndexDocs(source: string, reference: string, numDocs: number = 1) { - return await retry.try(async () => { - const searchResult = await searchTestIndexDocs(source, reference); - expect(searchResult.hits.total.value).to.eql(numDocs); - return searchResult.hits.hits; - }); - } - - async function createIndexRecordAction(spaceId: string) { - const { body: createdAction } = await supertest - .post(`${getUrlPrefix(spaceId)}/api/action`) + const { body: createdAction } = await supertestWithoutAuth + .post(`${getUrlPrefix(Spaces.space1.id)}/api/action`) .set('kbn-xsrf', 'foo') .send({ description: 'My action', @@ -84,43 +47,28 @@ export default function alertTests({ getService }: FtrProviderContext) { }, }) .expect(200); - objectRemover.add(spaceId, createdAction.id, 'action'); - return createdAction; - } + indexRecordActionId = createdAction.id; + alertUtils = new AlertUtils({ + space: Spaces.space1, + supertestWithoutAuth, + indexRecordActionId, + objectRemover, + }); + }); + afterEach(() => objectRemover.removeAll()); + after(async () => { + await esTestIndexTool.destroy(); + await es.indices.delete({ index: authorizationIndex }); + objectRemover.add(Spaces.space1.id, indexRecordActionId, 'action'); + await objectRemover.removeAll(); + }); it('should schedule task, run alert and schedule actions', async () => { - const reference = `create-test-1:${Spaces.space1.id}`; - const createdAction = await createIndexRecordAction(Spaces.space1.id); - - const response = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alert`) - .set('kbn-xsrf', 'foo') - .send( - getTestAlertData({ - interval: '1m', - alertTypeId: 'test.always-firing', - alertTypeParams: { - index: ES_TEST_INDEX_NAME, - reference, - }, - actions: [ - { - group: 'default', - id: createdAction.id, - params: { - index: ES_TEST_INDEX_NAME, - reference, - message: - 'instanceContextValue: {{context.instanceContextValue}}, instanceStateValue: {{state.instanceStateValue}}', - }, - }, - ], - }) - ); + const reference = alertUtils.generateReference(); + const response = await alertUtils.createAlwaysFiringAction(reference); expect(response.statusCode).to.eql(200); - objectRemover.add(Spaces.space1.id, response.body.id, 'alert'); - const alertTestRecord = (await waitForTestIndexDocs( + const alertTestRecord = (await esTestIndexTool.waitForDocs( 'alert:test.always-firing', reference ))[0]; @@ -133,7 +81,7 @@ export default function alertTests({ getService }: FtrProviderContext) { reference, }, }); - const actionTestRecord = (await waitForTestIndexDocs( + const actionTestRecord = (await esTestIndexTool.waitForDocs( 'action:test.index-record', reference ))[0]; @@ -160,7 +108,7 @@ export default function alertTests({ getService }: FtrProviderContext) { // We have to provide the test.rate-limit the next runAt, for testing purposes const retryDate = new Date(Date.now() + 60000); - const { body: createdAction } = await supertest + const { body: createdAction } = await supertestWithoutAuth .post(`${getUrlPrefix(Spaces.space1.id)}/api/action`) .set('kbn-xsrf', 'foo') .send({ @@ -171,8 +119,8 @@ export default function alertTests({ getService }: FtrProviderContext) { .expect(200); objectRemover.add(Spaces.space1.id, createdAction.id, 'action'); - const reference = `create-test-2:${Spaces.space1.id}`; - const response = await supertest + const reference = alertUtils.generateReference(); + const response = await supertestWithoutAuth .post(`${getUrlPrefix(Spaces.space1.id)}/api/alert`) .set('kbn-xsrf', 'foo') .send( @@ -240,8 +188,8 @@ export default function alertTests({ getService }: FtrProviderContext) { }); it('should have proper callCluster and savedObjectsClient authorization for alert type executor', async () => { - const reference = `create-test-3:${Spaces.space1.id}`; - const response = await supertest + const reference = alertUtils.generateReference(); + const response = await supertestWithoutAuth .post(`${getUrlPrefix(Spaces.space1.id)}/api/alert`) .set('kbn-xsrf', 'foo') .send( @@ -259,7 +207,7 @@ export default function alertTests({ getService }: FtrProviderContext) { expect(response.statusCode).to.eql(200); objectRemover.add(Spaces.space1.id, response.body.id, 'alert'); - const alertTestRecord = (await waitForTestIndexDocs( + const alertTestRecord = (await esTestIndexTool.waitForDocs( 'alert:test.authorization', reference ))[0]; @@ -277,8 +225,8 @@ export default function alertTests({ getService }: FtrProviderContext) { }); it('should have proper callCluster and savedObjectsClient authorization for action type executor', async () => { - const reference = `create-test-4:${Spaces.space1.id}`; - const { body: createdAction } = await supertest + const reference = alertUtils.generateReference(); + const { body: createdAction } = await supertestWithoutAuth .post(`${getUrlPrefix(Spaces.space1.id)}/api/action`) .set('kbn-xsrf', 'foo') .send({ @@ -287,7 +235,7 @@ export default function alertTests({ getService }: FtrProviderContext) { }) .expect(200); objectRemover.add(Spaces.space1.id, createdAction.id, 'action'); - const response = await supertest + const response = await supertestWithoutAuth .post(`${getUrlPrefix(Spaces.space1.id)}/api/alert`) .set('kbn-xsrf', 'foo') .send( @@ -315,7 +263,7 @@ export default function alertTests({ getService }: FtrProviderContext) { expect(response.statusCode).to.eql(200); objectRemover.add(Spaces.space1.id, response.body.id, 'alert'); - const actionTestRecord = (await waitForTestIndexDocs( + const actionTestRecord = (await esTestIndexTool.waitForDocs( 'action:test.authorization', reference ))[0]; From 4e25fcd378fe8c936498332396e56e5ce3a46beb Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Wed, 25 Sep 2019 16:23:05 -0400 Subject: [PATCH 19/26] Re-use alert utils where possible --- .../common/lib/alert_utils.ts | 120 +++++++++++++----- .../tests/alerting/alerts.ts | 104 ++++++++------- .../tests/alerting/disable.ts | 20 ++- .../tests/alerting/enable.ts | 20 ++- .../tests/alerting/mute.ts | 9 +- .../tests/alerting/mute_instance.ts | 14 +- .../tests/alerting/unmute.ts | 12 +- .../tests/alerting/unmute_instance.ts | 9 +- .../tests/alerting/update_api_key.ts | 27 ++-- .../spaces_only/tests/alerting/alerts.ts | 2 +- .../spaces_only/tests/alerting/disable.ts | 33 ++--- .../spaces_only/tests/alerting/enable.ts | 35 +++-- .../spaces_only/tests/alerting/mute.ts | 16 +-- .../tests/alerting/mute_instance.ts | 18 +-- .../spaces_only/tests/alerting/unmute.ts | 22 ++-- .../tests/alerting/unmute_instance.ts | 26 ++-- .../tests/alerting/update_api_key.ts | 35 +++-- 17 files changed, 270 insertions(+), 252 deletions(-) diff --git a/x-pack/test/alerting_api_integration/common/lib/alert_utils.ts b/x-pack/test/alerting_api_integration/common/lib/alert_utils.ts index 03b2a6c978d72..48d7754030e1e 100644 --- a/x-pack/test/alerting_api_integration/common/lib/alert_utils.ts +++ b/x-pack/test/alerting_api_integration/common/lib/alert_utils.ts @@ -13,8 +13,15 @@ export interface AlertUtilsOpts { user?: User; space: Space; supertestWithoutAuth: any; - indexRecordActionId: string; - objectRemover: ObjectRemover; + indexRecordActionId?: string; + objectRemover?: ObjectRemover; +} + +export interface CreateAlwaysFiringActionOpts { + indexRecordActionId?: string; + objectRemover?: ObjectRemover; + overwrites?: Record; + reference: string; } export class AlertUtils { @@ -22,8 +29,8 @@ export class AlertUtils { private readonly user?: User; private readonly space: Space; private readonly supertestWithoutAuth: any; - private readonly indexRecordActionId: string; - private readonly objectRemover: ObjectRemover; + private readonly indexRecordActionId?: string; + private readonly objectRemover?: ObjectRemover; constructor({ indexRecordActionId, @@ -45,71 +52,124 @@ export class AlertUtils { ); } - public async enable(alertId: string) { - let request = this.supertestWithoutAuth + public getEnableRequest(alertId: string) { + const request = this.supertestWithoutAuth .post(`${getUrlPrefix(this.space.id)}/api/alert/${alertId}/_enable`) .set('kbn-xsrf', 'foo'); if (this.user) { - request = request.auth(this.user.username, this.user.password); + return request.auth(this.user.username, this.user.password); } - await request.expect(204, ''); + return request; } - public async disable(alertId: string) { - let request = this.supertestWithoutAuth + public getDisableRequest(alertId: string) { + const request = this.supertestWithoutAuth .post(`${getUrlPrefix(this.space.id)}/api/alert/${alertId}/_disable`) .set('kbn-xsrf', 'foo'); if (this.user) { - request = request.auth(this.user.username, this.user.password); + return request.auth(this.user.username, this.user.password); } - await request.expect(204, ''); + return request; } - public async mute(alertId: string) { - let request = this.supertestWithoutAuth + public getMuteRequest(alertId: string) { + const request = this.supertestWithoutAuth .post(`${getUrlPrefix(this.space.id)}/api/alert/${alertId}/_mute_all`) .set('kbn-xsrf', 'foo'); if (this.user) { - request = request.auth(this.user.username, this.user.password); + return request.auth(this.user.username, this.user.password); } - await request.expect(204, ''); + return request; } - public async unmute(alertId: string) { - let request = this.supertestWithoutAuth + public getUnmuteRequest(alertId: string) { + const request = this.supertestWithoutAuth .post(`${getUrlPrefix(this.space.id)}/api/alert/${alertId}/_unmute_all`) .set('kbn-xsrf', 'foo'); if (this.user) { - request = request.auth(this.user.username, this.user.password); + return request.auth(this.user.username, this.user.password); } - await request.expect(204, ''); + return request; } - public async muteInstance(alertId: string, instanceId: string) { - let request = this.supertestWithoutAuth + public getMuteInstanceRequest(alertId: string, instanceId: string) { + const request = this.supertestWithoutAuth .post( `${getUrlPrefix(this.space.id)}/api/alert/${alertId}/alert_instance/${instanceId}/_mute` ) .set('kbn-xsrf', 'foo'); if (this.user) { - request = request.auth(this.user.username, this.user.password); + return request.auth(this.user.username, this.user.password); } - await request.expect(204, ''); + return request; } - public async unmuteInstance(alertId: string, instanceId: string) { - let request = this.supertestWithoutAuth + public getUnmuteInstanceRequest(alertId: string, instanceId: string) { + const request = this.supertestWithoutAuth .post( `${getUrlPrefix(this.space.id)}/api/alert/${alertId}/alert_instance/${instanceId}/_unmute` ) .set('kbn-xsrf', 'foo'); if (this.user) { - request = request.auth(this.user.username, this.user.password); + return request.auth(this.user.username, this.user.password); } - await request.expect(204, ''); + return request; } - public async createAlwaysFiringAction(reference: string, overwrites = {}) { + public getUpdateApiKeyRequest(alertId: string) { + const request = this.supertestWithoutAuth + .post(`${getUrlPrefix(this.space.id)}/api/alert/${alertId}/_update_api_key`) + .set('kbn-xsrf', 'foo'); + if (this.user) { + return request.auth(this.user.username, this.user.password); + } + return request; + } + + public async enable(alertId: string) { + await this.getEnableRequest(alertId).expect(204, ''); + } + + public async disable(alertId: string) { + await this.getDisableRequest(alertId).expect(204, ''); + } + + public async mute(alertId: string) { + await this.getMuteRequest(alertId).expect(204, ''); + } + + public async unmute(alertId: string) { + await this.getUnmuteRequest(alertId).expect(204, ''); + } + + public async muteInstance(alertId: string, instanceId: string) { + await this.getMuteInstanceRequest(alertId, instanceId).expect(204, ''); + } + + public async unmuteInstance(alertId: string, instanceId: string) { + await this.getUnmuteInstanceRequest(alertId, instanceId).expect(204, ''); + } + + public async updateApiKey(alertId: string) { + await this.getUpdateApiKeyRequest(alertId).expect(204, ''); + } + + public async createAlwaysFiringAction({ + objectRemover, + overwrites = {}, + indexRecordActionId, + reference, + }: CreateAlwaysFiringActionOpts) { + const objRemover = objectRemover || this.objectRemover; + const actionId = indexRecordActionId || this.indexRecordActionId; + + if (!objRemover) { + throw new Error('objectRemover is required'); + } + if (!actionId) { + throw new Error('indexRecordActionId is required '); + } + let request = this.supertestWithoutAuth .post(`${getUrlPrefix(this.space.id)}/api/alert`) .set('kbn-xsrf', 'foo'); @@ -140,7 +200,7 @@ export class AlertUtils { ...overwrites, }); if (response.statusCode === 200) { - this.objectRemover.add(this.space.id, response.body.id, 'alert'); + objRemover.add(this.space.id, response.body.id, 'alert'); } return response; } diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/alerts.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/alerts.ts index c914709c81635..0961b07c66bb5 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/alerts.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/alerts.ts @@ -74,7 +74,7 @@ export default function alertTests({ getService }: FtrProviderContext) { it('should schedule task, run alert and schedule actions when appropriate', async () => { const reference = alertUtils.generateReference(); - const response = await alertUtils.createAlwaysFiringAction(reference); + const response = await alertUtils.createAlwaysFiringAction({ reference }); switch (scenario.id) { case 'no_kibana_privileges at space1': @@ -408,8 +408,11 @@ export default function alertTests({ getService }: FtrProviderContext) { it('should throttle alerts when appropriate', async () => { const reference = alertUtils.generateReference(); - const response = await alertUtils.createAlwaysFiringAction(reference, { - interval: '1s', + const response = await alertUtils.createAlwaysFiringAction({ + reference, + overwrites: { + interval: '1s', + }, }); switch (scenario.id) { @@ -440,33 +443,36 @@ export default function alertTests({ getService }: FtrProviderContext) { it('should not throttle when changing groups', async () => { const reference = alertUtils.generateReference(); - const response = await alertUtils.createAlwaysFiringAction(reference, { - interval: '1s', - alertTypeParams: { - index: ES_TEST_INDEX_NAME, - reference, - groupsToScheduleActionsInSeries: ['default', 'other'], - }, - actions: [ - { - group: 'default', - id: indexRecordActionId, - params: { - index: ES_TEST_INDEX_NAME, - reference, - message: 'from:default', - }, + const response = await alertUtils.createAlwaysFiringAction({ + reference, + overwrites: { + interval: '1s', + alertTypeParams: { + index: ES_TEST_INDEX_NAME, + reference, + groupsToScheduleActionsInSeries: ['default', 'other'], }, - { - group: 'other', - id: indexRecordActionId, - params: { - index: ES_TEST_INDEX_NAME, - reference, - message: 'from:other', + actions: [ + { + group: 'default', + id: indexRecordActionId, + params: { + index: ES_TEST_INDEX_NAME, + reference, + message: 'from:default', + }, }, - }, - ], + { + group: 'other', + id: indexRecordActionId, + params: { + index: ES_TEST_INDEX_NAME, + reference, + message: 'from:other', + }, + }, + ], + }, }); switch (scenario.id) { @@ -501,12 +507,15 @@ export default function alertTests({ getService }: FtrProviderContext) { it('should reset throttle window when not firing', async () => { const reference = alertUtils.generateReference(); - const response = await alertUtils.createAlwaysFiringAction(reference, { - interval: '1s', - alertTypeParams: { - index: ES_TEST_INDEX_NAME, - reference, - groupsToScheduleActionsInSeries: ['default', null, 'default'], + const response = await alertUtils.createAlwaysFiringAction({ + reference, + overwrites: { + interval: '1s', + alertTypeParams: { + index: ES_TEST_INDEX_NAME, + reference, + groupsToScheduleActionsInSeries: ['default', null, 'default'], + }, }, }); @@ -538,9 +547,12 @@ export default function alertTests({ getService }: FtrProviderContext) { it(`shouldn't schedule actions when alert is muted`, async () => { const reference = alertUtils.generateReference(); - const response = await alertUtils.createAlwaysFiringAction(reference, { - enabled: false, - interval: '1s', + const response = await alertUtils.createAlwaysFiringAction({ + reference, + overwrites: { + enabled: false, + interval: '1s', + }, }); switch (scenario.id) { @@ -573,9 +585,12 @@ export default function alertTests({ getService }: FtrProviderContext) { it(`shouldn't schedule actions when alert instance is muted`, async () => { const reference = alertUtils.generateReference(); - const response = await alertUtils.createAlwaysFiringAction(reference, { - enabled: false, - interval: '1s', + const response = await alertUtils.createAlwaysFiringAction({ + reference, + overwrites: { + enabled: false, + interval: '1s', + }, }); switch (scenario.id) { @@ -608,9 +623,12 @@ export default function alertTests({ getService }: FtrProviderContext) { it(`should unmute all instances when unmuting an alert`, async () => { const reference = alertUtils.generateReference(); - const response = await alertUtils.createAlwaysFiringAction(reference, { - enabled: false, - interval: '1s', + const response = await alertUtils.createAlwaysFiringAction({ + reference, + overwrites: { + enabled: false, + interval: '1s', + }, }); switch (scenario.id) { diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/disable.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/disable.ts index 0bdbd60cfd885..8a9b7e3fc35c4 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/disable.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/disable.ts @@ -6,7 +6,7 @@ import expect from '@kbn/expect'; import { UserAtSpaceScenarios } from '../../scenarios'; -import { getUrlPrefix, getTestAlertData, ObjectRemover } from '../../../common/lib'; +import { AlertUtils, getUrlPrefix, getTestAlertData, ObjectRemover } from '../../../common/lib'; import { FtrProviderContext } from '../../../common/ftr_provider_context'; // eslint-disable-next-line import/no-default-export @@ -29,6 +29,8 @@ export default function createDisableAlertTests({ getService }: FtrProviderConte for (const scenario of UserAtSpaceScenarios) { const { user, space } = scenario; + const alertUtils = new AlertUtils({ user, space, supertestWithoutAuth }); + describe(scenario.id, () => { it('should handle disable alert request appropriately', async () => { const { body: createdAlert } = await supertest @@ -38,10 +40,7 @@ export default function createDisableAlertTests({ getService }: FtrProviderConte .expect(200); objectRemover.add(space.id, createdAlert.id, 'alert'); - const response = await supertestWithoutAuth - .post(`${getUrlPrefix(space.id)}/api/alert/${createdAlert.id}/_disable`) - .set('kbn-xsrf', 'foo') - .auth(user.username, user.password); + const response = await alertUtils.getDisableRequest(createdAlert.id); switch (scenario.id) { case 'no_kibana_privileges at space1': @@ -74,23 +73,19 @@ export default function createDisableAlertTests({ getService }: FtrProviderConte it(`shouldn't disable alert from another space`, async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alert`) + .post(`${getUrlPrefix('other')}/api/alert`) .set('kbn-xsrf', 'foo') .send(getTestAlertData({ enabled: true })) .expect(200); - objectRemover.add(space.id, createdAlert.id, 'alert'); + objectRemover.add('other', createdAlert.id, 'alert'); - const response = await supertestWithoutAuth - .post(`${getUrlPrefix('other')}/api/alert/${createdAlert.id}/_disable`) - .set('kbn-xsrf', 'foo') - .auth(user.username, user.password); + const response = await alertUtils.getDisableRequest(createdAlert.id); expect(response.statusCode).to.eql(404); switch (scenario.id) { case 'no_kibana_privileges at space1': case 'space_1_all at space2': case 'global_read at space1': - case 'space_1_all at space1': expect(response.body).to.eql({ statusCode: 404, error: 'Not Found', @@ -98,6 +93,7 @@ export default function createDisableAlertTests({ getService }: FtrProviderConte }); break; case 'superuser at space1': + case 'space_1_all at space1': expect(response.body).to.eql({ statusCode: 404, error: 'Not Found', diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/enable.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/enable.ts index d025b35f3602e..543805fb83b18 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/enable.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/enable.ts @@ -6,7 +6,7 @@ import expect from '@kbn/expect'; import { UserAtSpaceScenarios } from '../../scenarios'; -import { getUrlPrefix, getTestAlertData, ObjectRemover } from '../../../common/lib'; +import { AlertUtils, getUrlPrefix, getTestAlertData, ObjectRemover } from '../../../common/lib'; import { FtrProviderContext } from '../../../common/ftr_provider_context'; // eslint-disable-next-line import/no-default-export @@ -29,6 +29,8 @@ export default function createEnableAlertTests({ getService }: FtrProviderContex for (const scenario of UserAtSpaceScenarios) { const { user, space } = scenario; + const alertUtils = new AlertUtils({ user, space, supertestWithoutAuth }); + describe(scenario.id, () => { it('should handle enable alert request appropriately', async () => { const { body: createdAlert } = await supertest @@ -38,10 +40,7 @@ export default function createEnableAlertTests({ getService }: FtrProviderContex .expect(200); objectRemover.add(space.id, createdAlert.id, 'alert'); - const response = await supertestWithoutAuth - .post(`${getUrlPrefix(space.id)}/api/alert/${createdAlert.id}/_enable`) - .set('kbn-xsrf', 'foo') - .auth(user.username, user.password); + const response = await alertUtils.getEnableRequest(createdAlert.id); switch (scenario.id) { case 'no_kibana_privileges at space1': @@ -79,23 +78,19 @@ export default function createEnableAlertTests({ getService }: FtrProviderContex it(`shouldn't enable alert from another space`, async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alert`) + .post(`${getUrlPrefix('other')}/api/alert`) .set('kbn-xsrf', 'foo') .send(getTestAlertData({ enabled: false })) .expect(200); - objectRemover.add(space.id, createdAlert.id, 'alert'); + objectRemover.add('other', createdAlert.id, 'alert'); - const response = await supertestWithoutAuth - .post(`${getUrlPrefix('other')}/api/alert/${createdAlert.id}/_enable`) - .set('kbn-xsrf', 'foo') - .auth(user.username, user.password); + const response = await alertUtils.getEnableRequest(createdAlert.id); expect(response.statusCode).to.eql(404); switch (scenario.id) { case 'no_kibana_privileges at space1': case 'space_1_all at space2': case 'global_read at space1': - case 'space_1_all at space1': expect(response.body).to.eql({ statusCode: 404, error: 'Not Found', @@ -103,6 +98,7 @@ export default function createEnableAlertTests({ getService }: FtrProviderContex }); break; case 'superuser at space1': + case 'space_1_all at space1': expect(response.body).to.eql({ statusCode: 404, error: 'Not Found', diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/mute.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/mute.ts index 66a6de101002a..267daeeffe68a 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/mute.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/mute.ts @@ -6,7 +6,7 @@ import expect from '@kbn/expect'; import { UserAtSpaceScenarios } from '../../scenarios'; -import { getUrlPrefix, getTestAlertData, ObjectRemover } from '../../../common/lib'; +import { AlertUtils, getUrlPrefix, getTestAlertData, ObjectRemover } from '../../../common/lib'; import { FtrProviderContext } from '../../../common/ftr_provider_context'; // eslint-disable-next-line import/no-default-export @@ -21,6 +21,8 @@ export default function createMuteAlertTests({ getService }: FtrProviderContext) for (const scenario of UserAtSpaceScenarios) { const { user, space } = scenario; + const alertUtils = new AlertUtils({ user, space, supertestWithoutAuth }); + describe(scenario.id, () => { it('should handle mute alert request appropriately', async () => { const { body: createdAlert } = await supertest @@ -30,10 +32,7 @@ export default function createMuteAlertTests({ getService }: FtrProviderContext) .expect(200); objectRemover.add(space.id, createdAlert.id, 'alert'); - const response = await supertestWithoutAuth - .post(`${getUrlPrefix(space.id)}/api/alert/${createdAlert.id}/_mute_all`) - .set('kbn-xsrf', 'foo') - .auth(user.username, user.password); + const response = await alertUtils.getMuteRequest(createdAlert.id); switch (scenario.id) { case 'no_kibana_privileges at space1': diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/mute_instance.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/mute_instance.ts index d02073d4a5018..302b61074e87d 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/mute_instance.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/mute_instance.ts @@ -6,7 +6,7 @@ import expect from '@kbn/expect'; import { UserAtSpaceScenarios } from '../../scenarios'; -import { getUrlPrefix, getTestAlertData, ObjectRemover } from '../../../common/lib'; +import { AlertUtils, getUrlPrefix, getTestAlertData, ObjectRemover } from '../../../common/lib'; import { FtrProviderContext } from '../../../common/ftr_provider_context'; // eslint-disable-next-line import/no-default-export @@ -21,6 +21,8 @@ export default function createMuteAlertInstanceTests({ getService }: FtrProvider for (const scenario of UserAtSpaceScenarios) { const { user, space } = scenario; + const alertUtils = new AlertUtils({ user, space, supertestWithoutAuth }); + describe(scenario.id, () => { it('should handle mute alert instance request appropriately', async () => { const { body: createdAlert } = await supertest @@ -30,10 +32,7 @@ export default function createMuteAlertInstanceTests({ getService }: FtrProvider .expect(200); objectRemover.add(space.id, createdAlert.id, 'alert'); - const response = await supertestWithoutAuth - .post(`${getUrlPrefix(space.id)}/api/alert/${createdAlert.id}/alert_instance/1/_mute`) - .set('kbn-xsrf', 'foo') - .auth(user.username, user.password); + const response = await alertUtils.getMuteInstanceRequest(createdAlert.id, '1'); switch (scenario.id) { case 'no_kibana_privileges at space1': @@ -75,10 +74,7 @@ export default function createMuteAlertInstanceTests({ getService }: FtrProvider .set('kbn-xsrf', 'foo') .expect(204, ''); - const response = await supertestWithoutAuth - .post(`${getUrlPrefix(space.id)}/api/alert/${createdAlert.id}/alert_instance/1/_mute`) - .set('kbn-xsrf', 'foo') - .auth(user.username, user.password); + const response = await alertUtils.getMuteInstanceRequest(createdAlert.id, '1'); switch (scenario.id) { case 'no_kibana_privileges at space1': diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/unmute.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/unmute.ts index fcc5774319209..bbb1b2f4746f8 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/unmute.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/unmute.ts @@ -6,7 +6,7 @@ import expect from '@kbn/expect'; import { UserAtSpaceScenarios } from '../../scenarios'; -import { getUrlPrefix, getTestAlertData, ObjectRemover } from '../../../common/lib'; +import { AlertUtils, getUrlPrefix, getTestAlertData, ObjectRemover } from '../../../common/lib'; import { FtrProviderContext } from '../../../common/ftr_provider_context'; // eslint-disable-next-line import/no-default-export @@ -21,6 +21,8 @@ export default function createUnmuteAlertTests({ getService }: FtrProviderContex for (const scenario of UserAtSpaceScenarios) { const { user, space } = scenario; + const alertUtils = new AlertUtils({ user, space, supertestWithoutAuth }); + describe(scenario.id, () => { it('should handle unmute alert request appropriately', async () => { const { body: createdAlert } = await supertest @@ -32,12 +34,10 @@ export default function createUnmuteAlertTests({ getService }: FtrProviderContex await supertest .post(`${getUrlPrefix(space.id)}/api/alert/${createdAlert.id}/_mute_all`) - .set('kbn-xsrf', 'foo'); - - const response = await supertestWithoutAuth - .post(`${getUrlPrefix(space.id)}/api/alert/${createdAlert.id}/_unmute_all`) .set('kbn-xsrf', 'foo') - .auth(user.username, user.password); + .expect(204, ''); + + const response = await alertUtils.getUnmuteRequest(createdAlert.id); switch (scenario.id) { case 'no_kibana_privileges at space1': diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/unmute_instance.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/unmute_instance.ts index f417012db2a9d..b466575841d0a 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/unmute_instance.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/unmute_instance.ts @@ -6,7 +6,7 @@ import expect from '@kbn/expect'; import { UserAtSpaceScenarios } from '../../scenarios'; -import { getUrlPrefix, getTestAlertData, ObjectRemover } from '../../../common/lib'; +import { AlertUtils, getUrlPrefix, getTestAlertData, ObjectRemover } from '../../../common/lib'; import { FtrProviderContext } from '../../../common/ftr_provider_context'; // eslint-disable-next-line import/no-default-export @@ -21,6 +21,8 @@ export default function createMuteAlertInstanceTests({ getService }: FtrProvider for (const scenario of UserAtSpaceScenarios) { const { user, space } = scenario; + const alertUtils = new AlertUtils({ user, space, supertestWithoutAuth }); + describe(scenario.id, () => { it('should handle unmute alert instance request appropriately', async () => { const { body: createdAlert } = await supertest @@ -35,10 +37,7 @@ export default function createMuteAlertInstanceTests({ getService }: FtrProvider .set('kbn-xsrf', 'foo') .expect(204, ''); - const response = await supertestWithoutAuth - .post(`${getUrlPrefix(space.id)}/api/alert/${createdAlert.id}/alert_instance/1/_unmute`) - .set('kbn-xsrf', 'foo') - .auth(user.username, user.password); + const response = await alertUtils.getUnmuteInstanceRequest(createdAlert.id, '1'); switch (scenario.id) { case 'no_kibana_privileges at space1': diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/update_api_key.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/update_api_key.ts index a3357d7ac46c3..4963d749c2935 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/update_api_key.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/update_api_key.ts @@ -5,8 +5,8 @@ */ import expect from '@kbn/expect'; -import { UserAtSpaceScenarios, Spaces } from '../../scenarios'; -import { getUrlPrefix, getTestAlertData, ObjectRemover } from '../../../common/lib'; +import { UserAtSpaceScenarios } from '../../scenarios'; +import { AlertUtils, getUrlPrefix, getTestAlertData, ObjectRemover } from '../../../common/lib'; import { FtrProviderContext } from '../../../common/ftr_provider_context'; // eslint-disable-next-line import/no-default-export @@ -16,16 +16,13 @@ export default function createUpdateApiKeyTests({ getService }: FtrProviderConte describe('update_api_key', () => { const objectRemover = new ObjectRemover(supertest); - const OtherSpace = Spaces.find(space => space.id === 'other'); - - if (!OtherSpace) { - throw new Error('Space "other" not defined in scenarios'); - } after(() => objectRemover.removeAll()); for (const scenario of UserAtSpaceScenarios) { const { user, space } = scenario; + const alertUtils = new AlertUtils({ user, space, supertestWithoutAuth }); + describe(scenario.id, () => { it('should handle update alert api key request appropriately', async () => { const { body: createdAlert } = await supertest @@ -35,10 +32,7 @@ export default function createUpdateApiKeyTests({ getService }: FtrProviderConte .expect(200); objectRemover.add(space.id, createdAlert.id, 'alert'); - const response = await supertestWithoutAuth - .post(`${getUrlPrefix(space.id)}/api/alert/${createdAlert.id}/_update_api_key`) - .set('kbn-xsrf', 'foo') - .auth(user.username, user.password); + const response = await alertUtils.getUpdateApiKeyRequest(createdAlert.id); switch (scenario.id) { case 'no_kibana_privileges at space1': @@ -69,23 +63,19 @@ export default function createUpdateApiKeyTests({ getService }: FtrProviderConte it(`shouldn't update alert api key from another space`, async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alert`) + .post(`${getUrlPrefix('other')}/api/alert`) .set('kbn-xsrf', 'foo') .send(getTestAlertData()) .expect(200); - objectRemover.add(space.id, createdAlert.id, 'alert'); + objectRemover.add('other', createdAlert.id, 'alert'); - const response = await supertestWithoutAuth - .post(`${getUrlPrefix(OtherSpace.id)}/api/alert/${createdAlert.id}/_update_api_key`) - .set('kbn-xsrf', 'foo') - .auth(user.username, user.password); + const response = await alertUtils.getUpdateApiKeyRequest(createdAlert.id); expect(response.statusCode).to.eql(404); switch (scenario.id) { case 'no_kibana_privileges at space1': case 'space_1_all at space2': case 'global_read at space1': - case 'space_1_all at space1': expect(response.body).to.eql({ statusCode: 404, error: 'Not Found', @@ -93,6 +83,7 @@ export default function createUpdateApiKeyTests({ getService }: FtrProviderConte }); break; case 'superuser at space1': + case 'space_1_all at space1': expect(response.body).to.eql({ statusCode: 404, error: 'Not Found', diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/alerts.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/alerts.ts index 8a69dedcd11db..02e0b3795fcc5 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/alerts.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/alerts.ts @@ -65,7 +65,7 @@ export default function alertTests({ getService }: FtrProviderContext) { it('should schedule task, run alert and schedule actions', async () => { const reference = alertUtils.generateReference(); - const response = await alertUtils.createAlwaysFiringAction(reference); + const response = await alertUtils.createAlwaysFiringAction({ reference }); expect(response.statusCode).to.eql(200); const alertTestRecord = (await esTestIndexTool.waitForDocs( diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/disable.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/disable.ts index 1b2e7a39f488e..664e74835d415 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/disable.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/disable.ts @@ -6,16 +6,17 @@ import expect from '@kbn/expect'; import { Spaces } from '../../scenarios'; -import { getUrlPrefix, getTestAlertData, ObjectRemover } from '../../../common/lib'; +import { AlertUtils, getUrlPrefix, getTestAlertData, ObjectRemover } from '../../../common/lib'; import { FtrProviderContext } from '../../../common/ftr_provider_context'; // eslint-disable-next-line import/no-default-export export default function createDisableAlertTests({ getService }: FtrProviderContext) { const es = getService('es'); - const supertest = getService('supertest'); + const supertestWithoutAuth = getService('supertestWithoutAuth'); describe('disable', () => { - const objectRemover = new ObjectRemover(supertest); + const objectRemover = new ObjectRemover(supertestWithoutAuth); + const alertUtils = new AlertUtils({ space: Spaces.space1, supertestWithoutAuth }); after(() => objectRemover.removeAll()); @@ -27,17 +28,14 @@ export default function createDisableAlertTests({ getService }: FtrProviderConte } it('should handle disable alert request appropriately', async () => { - const { body: createdAlert } = await supertest + const { body: createdAlert } = await supertestWithoutAuth .post(`${getUrlPrefix(Spaces.space1.id)}/api/alert`) .set('kbn-xsrf', 'foo') .send(getTestAlertData({ enabled: true })) .expect(200); objectRemover.add(Spaces.space1.id, createdAlert.id, 'alert'); - await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alert/${createdAlert.id}/_disable`) - .set('kbn-xsrf', 'foo') - .expect(204, ''); + await alertUtils.disable(createdAlert.id); try { await getScheduledTask(createdAlert.scheduledTaskId); @@ -48,21 +46,18 @@ export default function createDisableAlertTests({ getService }: FtrProviderConte }); it(`shouldn't disable alert from another space`, async () => { - const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alert`) + const { body: createdAlert } = await supertestWithoutAuth + .post(`${getUrlPrefix(Spaces.other.id)}/api/alert`) .set('kbn-xsrf', 'foo') .send(getTestAlertData({ enabled: true })) .expect(200); - objectRemover.add(Spaces.space1.id, createdAlert.id, 'alert'); + objectRemover.add(Spaces.other.id, createdAlert.id, 'alert'); - await supertest - .post(`${getUrlPrefix(Spaces.other.id)}/api/alert/${createdAlert.id}/_disable`) - .set('kbn-xsrf', 'foo') - .expect(404, { - statusCode: 404, - error: 'Not Found', - message: `Saved object [alert/${createdAlert.id}] not found`, - }); + await alertUtils.getDisableRequest(createdAlert.id).expect(404, { + statusCode: 404, + error: 'Not Found', + message: `Saved object [alert/${createdAlert.id}] not found`, + }); }); }); } diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/enable.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/enable.ts index 3a43ccbd07ac5..2a8de1f6e31c3 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/enable.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/enable.ts @@ -6,16 +6,17 @@ import expect from '@kbn/expect'; import { Spaces } from '../../scenarios'; -import { getUrlPrefix, getTestAlertData, ObjectRemover } from '../../../common/lib'; +import { AlertUtils, getUrlPrefix, getTestAlertData, ObjectRemover } from '../../../common/lib'; import { FtrProviderContext } from '../../../common/ftr_provider_context'; // eslint-disable-next-line import/no-default-export export default function createEnableAlertTests({ getService }: FtrProviderContext) { const es = getService('es'); - const supertest = getService('supertest'); + const supertestWithoutAuth = getService('supertestWithoutAuth'); describe('enable', () => { - const objectRemover = new ObjectRemover(supertest); + const objectRemover = new ObjectRemover(supertestWithoutAuth); + const alertUtils = new AlertUtils({ space: Spaces.space1, supertestWithoutAuth }); after(() => objectRemover.removeAll()); @@ -27,19 +28,16 @@ export default function createEnableAlertTests({ getService }: FtrProviderContex } it('should handle enable alert request appropriately', async () => { - const { body: createdAlert } = await supertest + const { body: createdAlert } = await supertestWithoutAuth .post(`${getUrlPrefix(Spaces.space1.id)}/api/alert`) .set('kbn-xsrf', 'foo') .send(getTestAlertData({ enabled: false })) .expect(200); objectRemover.add(Spaces.space1.id, createdAlert.id, 'alert'); - await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alert/${createdAlert.id}/_enable`) - .set('kbn-xsrf', 'foo') - .expect(204, ''); + await alertUtils.enable(createdAlert.id); - const { body: updatedAlert } = await supertest + const { body: updatedAlert } = await supertestWithoutAuth .get(`${getUrlPrefix(Spaces.space1.id)}/api/alert/${createdAlert.id}`) .set('kbn-xsrf', 'foo') .expect(200); @@ -54,21 +52,18 @@ export default function createEnableAlertTests({ getService }: FtrProviderContex }); it(`shouldn't enable alert from another space`, async () => { - const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alert`) + const { body: createdAlert } = await supertestWithoutAuth + .post(`${getUrlPrefix(Spaces.other.id)}/api/alert`) .set('kbn-xsrf', 'foo') .send(getTestAlertData({ enabled: false })) .expect(200); - objectRemover.add(Spaces.space1.id, createdAlert.id, 'alert'); + objectRemover.add(Spaces.other.id, createdAlert.id, 'alert'); - await supertest - .post(`${getUrlPrefix(Spaces.other.id)}/api/alert/${createdAlert.id}/_enable`) - .set('kbn-xsrf', 'foo') - .expect(404, { - statusCode: 404, - error: 'Not Found', - message: `Saved object [alert/${createdAlert.id}] not found`, - }); + await alertUtils.getEnableRequest(createdAlert.id).expect(404, { + statusCode: 404, + error: 'Not Found', + message: `Saved object [alert/${createdAlert.id}] not found`, + }); }); }); } diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/mute.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/mute.ts index e2c861a7e2e17..efaed31ffe15e 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/mute.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/mute.ts @@ -6,32 +6,30 @@ import expect from '@kbn/expect'; import { Spaces } from '../../scenarios'; -import { getUrlPrefix, getTestAlertData, ObjectRemover } from '../../../common/lib'; +import { AlertUtils, getUrlPrefix, getTestAlertData, ObjectRemover } from '../../../common/lib'; import { FtrProviderContext } from '../../../common/ftr_provider_context'; // eslint-disable-next-line import/no-default-export export default function createMuteTests({ getService }: FtrProviderContext) { - const supertest = getService('supertest'); + const supertestWithoutAuth = getService('supertestWithoutAuth'); describe('mute', () => { - const objectRemover = new ObjectRemover(supertest); + const objectRemover = new ObjectRemover(supertestWithoutAuth); + const alertUtils = new AlertUtils({ space: Spaces.space1, supertestWithoutAuth }); after(() => objectRemover.removeAll()); it('should handle mute alert request appropriately', async () => { - const { body: createdAlert } = await supertest + const { body: createdAlert } = await supertestWithoutAuth .post(`${getUrlPrefix(Spaces.space1.id)}/api/alert`) .set('kbn-xsrf', 'foo') .send(getTestAlertData({ enabled: false })) .expect(200); objectRemover.add(Spaces.space1.id, createdAlert.id, 'alert'); - await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alert/${createdAlert.id}/_mute_all`) - .set('kbn-xsrf', 'foo') - .expect(204, ''); + await alertUtils.mute(createdAlert.id); - const { body: updatedAlert } = await supertest + const { body: updatedAlert } = await supertestWithoutAuth .get(`${getUrlPrefix(Spaces.space1.id)}/api/alert/${createdAlert.id}`) .set('kbn-xsrf', 'foo') .expect(200); diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/mute_instance.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/mute_instance.ts index f9bc602c62fda..09ca359716026 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/mute_instance.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/mute_instance.ts @@ -6,34 +6,30 @@ import expect from '@kbn/expect'; import { Spaces } from '../../scenarios'; -import { getUrlPrefix, getTestAlertData, ObjectRemover } from '../../../common/lib'; +import { AlertUtils, getUrlPrefix, getTestAlertData, ObjectRemover } from '../../../common/lib'; import { FtrProviderContext } from '../../../common/ftr_provider_context'; // eslint-disable-next-line import/no-default-export export default function createMuteInstanceTests({ getService }: FtrProviderContext) { - const supertest = getService('supertest'); + const supertestWithoutAuth = getService('supertestWithoutAuth'); describe('mute_instance', () => { - const objectRemover = new ObjectRemover(supertest); + const objectRemover = new ObjectRemover(supertestWithoutAuth); + const alertUtils = new AlertUtils({ space: Spaces.space1, supertestWithoutAuth }); after(() => objectRemover.removeAll()); it('should handle mute alert instance request appropriately', async () => { - const { body: createdAlert } = await supertest + const { body: createdAlert } = await supertestWithoutAuth .post(`${getUrlPrefix(Spaces.space1.id)}/api/alert`) .set('kbn-xsrf', 'foo') .send(getTestAlertData({ enabled: false })) .expect(200); objectRemover.add(Spaces.space1.id, createdAlert.id, 'alert'); - await supertest - .post( - `${getUrlPrefix(Spaces.space1.id)}/api/alert/${createdAlert.id}/alert_instance/1/_mute` - ) - .set('kbn-xsrf', 'foo') - .expect(204, ''); + await alertUtils.muteInstance(createdAlert.id, '1'); - const { body: updatedAlert } = await supertest + const { body: updatedAlert } = await supertestWithoutAuth .get(`${getUrlPrefix(Spaces.space1.id)}/api/alert/${createdAlert.id}`) .set('kbn-xsrf', 'foo') .expect(200); diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/unmute.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/unmute.ts index 5cee11f8e1188..da8d89284d4c7 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/unmute.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/unmute.ts @@ -6,37 +6,31 @@ import expect from '@kbn/expect'; import { Spaces } from '../../scenarios'; -import { getUrlPrefix, getTestAlertData, ObjectRemover } from '../../../common/lib'; +import { AlertUtils, getUrlPrefix, getTestAlertData, ObjectRemover } from '../../../common/lib'; import { FtrProviderContext } from '../../../common/ftr_provider_context'; // eslint-disable-next-line import/no-default-export export default function createUnmuteTests({ getService }: FtrProviderContext) { - const supertest = getService('supertest'); + const supertestWithoutAuth = getService('supertestWithoutAuth'); describe('unmute', () => { - const objectRemover = new ObjectRemover(supertest); + const objectRemover = new ObjectRemover(supertestWithoutAuth); + const alertUtils = new AlertUtils({ space: Spaces.space1, supertestWithoutAuth }); after(() => objectRemover.removeAll()); it('should handle unmute alert request appropriately', async () => { - const { body: createdAlert } = await supertest + const { body: createdAlert } = await supertestWithoutAuth .post(`${getUrlPrefix(Spaces.space1.id)}/api/alert`) .set('kbn-xsrf', 'foo') .send(getTestAlertData({ enabled: false })) .expect(200); objectRemover.add(Spaces.space1.id, createdAlert.id, 'alert'); - await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alert/${createdAlert.id}/_mute_all`) - .set('kbn-xsrf', 'foo') - .expect(204, ''); - - await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alert/${createdAlert.id}/_unmute_all`) - .set('kbn-xsrf', 'foo') - .expect(204, ''); + await alertUtils.mute(createdAlert.id); + await alertUtils.unmute(createdAlert.id); - const { body: updatedAlert } = await supertest + const { body: updatedAlert } = await supertestWithoutAuth .get(`${getUrlPrefix(Spaces.space1.id)}/api/alert/${createdAlert.id}`) .set('kbn-xsrf', 'foo') .expect(200); diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/unmute_instance.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/unmute_instance.ts index 68858ded0111c..d0f1b2fdb3f9f 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/unmute_instance.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/unmute_instance.ts @@ -6,41 +6,31 @@ import expect from '@kbn/expect'; import { Spaces } from '../../scenarios'; -import { getUrlPrefix, getTestAlertData, ObjectRemover } from '../../../common/lib'; +import { AlertUtils, getUrlPrefix, getTestAlertData, ObjectRemover } from '../../../common/lib'; import { FtrProviderContext } from '../../../common/ftr_provider_context'; // eslint-disable-next-line import/no-default-export export default function createUnmuteInstanceTests({ getService }: FtrProviderContext) { - const supertest = getService('supertest'); + const supertestWithoutAuth = getService('supertestWithoutAuth'); describe('unmute_instance', () => { - const objectRemover = new ObjectRemover(supertest); + const objectRemover = new ObjectRemover(supertestWithoutAuth); + const alertUtils = new AlertUtils({ space: Spaces.space1, supertestWithoutAuth }); after(() => objectRemover.removeAll()); it('should handle unmute alert instance request appropriately', async () => { - const { body: createdAlert } = await supertest + const { body: createdAlert } = await supertestWithoutAuth .post(`${getUrlPrefix(Spaces.space1.id)}/api/alert`) .set('kbn-xsrf', 'foo') .send(getTestAlertData({ enabled: false })) .expect(200); objectRemover.add(Spaces.space1.id, createdAlert.id, 'alert'); - await supertest - .post( - `${getUrlPrefix(Spaces.space1.id)}/api/alert/${createdAlert.id}/alert_instance/1/_mute` - ) - .set('kbn-xsrf', 'foo') - .expect(204, ''); - - await supertest - .post( - `${getUrlPrefix(Spaces.space1.id)}/api/alert/${createdAlert.id}/alert_instance/1/_unmute` - ) - .set('kbn-xsrf', 'foo') - .expect(204, ''); + await alertUtils.muteInstance(createdAlert.id, '1'); + await alertUtils.unmuteInstance(createdAlert.id, '1'); - const { body: updatedAlert } = await supertest + const { body: updatedAlert } = await supertestWithoutAuth .get(`${getUrlPrefix(Spaces.space1.id)}/api/alert/${createdAlert.id}`) .set('kbn-xsrf', 'foo') .expect(200); diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/update_api_key.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/update_api_key.ts index 71d20299f2377..2cd3634043740 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/update_api_key.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/update_api_key.ts @@ -6,7 +6,7 @@ import expect from '@kbn/expect'; import { Spaces } from '../../scenarios'; -import { getUrlPrefix, getTestAlertData, ObjectRemover } from '../../../common/lib'; +import { AlertUtils, getUrlPrefix, getTestAlertData, ObjectRemover } from '../../../common/lib'; import { FtrProviderContext } from '../../../common/ftr_provider_context'; /** @@ -15,27 +15,25 @@ import { FtrProviderContext } from '../../../common/ftr_provider_context'; // eslint-disable-next-line import/no-default-export export default function createUpdateApiKeyTests({ getService }: FtrProviderContext) { - const supertest = getService('supertest'); + const supertestWithoutAuth = getService('supertestWithoutAuth'); describe('update_api_key', () => { - const objectRemover = new ObjectRemover(supertest); + const objectRemover = new ObjectRemover(supertestWithoutAuth); + const alertUtils = new AlertUtils({ space: Spaces.space1, supertestWithoutAuth }); after(() => objectRemover.removeAll()); it('should handle update alert api key appropriately', async () => { - const { body: createdAlert } = await supertest + const { body: createdAlert } = await supertestWithoutAuth .post(`${getUrlPrefix(Spaces.space1.id)}/api/alert`) .set('kbn-xsrf', 'foo') .send(getTestAlertData()) .expect(200); objectRemover.add(Spaces.space1.id, createdAlert.id, 'alert'); - await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alert/${createdAlert.id}/_update_api_key`) - .set('kbn-xsrf', 'foo') - .expect(204, ''); + await alertUtils.updateApiKey(createdAlert.id); - const { body: updatedAlert } = await supertest + const { body: updatedAlert } = await supertestWithoutAuth .get(`${getUrlPrefix(Spaces.space1.id)}/api/alert/${createdAlert.id}`) .set('kbn-xsrf', 'foo') .expect(200); @@ -43,21 +41,18 @@ export default function createUpdateApiKeyTests({ getService }: FtrProviderConte }); it(`shouldn't update alert api key from another space`, async () => { - const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alert`) + const { body: createdAlert } = await supertestWithoutAuth + .post(`${getUrlPrefix(Spaces.other.id)}/api/alert`) .set('kbn-xsrf', 'foo') .send(getTestAlertData()) .expect(200); - objectRemover.add(Spaces.space1.id, createdAlert.id, 'alert'); + objectRemover.add(Spaces.other.id, createdAlert.id, 'alert'); - await supertest - .post(`${getUrlPrefix(Spaces.other.id)}/api/alert/${createdAlert.id}/_update_api_key`) - .set('kbn-xsrf', 'foo') - .expect(404, { - statusCode: 404, - error: 'Not Found', - message: `Saved object [alert/${createdAlert.id}] not found`, - }); + await alertUtils.getUpdateApiKeyRequest(createdAlert.id).expect(404, { + statusCode: 404, + error: 'Not Found', + message: `Saved object [alert/${createdAlert.id}] not found`, + }); }); }); } From 67c1bb3f42840669db3d60dfce229dceb7bfe285 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Fri, 27 Sep 2019 12:41:15 -0400 Subject: [PATCH 20/26] Change muted in mapping to muteAll --- x-pack/legacy/plugins/alerting/mappings.json | 2 +- .../alerting/server/alerts_client.test.ts | 68 +++++++++---------- .../plugins/alerting/server/alerts_client.ts | 20 +++--- .../legacy/plugins/alerting/server/types.ts | 4 +- .../tests/alerting/create.ts | 2 +- .../tests/alerting/find.ts | 2 +- .../security_and_spaces/tests/alerting/get.ts | 2 +- .../tests/alerting/mute.ts | 2 +- .../tests/alerting/unmute.ts | 2 +- .../tests/alerting/update.ts | 2 +- .../spaces_only/tests/alerting/create.ts | 2 +- .../spaces_only/tests/alerting/find.ts | 2 +- .../spaces_only/tests/alerting/get.ts | 2 +- .../spaces_only/tests/alerting/mute.ts | 2 +- .../spaces_only/tests/alerting/unmute.ts | 2 +- .../spaces_only/tests/alerting/update.ts | 2 +- 16 files changed, 59 insertions(+), 59 deletions(-) diff --git a/x-pack/legacy/plugins/alerting/mappings.json b/x-pack/legacy/plugins/alerting/mappings.json index 84d6b67642a05..bc648e874cfa4 100644 --- a/x-pack/legacy/plugins/alerting/mappings.json +++ b/x-pack/legacy/plugins/alerting/mappings.json @@ -47,7 +47,7 @@ "throttle": { "type": "keyword" }, - "muted": { + "muteAll": { "type": "boolean" }, "mutedInstanceIds": { diff --git a/x-pack/legacy/plugins/alerting/server/alerts_client.test.ts b/x-pack/legacy/plugins/alerting/server/alerts_client.test.ts index f8f8d34148c7f..b788509ebe691 100644 --- a/x-pack/legacy/plugins/alerting/server/alerts_client.test.ts +++ b/x-pack/legacy/plugins/alerting/server/alerts_client.test.ts @@ -150,31 +150,31 @@ describe('create()', () => { expect(savedObjectsClient.create.mock.calls[0]).toHaveLength(3); expect(savedObjectsClient.create.mock.calls[0][0]).toEqual('alert'); expect(savedObjectsClient.create.mock.calls[0][1]).toMatchInlineSnapshot(` - Object { - "actions": Array [ - Object { - "actionRef": "action_0", - "group": "default", - "params": Object { - "foo": true, - }, - }, - ], - "alertTypeId": "123", - "alertTypeParams": Object { - "bar": true, - }, - "apiKey": undefined, - "apiKeyOwner": undefined, - "createdBy": "elastic", - "enabled": true, - "interval": "10s", - "muted": false, - "mutedInstanceIds": Array [], - "throttle": null, - "updatedBy": "elastic", - } - `); + Object { + "actions": Array [ + Object { + "actionRef": "action_0", + "group": "default", + "params": Object { + "foo": true, + }, + }, + ], + "alertTypeId": "123", + "alertTypeParams": Object { + "bar": true, + }, + "apiKey": undefined, + "apiKeyOwner": undefined, + "createdBy": "elastic", + "enabled": true, + "interval": "10s", + "muteAll": false, + "mutedInstanceIds": Array [], + "throttle": null, + "updatedBy": "elastic", + } + `); expect(savedObjectsClient.create.mock.calls[0][2]).toMatchInlineSnapshot(` Object { "references": Array [ @@ -528,7 +528,7 @@ describe('create()', () => { enabled: true, interval: '10s', throttle: null, - muted: false, + muteAll: false, mutedInstanceIds: [], }, { @@ -744,7 +744,7 @@ describe('mute()', () => { id: '1', type: 'alert', attributes: { - muted: false, + muteAll: false, }, references: [], }); @@ -753,7 +753,7 @@ describe('mute()', () => { expect(savedObjectsClient.update).toHaveBeenCalledWith( 'alert', '1', - { muted: true, mutedInstanceIds: [], updatedBy: 'elastic' }, + { muteAll: true, mutedInstanceIds: [], updatedBy: 'elastic' }, { references: [] } ); }); @@ -764,7 +764,7 @@ describe('mute()', () => { id: '1', type: 'alert', attributes: { - muted: true, + muteAll: true, }, references: [], }); @@ -781,7 +781,7 @@ describe('unmute()', () => { id: '1', type: 'alert', attributes: { - muted: true, + muteAll: true, }, references: [], }); @@ -790,7 +790,7 @@ describe('unmute()', () => { expect(savedObjectsClient.update).toHaveBeenCalledWith( 'alert', '1', - { muted: false, mutedInstanceIds: [], updatedBy: 'elastic' }, + { muteAll: false, mutedInstanceIds: [], updatedBy: 'elastic' }, { references: [] } ); }); @@ -801,7 +801,7 @@ describe('unmute()', () => { id: '1', type: 'alert', attributes: { - muted: false, + muteAll: false, }, references: [], }); @@ -869,7 +869,7 @@ describe('muteInstance()', () => { enabled: true, scheduledTaskId: 'task-123', mutedInstanceIds: [], - muted: true, + muteAll: true, }, references: [], }); @@ -937,7 +937,7 @@ describe('unmuteInstance()', () => { enabled: true, scheduledTaskId: 'task-123', mutedInstanceIds: [], - muted: true, + muteAll: true, }, references: [], }); diff --git a/x-pack/legacy/plugins/alerting/server/alerts_client.ts b/x-pack/legacy/plugins/alerting/server/alerts_client.ts index ba383771ee58f..3292d618c87c0 100644 --- a/x-pack/legacy/plugins/alerting/server/alerts_client.ts +++ b/x-pack/legacy/plugins/alerting/server/alerts_client.ts @@ -60,7 +60,7 @@ interface CreateOptions { Alert, Exclude< keyof Alert, - 'createdBy' | 'updatedBy' | 'apiKey' | 'apiKeyOwner' | 'muted' | 'mutedInstanceIds' + 'createdBy' | 'updatedBy' | 'apiKey' | 'apiKeyOwner' | 'muteAll' | 'mutedInstanceIds' > >; options?: { @@ -122,7 +122,7 @@ export class AlertsClient { ? Buffer.from(`${apiKey.result.id}:${apiKey.result.api_key}`).toString('base64') : undefined, alertTypeParams: validatedAlertTypeParams, - muted: false, + muteAll: false, mutedInstanceIds: [], }); const createdAlert = await this.savedObjectsClient.create('alert', rawAlert, { @@ -309,14 +309,14 @@ export class AlertsClient { public async mute({ id }: { id: string }) { const { references, - attributes: { muted }, + attributes: { muteAll }, } = await this.savedObjectsClient.get('alert', id); - if (!muted) { + if (!muteAll) { await this.savedObjectsClient.update( 'alert', id, { - muted: true, + muteAll: true, mutedInstanceIds: [], updatedBy: await this.getUserName(), }, @@ -328,14 +328,14 @@ export class AlertsClient { public async unmute({ id }: { id: string }) { const { references, - attributes: { muted }, + attributes: { muteAll }, } = await this.savedObjectsClient.get('alert', id); - if (muted) { + if (muteAll) { await this.savedObjectsClient.update( 'alert', id, { - muted: false, + muteAll: false, mutedInstanceIds: [], updatedBy: await this.getUserName(), }, @@ -353,7 +353,7 @@ export class AlertsClient { }) { const existingObject = await this.savedObjectsClient.get('alert', alertId); const mutedInstanceIds = existingObject.attributes.mutedInstanceIds || []; - if (!existingObject.attributes.muted && !mutedInstanceIds.includes(alertInstanceId)) { + if (!existingObject.attributes.muteAll && !mutedInstanceIds.includes(alertInstanceId)) { mutedInstanceIds.push(alertInstanceId); await this.savedObjectsClient.update( 'alert', @@ -379,7 +379,7 @@ export class AlertsClient { }) { const existingObject = await this.savedObjectsClient.get('alert', alertId); const mutedInstanceIds = existingObject.attributes.mutedInstanceIds || []; - if (!existingObject.attributes.muted && mutedInstanceIds.includes(alertInstanceId)) { + if (!existingObject.attributes.muteAll && mutedInstanceIds.includes(alertInstanceId)) { await this.savedObjectsClient.update( 'alert', alertId, diff --git a/x-pack/legacy/plugins/alerting/server/types.ts b/x-pack/legacy/plugins/alerting/server/types.ts index 5b11135f85a4a..723436c4f1c70 100644 --- a/x-pack/legacy/plugins/alerting/server/types.ts +++ b/x-pack/legacy/plugins/alerting/server/types.ts @@ -75,7 +75,7 @@ export interface Alert { apiKey?: string; apiKeyOwner?: string; throttle: string | null; - muted: boolean; + muteAll: boolean; mutedInstanceIds: string[]; } @@ -91,7 +91,7 @@ export interface RawAlert extends SavedObjectAttributes { apiKey?: string; apiKeyOwner?: string; throttle: string | null; - muted: boolean; + muteAll: boolean; mutedInstanceIds: string[]; } diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/create.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/create.ts index af793fed1cccf..4d4bdfa1558b6 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/create.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/create.ts @@ -64,7 +64,7 @@ export default function createAlertTests({ getService }: FtrProviderContext) { throttle: '1m', updatedBy: user.username, apiKeyOwner: user.username, - muted: false, + muteAll: false, mutedInstanceIds: [], }); expect(typeof response.body.scheduledTaskId).to.be('string'); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/find.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/find.ts index fe77b02e10558..e782f0780ea6c 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/find.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/find.ts @@ -66,7 +66,7 @@ export default function createFindTests({ getService }: FtrProviderContext) { throttle: '1m', updatedBy: 'elastic', apiKeyOwner: 'elastic', - muted: false, + muteAll: false, mutedInstanceIds: [], }); break; diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/get.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/get.ts index 250695d3a943b..a40fc0a9ac86e 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/get.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/get.ts @@ -60,7 +60,7 @@ export default function createGetTests({ getService }: FtrProviderContext) { throttle: '1m', updatedBy: 'elastic', apiKeyOwner: 'elastic', - muted: false, + muteAll: false, mutedInstanceIds: [], }); break; diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/mute.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/mute.ts index 267daeeffe68a..9f98fd9a4abb1 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/mute.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/mute.ts @@ -54,7 +54,7 @@ export default function createMuteAlertTests({ getService }: FtrProviderContext) .set('kbn-xsrf', 'foo') .auth(user.username, user.password) .expect(200); - expect(updatedAlert.muted).to.eql(true); + expect(updatedAlert.muteAll).to.eql(true); break; default: throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/unmute.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/unmute.ts index bbb1b2f4746f8..2e124704417fa 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/unmute.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/unmute.ts @@ -59,7 +59,7 @@ export default function createUnmuteAlertTests({ getService }: FtrProviderContex .set('kbn-xsrf', 'foo') .auth(user.username, user.password) .expect(200); - expect(updatedAlert.muted).to.eql(false); + expect(updatedAlert.muteAll).to.eql(false); break; default: throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/update.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/update.ts index 468e70e26d795..5736b82dffec5 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/update.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/update.ts @@ -66,7 +66,7 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { enabled: true, updatedBy: user.username, apiKeyOwner: user.username, - muted: false, + muteAll: false, mutedInstanceIds: [], scheduledTaskId: createdAlert.scheduledTaskId, }); diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/create.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/create.ts index 7dcc4d0ba5c19..10335633f5d28 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/create.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/create.ts @@ -45,7 +45,7 @@ export default function createAlertTests({ getService }: FtrProviderContext) { scheduledTaskId: response.body.scheduledTaskId, updatedBy: null, throttle: '1m', - muted: false, + muteAll: false, mutedInstanceIds: [], }); expect(typeof response.body.scheduledTaskId).to.be('string'); diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/find.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/find.ts index 4b4c29ee51754..521befeb49047 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/find.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/find.ts @@ -48,7 +48,7 @@ export default function createFindTests({ getService }: FtrProviderContext) { scheduledTaskId: match.scheduledTaskId, updatedBy: null, throttle: '1m', - muted: false, + muteAll: false, mutedInstanceIds: [], }); }); diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/get.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/get.ts index 062b5f4048512..cd30b65cb180e 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/get.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/get.ts @@ -42,7 +42,7 @@ export default function createGetTests({ getService }: FtrProviderContext) { scheduledTaskId: response.body.scheduledTaskId, updatedBy: null, throttle: '1m', - muted: false, + muteAll: false, mutedInstanceIds: [], }); }); diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/mute.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/mute.ts index efaed31ffe15e..adfa474d104b7 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/mute.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/mute.ts @@ -33,7 +33,7 @@ export default function createMuteTests({ getService }: FtrProviderContext) { .get(`${getUrlPrefix(Spaces.space1.id)}/api/alert/${createdAlert.id}`) .set('kbn-xsrf', 'foo') .expect(200); - expect(updatedAlert.muted).to.eql(true); + expect(updatedAlert.muteAll).to.eql(true); }); }); } diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/unmute.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/unmute.ts index da8d89284d4c7..eb59117ac803b 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/unmute.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/unmute.ts @@ -34,7 +34,7 @@ export default function createUnmuteTests({ getService }: FtrProviderContext) { .get(`${getUrlPrefix(Spaces.space1.id)}/api/alert/${createdAlert.id}`) .set('kbn-xsrf', 'foo') .expect(200); - expect(updatedAlert.muted).to.eql(false); + expect(updatedAlert.muteAll).to.eql(false); }); }); } diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/update.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/update.ts index 80cac9507d354..d98f6b5cd830b 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/update.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/update.ts @@ -45,7 +45,7 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { enabled: true, updatedBy: null, apiKeyOwner: null, - muted: false, + muteAll: false, mutedInstanceIds: [], scheduledTaskId: createdAlert.scheduledTaskId, }); From 9de3ccf2495926747a1270def4f5cc306f1a08cf Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Fri, 27 Sep 2019 13:01:13 -0400 Subject: [PATCH 21/26] Rename alert client methods to muteAll and unmuteAll --- .../legacy/plugins/alerting/server/alerts_client.mock.ts | 4 ++-- .../legacy/plugins/alerting/server/alerts_client.test.ts | 8 ++++---- x-pack/legacy/plugins/alerting/server/alerts_client.ts | 4 ++-- x-pack/legacy/plugins/alerting/server/routes/mute.test.ts | 2 +- x-pack/legacy/plugins/alerting/server/routes/mute.ts | 2 +- .../legacy/plugins/alerting/server/routes/unmute.test.ts | 2 +- x-pack/legacy/plugins/alerting/server/routes/unmute.ts | 2 +- 7 files changed, 12 insertions(+), 12 deletions(-) diff --git a/x-pack/legacy/plugins/alerting/server/alerts_client.mock.ts b/x-pack/legacy/plugins/alerting/server/alerts_client.mock.ts index b6b6311d04e05..c7d359491680f 100644 --- a/x-pack/legacy/plugins/alerting/server/alerts_client.mock.ts +++ b/x-pack/legacy/plugins/alerting/server/alerts_client.mock.ts @@ -18,8 +18,8 @@ const createAlertsClientMock = () => { enable: jest.fn(), disable: jest.fn(), updateApiKey: jest.fn(), - mute: jest.fn(), - unmute: jest.fn(), + muteAll: jest.fn(), + unmuteAll: jest.fn(), muteInstance: jest.fn(), unmuteInstance: jest.fn(), }; diff --git a/x-pack/legacy/plugins/alerting/server/alerts_client.test.ts b/x-pack/legacy/plugins/alerting/server/alerts_client.test.ts index b788509ebe691..ec18f67c6dd22 100644 --- a/x-pack/legacy/plugins/alerting/server/alerts_client.test.ts +++ b/x-pack/legacy/plugins/alerting/server/alerts_client.test.ts @@ -749,7 +749,7 @@ describe('mute()', () => { references: [], }); - await alertsClient.mute({ id: '1' }); + await alertsClient.muteAll({ id: '1' }); expect(savedObjectsClient.update).toHaveBeenCalledWith( 'alert', '1', @@ -769,7 +769,7 @@ describe('mute()', () => { references: [], }); - await alertsClient.mute({ id: '1' }); + await alertsClient.muteAll({ id: '1' }); expect(savedObjectsClient.update).not.toHaveBeenCalled(); }); }); @@ -786,7 +786,7 @@ describe('unmute()', () => { references: [], }); - await alertsClient.unmute({ id: '1' }); + await alertsClient.unmuteAll({ id: '1' }); expect(savedObjectsClient.update).toHaveBeenCalledWith( 'alert', '1', @@ -806,7 +806,7 @@ describe('unmute()', () => { references: [], }); - await alertsClient.unmute({ id: '1' }); + await alertsClient.unmuteAll({ id: '1' }); expect(savedObjectsClient.update).not.toHaveBeenCalled(); }); }); diff --git a/x-pack/legacy/plugins/alerting/server/alerts_client.ts b/x-pack/legacy/plugins/alerting/server/alerts_client.ts index 3292d618c87c0..2c671b52c261f 100644 --- a/x-pack/legacy/plugins/alerting/server/alerts_client.ts +++ b/x-pack/legacy/plugins/alerting/server/alerts_client.ts @@ -306,7 +306,7 @@ export class AlertsClient { } } - public async mute({ id }: { id: string }) { + public async muteAll({ id }: { id: string }) { const { references, attributes: { muteAll }, @@ -325,7 +325,7 @@ export class AlertsClient { } } - public async unmute({ id }: { id: string }) { + public async unmuteAll({ id }: { id: string }) { const { references, attributes: { muteAll }, diff --git a/x-pack/legacy/plugins/alerting/server/routes/mute.test.ts b/x-pack/legacy/plugins/alerting/server/routes/mute.test.ts index d7b2a01947e25..ddfd2065a3349 100644 --- a/x-pack/legacy/plugins/alerting/server/routes/mute.test.ts +++ b/x-pack/legacy/plugins/alerting/server/routes/mute.test.ts @@ -18,5 +18,5 @@ test('mutes an alert', async () => { const { statusCode } = await server.inject(request); expect(statusCode).toBe(204); - expect(alertsClient.mute).toHaveBeenCalledWith({ id: '1' }); + expect(alertsClient.muteAll).toHaveBeenCalledWith({ id: '1' }); }); diff --git a/x-pack/legacy/plugins/alerting/server/routes/mute.ts b/x-pack/legacy/plugins/alerting/server/routes/mute.ts index 686af10247d48..e7b1e5640eabe 100644 --- a/x-pack/legacy/plugins/alerting/server/routes/mute.ts +++ b/x-pack/legacy/plugins/alerting/server/routes/mute.ts @@ -24,7 +24,7 @@ export function muteAlertRoute(server: Hapi.Server) { }, async handler(request: MuteRequest, h: Hapi.ResponseToolkit) { const alertsClient = request.getAlertsClient!(); - await alertsClient.mute(request.params); + await alertsClient.muteAll(request.params); return h.response(); }, }); diff --git a/x-pack/legacy/plugins/alerting/server/routes/unmute.test.ts b/x-pack/legacy/plugins/alerting/server/routes/unmute.test.ts index fb9946bf8b730..5b2daaf92daf4 100644 --- a/x-pack/legacy/plugins/alerting/server/routes/unmute.test.ts +++ b/x-pack/legacy/plugins/alerting/server/routes/unmute.test.ts @@ -18,5 +18,5 @@ test('unmutes an alert', async () => { const { statusCode } = await server.inject(request); expect(statusCode).toBe(204); - expect(alertsClient.unmute).toHaveBeenCalledWith({ id: '1' }); + expect(alertsClient.unmuteAll).toHaveBeenCalledWith({ id: '1' }); }); diff --git a/x-pack/legacy/plugins/alerting/server/routes/unmute.ts b/x-pack/legacy/plugins/alerting/server/routes/unmute.ts index 355aa8d0fb4d8..a0849ff35bd0e 100644 --- a/x-pack/legacy/plugins/alerting/server/routes/unmute.ts +++ b/x-pack/legacy/plugins/alerting/server/routes/unmute.ts @@ -24,7 +24,7 @@ export function unmuteAlertRoute(server: Hapi.Server) { }, async handler(request: UnmuteRequest, h: Hapi.ResponseToolkit) { const alertsClient = request.getAlertsClient!(); - await alertsClient.unmute(request.params); + await alertsClient.unmuteAll(request.params); return h.response(); }, }); From 3ee1ea4ac450cf149a36617d051a620a78742bf9 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Fri, 27 Sep 2019 13:07:14 -0400 Subject: [PATCH 22/26] Rename files --- x-pack/legacy/plugins/alerting/server/init.ts | 8 ++++---- x-pack/legacy/plugins/alerting/server/routes/index.ts | 4 ++-- .../server/routes/{mute.test.ts => mute_all.test.ts} | 4 ++-- .../alerting/server/routes/{mute.ts => mute_all.ts} | 6 +++--- .../server/routes/{unmute.test.ts => unmute_all.test.ts} | 4 ++-- .../alerting/server/routes/{unmute.ts => unmute_all.ts} | 6 +++--- .../security_and_spaces/tests/alerting/index.ts | 4 ++-- .../tests/alerting/{mute.ts => mute_all.ts} | 2 +- .../tests/alerting/{unmute.ts => unmute_all.ts} | 2 +- .../spaces_only/tests/alerting/index.ts | 4 ++-- .../spaces_only/tests/alerting/{mute.ts => mute_all.ts} | 2 +- .../tests/alerting/{unmute.ts => unmute_all.ts} | 2 +- 12 files changed, 24 insertions(+), 24 deletions(-) rename x-pack/legacy/plugins/alerting/server/routes/{mute.test.ts => mute_all.test.ts} (89%) rename x-pack/legacy/plugins/alerting/server/routes/{mute.ts => mute_all.ts} (78%) rename x-pack/legacy/plugins/alerting/server/routes/{unmute.test.ts => unmute_all.test.ts} (88%) rename x-pack/legacy/plugins/alerting/server/routes/{unmute.ts => unmute_all.ts} (78%) rename x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/{mute.ts => mute_all.ts} (98%) rename x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/{unmute.ts => unmute_all.ts} (98%) rename x-pack/test/alerting_api_integration/spaces_only/tests/alerting/{mute.ts => mute_all.ts} (98%) rename x-pack/test/alerting_api_integration/spaces_only/tests/alerting/{unmute.ts => unmute_all.ts} (98%) diff --git a/x-pack/legacy/plugins/alerting/server/init.ts b/x-pack/legacy/plugins/alerting/server/init.ts index b245f5d64254c..191d9b08c8ab7 100644 --- a/x-pack/legacy/plugins/alerting/server/init.ts +++ b/x-pack/legacy/plugins/alerting/server/init.ts @@ -28,8 +28,8 @@ import { enableAlertRoute, disableAlertRoute, updateApiKeyRoute, - muteAlertRoute, - unmuteAlertRoute, + muteAllAlertRoute, + unmuteAllAlertRoute, muteAlertInstanceRoute, unmuteAlertInstanceRoute, } from './routes'; @@ -136,8 +136,8 @@ export function init(server: Server) { enableAlertRoute(server); disableAlertRoute(server); updateApiKeyRoute(server); - muteAlertRoute(server); - unmuteAlertRoute(server); + muteAllAlertRoute(server); + unmuteAllAlertRoute(server); muteAlertInstanceRoute(server); unmuteAlertInstanceRoute(server); diff --git a/x-pack/legacy/plugins/alerting/server/routes/index.ts b/x-pack/legacy/plugins/alerting/server/routes/index.ts index db359a672cda1..9e568c21f2992 100644 --- a/x-pack/legacy/plugins/alerting/server/routes/index.ts +++ b/x-pack/legacy/plugins/alerting/server/routes/index.ts @@ -15,5 +15,5 @@ export { disableAlertRoute } from './disable'; export { updateApiKeyRoute } from './update_api_key'; export { muteAlertInstanceRoute } from './mute_instance'; export { unmuteAlertInstanceRoute } from './unmute_instance'; -export { muteAlertRoute } from './mute'; -export { unmuteAlertRoute } from './unmute'; +export { muteAllAlertRoute } from './mute_all'; +export { unmuteAllAlertRoute } from './unmute_all'; diff --git a/x-pack/legacy/plugins/alerting/server/routes/mute.test.ts b/x-pack/legacy/plugins/alerting/server/routes/mute_all.test.ts similarity index 89% rename from x-pack/legacy/plugins/alerting/server/routes/mute.test.ts rename to x-pack/legacy/plugins/alerting/server/routes/mute_all.test.ts index ddfd2065a3349..17114fcc62a42 100644 --- a/x-pack/legacy/plugins/alerting/server/routes/mute.test.ts +++ b/x-pack/legacy/plugins/alerting/server/routes/mute_all.test.ts @@ -5,10 +5,10 @@ */ import { createMockServer } from './_mock_server'; -import { muteAlertRoute } from './mute'; +import { muteAllAlertRoute } from './mute_all'; const { server, alertsClient } = createMockServer(); -muteAlertRoute(server); +muteAllAlertRoute(server); test('mutes an alert', async () => { const request = { diff --git a/x-pack/legacy/plugins/alerting/server/routes/mute.ts b/x-pack/legacy/plugins/alerting/server/routes/mute_all.ts similarity index 78% rename from x-pack/legacy/plugins/alerting/server/routes/mute.ts rename to x-pack/legacy/plugins/alerting/server/routes/mute_all.ts index e7b1e5640eabe..5ad63c8ed97d4 100644 --- a/x-pack/legacy/plugins/alerting/server/routes/mute.ts +++ b/x-pack/legacy/plugins/alerting/server/routes/mute_all.ts @@ -6,13 +6,13 @@ import Hapi from 'hapi'; -interface MuteRequest extends Hapi.Request { +interface MuteAllRequest extends Hapi.Request { params: { id: string; }; } -export function muteAlertRoute(server: Hapi.Server) { +export function muteAllAlertRoute(server: Hapi.Server) { server.route({ method: 'POST', path: '/api/alert/{id}/_mute_all', @@ -22,7 +22,7 @@ export function muteAlertRoute(server: Hapi.Server) { emptyStatusCode: 204, }, }, - async handler(request: MuteRequest, h: Hapi.ResponseToolkit) { + async handler(request: MuteAllRequest, h: Hapi.ResponseToolkit) { const alertsClient = request.getAlertsClient!(); await alertsClient.muteAll(request.params); return h.response(); diff --git a/x-pack/legacy/plugins/alerting/server/routes/unmute.test.ts b/x-pack/legacy/plugins/alerting/server/routes/unmute_all.test.ts similarity index 88% rename from x-pack/legacy/plugins/alerting/server/routes/unmute.test.ts rename to x-pack/legacy/plugins/alerting/server/routes/unmute_all.test.ts index 5b2daaf92daf4..62fce147b0105 100644 --- a/x-pack/legacy/plugins/alerting/server/routes/unmute.test.ts +++ b/x-pack/legacy/plugins/alerting/server/routes/unmute_all.test.ts @@ -5,10 +5,10 @@ */ import { createMockServer } from './_mock_server'; -import { unmuteAlertRoute } from './unmute'; +import { unmuteAllAlertRoute } from './unmute_all'; const { server, alertsClient } = createMockServer(); -unmuteAlertRoute(server); +unmuteAllAlertRoute(server); test('unmutes an alert', async () => { const request = { diff --git a/x-pack/legacy/plugins/alerting/server/routes/unmute.ts b/x-pack/legacy/plugins/alerting/server/routes/unmute_all.ts similarity index 78% rename from x-pack/legacy/plugins/alerting/server/routes/unmute.ts rename to x-pack/legacy/plugins/alerting/server/routes/unmute_all.ts index a0849ff35bd0e..8a72f1d9e08f9 100644 --- a/x-pack/legacy/plugins/alerting/server/routes/unmute.ts +++ b/x-pack/legacy/plugins/alerting/server/routes/unmute_all.ts @@ -6,13 +6,13 @@ import Hapi from 'hapi'; -interface UnmuteRequest extends Hapi.Request { +interface UnmuteAllRequest extends Hapi.Request { params: { id: string; }; } -export function unmuteAlertRoute(server: Hapi.Server) { +export function unmuteAllAlertRoute(server: Hapi.Server) { server.route({ method: 'POST', path: '/api/alert/{id}/_unmute_all', @@ -22,7 +22,7 @@ export function unmuteAlertRoute(server: Hapi.Server) { emptyStatusCode: 204, }, }, - async handler(request: UnmuteRequest, h: Hapi.ResponseToolkit) { + async handler(request: UnmuteAllRequest, h: Hapi.ResponseToolkit) { const alertsClient = request.getAlertsClient!(); await alertsClient.unmuteAll(request.params); return h.response(); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/index.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/index.ts index fe0714b8eb36c..1aa084356cfa4 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/index.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/index.ts @@ -16,9 +16,9 @@ export default function alertingTests({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./find')); loadTestFile(require.resolve('./get')); loadTestFile(require.resolve('./list_alert_types')); - loadTestFile(require.resolve('./mute')); + loadTestFile(require.resolve('./mute_all')); loadTestFile(require.resolve('./mute_instance')); - loadTestFile(require.resolve('./unmute')); + loadTestFile(require.resolve('./unmute_all')); loadTestFile(require.resolve('./unmute_instance')); loadTestFile(require.resolve('./update')); loadTestFile(require.resolve('./update_api_key')); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/mute.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/mute_all.ts similarity index 98% rename from x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/mute.ts rename to x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/mute_all.ts index 9f98fd9a4abb1..81a634a8a09e0 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/mute.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/mute_all.ts @@ -14,7 +14,7 @@ export default function createMuteAlertTests({ getService }: FtrProviderContext) const supertest = getService('supertest'); const supertestWithoutAuth = getService('supertestWithoutAuth'); - describe('mute', () => { + describe('mute_all', () => { const objectRemover = new ObjectRemover(supertest); after(() => objectRemover.removeAll()); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/unmute.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/unmute_all.ts similarity index 98% rename from x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/unmute.ts rename to x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/unmute_all.ts index 2e124704417fa..4f4f5b63af2f8 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/unmute.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/unmute_all.ts @@ -14,7 +14,7 @@ export default function createUnmuteAlertTests({ getService }: FtrProviderContex const supertest = getService('supertest'); const supertestWithoutAuth = getService('supertestWithoutAuth'); - describe('unmute', () => { + describe('unmute_all', () => { const objectRemover = new ObjectRemover(supertest); after(() => objectRemover.removeAll()); diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/index.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/index.ts index fe0714b8eb36c..1aa084356cfa4 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/index.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/index.ts @@ -16,9 +16,9 @@ export default function alertingTests({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./find')); loadTestFile(require.resolve('./get')); loadTestFile(require.resolve('./list_alert_types')); - loadTestFile(require.resolve('./mute')); + loadTestFile(require.resolve('./mute_all')); loadTestFile(require.resolve('./mute_instance')); - loadTestFile(require.resolve('./unmute')); + loadTestFile(require.resolve('./unmute_all')); loadTestFile(require.resolve('./unmute_instance')); loadTestFile(require.resolve('./update')); loadTestFile(require.resolve('./update_api_key')); diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/mute.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/mute_all.ts similarity index 98% rename from x-pack/test/alerting_api_integration/spaces_only/tests/alerting/mute.ts rename to x-pack/test/alerting_api_integration/spaces_only/tests/alerting/mute_all.ts index adfa474d104b7..c500c829c51c8 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/mute.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/mute_all.ts @@ -13,7 +13,7 @@ import { FtrProviderContext } from '../../../common/ftr_provider_context'; export default function createMuteTests({ getService }: FtrProviderContext) { const supertestWithoutAuth = getService('supertestWithoutAuth'); - describe('mute', () => { + describe('mute_all', () => { const objectRemover = new ObjectRemover(supertestWithoutAuth); const alertUtils = new AlertUtils({ space: Spaces.space1, supertestWithoutAuth }); diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/unmute.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/unmute_all.ts similarity index 98% rename from x-pack/test/alerting_api_integration/spaces_only/tests/alerting/unmute.ts rename to x-pack/test/alerting_api_integration/spaces_only/tests/alerting/unmute_all.ts index eb59117ac803b..739861d856dd0 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/unmute.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/unmute_all.ts @@ -13,7 +13,7 @@ import { FtrProviderContext } from '../../../common/ftr_provider_context'; export default function createUnmuteTests({ getService }: FtrProviderContext) { const supertestWithoutAuth = getService('supertestWithoutAuth'); - describe('unmute', () => { + describe('unmute_all', () => { const objectRemover = new ObjectRemover(supertestWithoutAuth); const alertUtils = new AlertUtils({ space: Spaces.space1, supertestWithoutAuth }); From 10f660d6537dbe5a56660939ee93fe3bc681e38a Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Fri, 27 Sep 2019 13:12:03 -0400 Subject: [PATCH 23/26] Rename alert utils function muteAll and unmuteAll --- .../common/lib/alert_utils.ts | 12 ++++++------ .../security_and_spaces/tests/alerting/alerts.ts | 6 +++--- .../security_and_spaces/tests/alerting/mute_all.ts | 2 +- .../security_and_spaces/tests/alerting/unmute_all.ts | 2 +- .../spaces_only/tests/alerting/mute_all.ts | 2 +- .../spaces_only/tests/alerting/unmute_all.ts | 4 ++-- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/x-pack/test/alerting_api_integration/common/lib/alert_utils.ts b/x-pack/test/alerting_api_integration/common/lib/alert_utils.ts index 48d7754030e1e..83863ef11c4c9 100644 --- a/x-pack/test/alerting_api_integration/common/lib/alert_utils.ts +++ b/x-pack/test/alerting_api_integration/common/lib/alert_utils.ts @@ -72,7 +72,7 @@ export class AlertUtils { return request; } - public getMuteRequest(alertId: string) { + public getMuteAllRequest(alertId: string) { const request = this.supertestWithoutAuth .post(`${getUrlPrefix(this.space.id)}/api/alert/${alertId}/_mute_all`) .set('kbn-xsrf', 'foo'); @@ -82,7 +82,7 @@ export class AlertUtils { return request; } - public getUnmuteRequest(alertId: string) { + public getUnmuteAllRequest(alertId: string) { const request = this.supertestWithoutAuth .post(`${getUrlPrefix(this.space.id)}/api/alert/${alertId}/_unmute_all`) .set('kbn-xsrf', 'foo'); @@ -134,12 +134,12 @@ export class AlertUtils { await this.getDisableRequest(alertId).expect(204, ''); } - public async mute(alertId: string) { - await this.getMuteRequest(alertId).expect(204, ''); + public async muteAll(alertId: string) { + await this.getMuteAllRequest(alertId).expect(204, ''); } - public async unmute(alertId: string) { - await this.getUnmuteRequest(alertId).expect(204, ''); + public async unmuteAll(alertId: string) { + await this.getUnmuteAllRequest(alertId).expect(204, ''); } public async muteInstance(alertId: string, instanceId: string) { diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/alerts.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/alerts.ts index 0961b07c66bb5..7a984acb2c09f 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/alerts.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/alerts.ts @@ -568,7 +568,7 @@ export default function alertTests({ getService }: FtrProviderContext) { break; case 'space_1_all at space1': case 'superuser at space1': - await alertUtils.mute(response.body.id); + await alertUtils.muteAll(response.body.id); await alertUtils.enable(response.body.id); // Wait until alerts schedule actions twice to ensure actions had a chance to skip execution once await esTestIndexTool.waitForDocs('alert:test.always-firing', reference, 2); @@ -645,8 +645,8 @@ export default function alertTests({ getService }: FtrProviderContext) { case 'space_1_all at space1': case 'superuser at space1': await alertUtils.muteInstance(response.body.id, '1'); - await alertUtils.mute(response.body.id); - await alertUtils.unmute(response.body.id); + await alertUtils.muteAll(response.body.id); + await alertUtils.unmuteAll(response.body.id); await alertUtils.enable(response.body.id); // Wait until alerts scheduled actions twice to ensure actions had a chance to execute once await esTestIndexTool.waitForDocs('alert:test.always-firing', reference, 2); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/mute_all.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/mute_all.ts index 81a634a8a09e0..9e479064e66c7 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/mute_all.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/mute_all.ts @@ -32,7 +32,7 @@ export default function createMuteAlertTests({ getService }: FtrProviderContext) .expect(200); objectRemover.add(space.id, createdAlert.id, 'alert'); - const response = await alertUtils.getMuteRequest(createdAlert.id); + const response = await alertUtils.getMuteAllRequest(createdAlert.id); switch (scenario.id) { case 'no_kibana_privileges at space1': diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/unmute_all.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/unmute_all.ts index 4f4f5b63af2f8..5e9ad66cf40f3 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/unmute_all.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/unmute_all.ts @@ -37,7 +37,7 @@ export default function createUnmuteAlertTests({ getService }: FtrProviderContex .set('kbn-xsrf', 'foo') .expect(204, ''); - const response = await alertUtils.getUnmuteRequest(createdAlert.id); + const response = await alertUtils.getUnmuteAllRequest(createdAlert.id); switch (scenario.id) { case 'no_kibana_privileges at space1': diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/mute_all.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/mute_all.ts index c500c829c51c8..dba3046aa4b7f 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/mute_all.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/mute_all.ts @@ -27,7 +27,7 @@ export default function createMuteTests({ getService }: FtrProviderContext) { .expect(200); objectRemover.add(Spaces.space1.id, createdAlert.id, 'alert'); - await alertUtils.mute(createdAlert.id); + await alertUtils.muteAll(createdAlert.id); const { body: updatedAlert } = await supertestWithoutAuth .get(`${getUrlPrefix(Spaces.space1.id)}/api/alert/${createdAlert.id}`) diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/unmute_all.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/unmute_all.ts index 739861d856dd0..70ee32a9e6fb9 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/unmute_all.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/unmute_all.ts @@ -27,8 +27,8 @@ export default function createUnmuteTests({ getService }: FtrProviderContext) { .expect(200); objectRemover.add(Spaces.space1.id, createdAlert.id, 'alert'); - await alertUtils.mute(createdAlert.id); - await alertUtils.unmute(createdAlert.id); + await alertUtils.muteAll(createdAlert.id); + await alertUtils.unmuteAll(createdAlert.id); const { body: updatedAlert } = await supertestWithoutAuth .get(`${getUrlPrefix(Spaces.space1.id)}/api/alert/${createdAlert.id}`) From 522eaa902343b61e991406d35b26cd668cd0bc0b Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Fri, 27 Sep 2019 13:38:35 -0400 Subject: [PATCH 24/26] Rename variable in task runner --- .../alerting/server/lib/get_create_task_runner_function.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/legacy/plugins/alerting/server/lib/get_create_task_runner_function.ts b/x-pack/legacy/plugins/alerting/server/lib/get_create_task_runner_function.ts index c856403765024..3f186f04f1691 100644 --- a/x-pack/legacy/plugins/alerting/server/lib/get_create_task_runner_function.ts +++ b/x-pack/legacy/plugins/alerting/server/lib/get_create_task_runner_function.ts @@ -74,7 +74,7 @@ export function getCreateTaskRunnerFunction({ const services = getServices(fakeRequest); // Ensure API key is still valid and user has access const { - attributes: { alertTypeParams, actions, interval, throttle, muted, mutedInstanceIds }, + attributes: { alertTypeParams, actions, interval, throttle, muteAll, mutedInstanceIds }, references, } = await services.savedObjectsClient.get('alert', alertId); @@ -128,7 +128,7 @@ export function getCreateTaskRunnerFunction({ Object.keys(alertInstances).map(alertInstanceId => { const alertInstance = alertInstances[alertInstanceId]; if (alertInstance.hasScheduledActions(throttle)) { - if (muted || mutedInstanceIds.includes(alertInstanceId)) { + if (muteAll || mutedInstanceIds.includes(alertInstanceId)) { return; } const { actionGroup, context, state } = alertInstance.getSechduledActionOptions()!; From b97f1ce0417f3e77dff9385115c6be326aa73cb6 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Fri, 27 Sep 2019 14:11:58 -0400 Subject: [PATCH 25/26] Cleanup --- x-pack/legacy/plugins/alerting/server/alerts_client.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/legacy/plugins/alerting/server/alerts_client.test.ts b/x-pack/legacy/plugins/alerting/server/alerts_client.test.ts index ec18f67c6dd22..bba0051e31e08 100644 --- a/x-pack/legacy/plugins/alerting/server/alerts_client.test.ts +++ b/x-pack/legacy/plugins/alerting/server/alerts_client.test.ts @@ -737,7 +737,7 @@ describe('disable()', () => { }); }); -describe('mute()', () => { +describe('muteAll()', () => { test('mutes an alert', async () => { const alertsClient = new AlertsClient(alertsClientParams); savedObjectsClient.get.mockResolvedValueOnce({ @@ -774,7 +774,7 @@ describe('mute()', () => { }); }); -describe('unmute()', () => { +describe('unmuteAll()', () => { test('unmutes an alert', async () => { const alertsClient = new AlertsClient(alertsClientParams); savedObjectsClient.get.mockResolvedValueOnce({ From 730acf2b53b523873129e9c97f3ba5dfcd5a5bf1 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Mon, 30 Sep 2019 11:06:39 -0400 Subject: [PATCH 26/26] Destructure instead of using existingObject variable --- .../plugins/alerting/server/alerts_client.ts | 63 +++++++++---------- 1 file changed, 31 insertions(+), 32 deletions(-) diff --git a/x-pack/legacy/plugins/alerting/server/alerts_client.ts b/x-pack/legacy/plugins/alerting/server/alerts_client.ts index 2c671b52c261f..10f87dbd6024a 100644 --- a/x-pack/legacy/plugins/alerting/server/alerts_client.ts +++ b/x-pack/legacy/plugins/alerting/server/alerts_client.ts @@ -196,9 +196,8 @@ export class AlertsClient { } public async update({ id, data }: UpdateOptions) { - const existingObject = await this.savedObjectsClient.get('alert', id); - const { alertTypeId } = existingObject.attributes; - const alertType = this.alertTypeRegistry.get(alertTypeId); + const { attributes, version } = await this.savedObjectsClient.get('alert', id); + const alertType = this.alertTypeRegistry.get(attributes.alertTypeId); const apiKey = await this.createAPIKey(); // Validate @@ -211,7 +210,7 @@ export class AlertsClient { 'alert', id, { - ...existingObject.attributes, + ...attributes, ...data, alertTypeParams: validatedAlertTypeParams, actions, @@ -222,15 +221,15 @@ export class AlertsClient { : null, }, { + version, references, - version: existingObject.version, } ); return this.getAlertFromRaw(id, updatedObject.attributes, updatedObject.references); } public async updateApiKey({ id }: { id: string }) { - const existingObject = await this.savedObjectsClient.get('alert', id); + const { references, version, attributes } = await this.savedObjectsClient.get('alert', id); const apiKey = await this.createAPIKey(); const username = await this.getUserName(); @@ -238,7 +237,7 @@ export class AlertsClient { 'alert', id, { - ...existingObject.attributes, + ...attributes, updatedBy: username, apiKeyOwner: apiKey.created ? username : null, apiKey: apiKey.created @@ -246,27 +245,27 @@ export class AlertsClient { : null, }, { - version: existingObject.version, - references: existingObject.references, + version, + references, } ); } public async enable({ id }: { id: string }) { - const existingObject = await this.savedObjectsClient.get('alert', id); - if (existingObject.attributes.enabled === false) { + const { attributes, version, references } = await this.savedObjectsClient.get('alert', id); + if (attributes.enabled === false) { const apiKey = await this.createAPIKey(); const scheduledTask = await this.scheduleAlert( id, - existingObject.attributes.alertTypeId, - existingObject.attributes.interval + attributes.alertTypeId, + attributes.interval ); const username = await this.getUserName(); await this.savedObjectsClient.update( 'alert', id, { - ...existingObject.attributes, + ...attributes, enabled: true, updatedBy: username, apiKeyOwner: apiKey.created ? username : null, @@ -276,21 +275,21 @@ export class AlertsClient { : null, }, { - version: existingObject.version, - references: existingObject.references, + version, + references, } ); } } public async disable({ id }: { id: string }) { - const existingObject = await this.savedObjectsClient.get('alert', id); - if (existingObject.attributes.enabled === true) { + const { attributes, version, references } = await this.savedObjectsClient.get('alert', id); + if (attributes.enabled === true) { await this.savedObjectsClient.update( 'alert', id, { - ...existingObject.attributes, + ...attributes, enabled: false, scheduledTaskId: null, apiKey: null, @@ -298,11 +297,11 @@ export class AlertsClient { updatedBy: await this.getUserName(), }, { - version: existingObject.version, - references: existingObject.references, + version, + references, } ); - await this.taskManager.remove(existingObject.attributes.scheduledTaskId); + await this.taskManager.remove(attributes.scheduledTaskId); } } @@ -351,9 +350,9 @@ export class AlertsClient { alertId: string; alertInstanceId: string; }) { - const existingObject = await this.savedObjectsClient.get('alert', alertId); - const mutedInstanceIds = existingObject.attributes.mutedInstanceIds || []; - if (!existingObject.attributes.muteAll && !mutedInstanceIds.includes(alertInstanceId)) { + const { attributes, version, references } = await this.savedObjectsClient.get('alert', alertId); + const mutedInstanceIds = attributes.mutedInstanceIds || []; + if (!attributes.muteAll && !mutedInstanceIds.includes(alertInstanceId)) { mutedInstanceIds.push(alertInstanceId); await this.savedObjectsClient.update( 'alert', @@ -363,8 +362,8 @@ export class AlertsClient { updatedBy: await this.getUserName(), }, { - version: existingObject.version, - references: existingObject.references, + version, + references, } ); } @@ -377,9 +376,9 @@ export class AlertsClient { alertId: string; alertInstanceId: string; }) { - const existingObject = await this.savedObjectsClient.get('alert', alertId); - const mutedInstanceIds = existingObject.attributes.mutedInstanceIds || []; - if (!existingObject.attributes.muteAll && mutedInstanceIds.includes(alertInstanceId)) { + const { attributes, version, references } = await this.savedObjectsClient.get('alert', alertId); + const mutedInstanceIds = attributes.mutedInstanceIds || []; + if (!attributes.muteAll && mutedInstanceIds.includes(alertInstanceId)) { await this.savedObjectsClient.update( 'alert', alertId, @@ -388,8 +387,8 @@ export class AlertsClient { mutedInstanceIds: mutedInstanceIds.filter((id: string) => id !== alertInstanceId), }, { - version: existingObject.version, - references: existingObject.references, + version, + references, } ); }