Add spaces only tests for alerting and actions (#43616) (#43702)

* Add spaces only tests

* Rename some tests to make more sense in spaces only context

* Modify test suite titles

* Apply changes from master

* Loop only one scenario for now

* Reduce amount of tests spaces_only runs

* Fix failing test

* Remove looping in spaces only tests
This commit is contained in:
Mike Côté 2019-08-21 15:57:23 -04:00 committed by GitHub
parent 1a45a65e7f
commit 4540c55916
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 1494 additions and 1 deletions

View file

@ -12,6 +12,7 @@ require('@kbn/test').runTestsCli([
require.resolve('../test/functional/config.js'),
require.resolve('../test/api_integration/config_security_basic.js'),
require.resolve('../test/api_integration/config.js'),
require.resolve('../test/alerting_api_integration/spaces_only/config.ts'),
require.resolve('../test/alerting_api_integration/security_and_spaces/config.ts'),
require.resolve('../test/plugin_api_integration/config.js'),
require.resolve('../test/kerberos_api_integration/config'),

View file

@ -18,7 +18,7 @@ export default function alertingApiIntegrationTests({
const spacesService: SpacesService = getService('spaces');
const esArchiver = getService('esArchiver');
describe('alerting api integration', function() {
describe('alerting api integration security and spaces enabled', function() {
this.tags('ciGroup8');
before(async () => {

View file

@ -0,0 +1,10 @@
/*
* 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 { createTestConfig } from '../common/config';
// eslint-disable-next-line import/no-default-export
export default createTestConfig('spaces_only', { disabledPlugins: ['security'], license: 'basic' });

View file

@ -0,0 +1,17 @@
/*
* 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 } from '../common/types';
const Space1: Space = {
id: 'space1',
name: 'Space 1',
disabledFeatures: [],
};
export const Spaces = {
space1: Space1,
};

View file

@ -0,0 +1,133 @@
/*
* 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 { FtrProviderContext } from '../../../../common/ftr_provider_context';
const ES_TEST_INDEX_NAME = 'functional-test-actions-index';
// eslint-disable-next-line import/no-default-export
export default function indexTest({ getService }: FtrProviderContext) {
const es = getService('es');
const supertest = getService('supertest');
const esArchiver = getService('esArchiver');
describe('index action', () => {
after(() => esArchiver.unload('empty_kibana'));
beforeEach(() => clearTestIndex(es));
let createdActionID: string;
let createdActionIDWithIndex: string;
it('should be created successfully', async () => {
// create action with no config
const { body: createdAction } = await supertest
.post('/api/action')
.set('kbn-xsrf', 'foo')
.send({
description: 'An index action',
actionTypeId: '.index',
config: {},
secrets: {},
})
.expect(200);
expect(createdAction).to.eql({
id: createdAction.id,
description: 'An index action',
actionTypeId: '.index',
config: {
index: null,
},
});
createdActionID = createdAction.id;
expect(typeof createdActionID).to.be('string');
const { body: fetchedAction } = await supertest
.get(`/api/action/${createdActionID}`)
.expect(200);
expect(fetchedAction).to.eql({
id: fetchedAction.id,
description: 'An index action',
actionTypeId: '.index',
config: { index: null },
});
// create action with index config
const { body: createdActionWithIndex } = await supertest
.post('/api/action')
.set('kbn-xsrf', 'foo')
.send({
description: 'An index action with index config',
actionTypeId: '.index',
config: {
index: ES_TEST_INDEX_NAME,
},
})
.expect(200);
expect(createdActionWithIndex).to.eql({
id: createdActionWithIndex.id,
description: 'An index action with index config',
actionTypeId: '.index',
config: {
index: ES_TEST_INDEX_NAME,
},
});
createdActionIDWithIndex = createdActionWithIndex.id;
expect(typeof createdActionIDWithIndex).to.be('string');
const { body: fetchedActionWithIndex } = await supertest
.get(`/api/action/${createdActionIDWithIndex}`)
.expect(200);
expect(fetchedActionWithIndex).to.eql({
id: fetchedActionWithIndex.id,
description: 'An index action with index config',
actionTypeId: '.index',
config: {
index: ES_TEST_INDEX_NAME,
},
});
});
it('should execute successly when expected for a single body', async () => {
const { body: result } = await supertest
.post(`/api/action/${createdActionID}/_execute`)
.set('kbn-xsrf', 'foo')
.send({
params: {
index: ES_TEST_INDEX_NAME,
documents: [{ testing: [1, 2, 3] }],
refresh: true,
},
})
.expect(200);
expect(result.status).to.eql('ok');
const items = await getTestIndexItems(es);
expect(items.length).to.eql(1);
expect(items[0]._source).to.eql({ testing: [1, 2, 3] });
});
});
}
async function clearTestIndex(es: any) {
return await es.indices.delete({
index: ES_TEST_INDEX_NAME,
ignoreUnavailable: true,
});
}
async function getTestIndexItems(es: any) {
const result = await es.search({
index: ES_TEST_INDEX_NAME,
});
return result.hits.hits;
}

View file

@ -0,0 +1,49 @@
/*
* 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, ObjectRemover } from '../../../common/lib';
import { FtrProviderContext } from '../../../common/ftr_provider_context';
// eslint-disable-next-line import/no-default-export
export default function createActionTests({ getService }: FtrProviderContext) {
const supertest = getService('supertest');
describe('create', () => {
const objectRemover = new ObjectRemover(supertest);
after(() => objectRemover.removeAll());
it('should handle create action request appropriately', async () => {
const response = await supertest
.post(`${getUrlPrefix(Spaces.space1.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(response.statusCode).to.eql(200);
expect(response.body).to.eql({
id: response.body.id,
description: 'My action',
actionTypeId: 'test.index-record',
config: {
unencrypted: `This value shouldn't get encrypted`,
},
});
expect(typeof response.body.id).to.be('string');
objectRemover.add(Spaces.space1.id, response.body.id, 'action');
});
});
}

View file

@ -0,0 +1,53 @@
/*
* 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 { Spaces } 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 deleteActionTests({ getService }: FtrProviderContext) {
const supertest = getService('supertest');
describe('delete', () => {
const objectRemover = new ObjectRemover(supertest);
after(() => objectRemover.removeAll());
it('should handle delete action request appropriately', async () => {
const { body: createdAction } = await supertest
.post(`${getUrlPrefix(Spaces.space1.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);
await supertest
.delete(`${getUrlPrefix(Spaces.space1.id)}/api/action/${createdAction.id}`)
.set('kbn-xsrf', 'foo')
.expect(204, '');
});
it(`should handle delete request appropriately when action doesn't exist`, async () => {
await supertest
.delete(`${getUrlPrefix(Spaces.space1.id)}/api/action/2`)
.set('kbn-xsrf', 'foo')
.expect(404, {
statusCode: 404,
error: 'Not Found',
message: 'Saved object [action/2] not found',
});
});
});
}

View file

@ -0,0 +1,175 @@
/*
* 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, ObjectRemover } from '../../../common/lib';
import { FtrProviderContext } from '../../../common/ftr_provider_context';
// eslint-disable-next-line import/no-default-export
export default function({ getService }: FtrProviderContext) {
const supertest = getService('supertest');
const es = getService('es');
const esTestIndexName = '.kibaka-alerting-test-data';
const authorizationIndex = '.kibana-test-authorization';
describe('execute', () => {
const objectRemover = new ObjectRemover(supertest);
before(async () => {
await es.indices.delete({ index: esTestIndexName, ignore: [404] });
await es.indices.create({
index: esTestIndexName,
body: {
mappings: {
properties: {
source: {
type: 'keyword',
},
reference: {
type: 'keyword',
},
params: {
enabled: false,
type: 'object',
},
config: {
enabled: false,
type: 'object',
},
state: {
enabled: false,
type: 'object',
},
},
},
},
});
await es.indices.create({ index: authorizationIndex });
});
after(async () => {
await es.indices.delete({ index: esTestIndexName });
await es.indices.delete({ index: authorizationIndex });
await objectRemover.removeAll();
});
async function getTestIndexDoc(source: string, reference: string) {
const searchResult = await es.search({
index: esTestIndexName,
body: {
query: {
bool: {
must: [
{
term: {
source,
},
},
{
term: {
reference,
},
},
],
},
},
},
});
expect(searchResult.hits.total.value).to.eql(1);
return searchResult.hits.hits[0];
}
it('should handle execute request appropriately', async () => {
const { body: createdAction } = await supertest
.post(`${getUrlPrefix(Spaces.space1.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(Spaces.space1.id, createdAction.id, 'action');
const reference = `actions-execute-1:${Spaces.space1.id}`;
const response = await supertest
.post(`${getUrlPrefix(Spaces.space1.id)}/api/action/${createdAction.id}/_execute`)
.set('kbn-xsrf', 'foo')
.send({
params: {
reference,
index: esTestIndexName,
message: 'Testing 123',
},
});
expect(response.statusCode).to.eql(200);
expect(response.body).to.be.an('object');
const indexedRecord = await getTestIndexDoc('action:test.index-record', reference);
expect(indexedRecord._source).to.eql({
params: {
reference,
index: esTestIndexName,
message: 'Testing 123',
},
config: {
unencrypted: `This value shouldn't get encrypted`,
},
secrets: {
encrypted: 'This value should be encrypted',
},
reference,
source: 'action:test.index-record',
});
});
it('should handle execute request appropriately and have proper callCluster and savedObjectsClient authorization', async () => {
const reference = `actions-execute-3:${Spaces.space1.id}`;
const { body: createdAction } = await supertest
.post(`${getUrlPrefix(Spaces.space1.id)}/api/action`)
.set('kbn-xsrf', 'foo')
.send({
description: 'My action',
actionTypeId: 'test.authorization',
})
.expect(200);
objectRemover.add(Spaces.space1.id, createdAction.id, 'action');
const response = await supertest
.post(`${getUrlPrefix(Spaces.space1.id)}/api/action/${createdAction.id}/_execute`)
.set('kbn-xsrf', 'foo')
.send({
params: {
callClusterAuthorizationIndex: authorizationIndex,
savedObjectsClientType: 'dashboard',
savedObjectsClientId: '1',
index: esTestIndexName,
reference,
},
});
expect(response.statusCode).to.eql(200);
const indexedRecord = await getTestIndexDoc('action:test.authorization', reference);
expect(indexedRecord._source.state).to.eql({
callClusterSuccess: true,
savedObjectsClientSuccess: false,
savedObjectsClientError: {
...indexedRecord._source.state.savedObjectsClientError,
output: {
...indexedRecord._source.state.savedObjectsClientError.output,
statusCode: 404,
},
},
});
});
});
}

View file

@ -0,0 +1,60 @@
/*
* 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 { Spaces } 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 findActionTests({ getService }: FtrProviderContext) {
const supertest = getService('supertest');
describe('find', () => {
const objectRemover = new ObjectRemover(supertest);
afterEach(() => objectRemover.removeAll());
it('should handle find action request appropriately', async () => {
const { body: createdAction } = await supertest
.post(`${getUrlPrefix(Spaces.space1.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(Spaces.space1.id, createdAction.id, 'action');
await supertest
.get(
`${getUrlPrefix(
Spaces.space1.id
)}/api/action/_find?search=test.index-record&search_fields=actionTypeId`
)
.expect(200, {
page: 1,
perPage: 20,
total: 1,
data: [
{
id: createdAction.id,
description: 'My action',
actionTypeId: 'test.index-record',
config: {
unencrypted: `This value shouldn't get encrypted`,
},
},
],
});
});
});
}

View file

@ -0,0 +1,49 @@
/*
* 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 { Spaces } 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 getActionTests({ getService }: FtrProviderContext) {
const supertest = getService('supertest');
describe('get', () => {
const objectRemover = new ObjectRemover(supertest);
afterEach(() => objectRemover.removeAll());
it('should handle get action request appropriately', async () => {
const { body: createdAction } = await supertest
.post(`${getUrlPrefix(Spaces.space1.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(Spaces.space1.id, createdAction.id, 'action');
await supertest
.get(`${getUrlPrefix(Spaces.space1.id)}/api/action/${createdAction.id}`)
.expect(200, {
id: createdAction.id,
actionTypeId: 'test.index-record',
description: 'My action',
config: {
unencrypted: `This value shouldn't get encrypted`,
},
});
});
});
}

View file

@ -0,0 +1,21 @@
/*
* 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 { FtrProviderContext } from '../../../common/ftr_provider_context';
// eslint-disable-next-line import/no-default-export
export default function actionsTests({ loadTestFile }: FtrProviderContext) {
describe('Actions', () => {
loadTestFile(require.resolve('./create'));
loadTestFile(require.resolve('./delete'));
loadTestFile(require.resolve('./find'));
loadTestFile(require.resolve('./get'));
loadTestFile(require.resolve('./list_action_types'));
loadTestFile(require.resolve('./update'));
loadTestFile(require.resolve('./execute'));
loadTestFile(require.resolve('./builtin_action_types/es_index'));
});
}

View file

@ -0,0 +1,34 @@
/*
* 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 } from '../../../common/lib/space_test_utils';
import { FtrProviderContext } from '../../../common/ftr_provider_context';
// eslint-disable-next-line import/no-default-export
export default function listActionTypesTests({ getService }: FtrProviderContext) {
const supertest = getService('supertest');
describe('list_action_types', () => {
it('should return 200 with list of action types containing defaults', async () => {
const response = await supertest.get(`${getUrlPrefix(Spaces.space1.id)}/api/action/types`);
function createActionTypeMatcher(id: string, name: string) {
return (actionType: { id: string; name: string }) => {
return actionType.id === id && actionType.name === name;
};
}
expect(response.statusCode).to.eql(200);
// Check for values explicitly in order to avoid this test failing each time plugins register
// a new action type
expect(
response.body.some(createActionTypeMatcher('test.index-record', 'Test: Index Record'))
).to.be(true);
});
});
}

View file

@ -0,0 +1,59 @@
/*
* 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 { Spaces } 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 updateActionTests({ getService }: FtrProviderContext) {
const supertest = getService('supertest');
describe('update', () => {
const objectRemover = new ObjectRemover(supertest);
after(() => objectRemover.removeAll());
it('should handle update action request appropriately', async () => {
const { body: createdAction } = await supertest
.post(`${getUrlPrefix(Spaces.space1.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(Spaces.space1.id, createdAction.id, 'action');
await supertest
.put(`${getUrlPrefix(Spaces.space1.id)}/api/action/${createdAction.id}`)
.set('kbn-xsrf', 'foo')
.send({
description: 'My action updated',
config: {
unencrypted: `This value shouldn't get encrypted`,
},
secrets: {
encrypted: 'This value should be encrypted',
},
})
.expect(200, {
id: createdAction.id,
actionTypeId: 'test.index-record',
description: 'My action updated',
config: {
unencrypted: `This value shouldn't get encrypted`,
},
});
});
});
}

View file

@ -0,0 +1,309 @@
/*
* 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, ObjectRemover } from '../../../common/lib';
import { getTestAlertData, setupEsTestIndex, destroyEsTestIndex } from './utils';
import { FtrProviderContext } from '../../../common/ftr_provider_context';
// eslint-disable-next-line import/no-default-export
export default function alertTests({ getService }: FtrProviderContext) {
const supertest = getService('supertest');
const es = getService('es');
const retry = getService('retry');
describe('alerts', () => {
let esTestIndexName: string;
const authorizationIndex = '.kibana-test-authorization';
const objectRemover = new ObjectRemover(supertest);
before(async () => {
await destroyEsTestIndex(es);
({ name: esTestIndexName } = await setupEsTestIndex(es));
await es.indices.create({ index: authorizationIndex });
});
afterEach(() => objectRemover.removeAll());
after(async () => {
await destroyEsTestIndex(es);
await es.indices.delete({ index: authorizationIndex });
});
async function waitForTestIndexDoc(source: string, reference: string) {
return await retry.try(async () => {
const searchResult = await es.search({
index: esTestIndexName,
body: {
query: {
bool: {
must: [
{
term: {
source,
},
},
{
term: {
reference,
},
},
],
},
},
},
});
expect(searchResult.hits.total.value).to.eql(1);
return searchResult.hits.hits[0];
});
}
it('should schedule task, run alert and fire actions', async () => {
const reference = `create-test-1:${Spaces.space1.id}`;
const { body: createdAction } = await supertest
.post(`${getUrlPrefix(Spaces.space1.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(Spaces.space1.id, createdAction.id, 'action');
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: esTestIndexName,
reference,
},
actions: [
{
group: 'default',
id: createdAction.id,
params: {
index: esTestIndexName,
reference,
message:
'instanceContextValue: {{context.instanceContextValue}}, instanceStateValue: {{state.instanceStateValue}}',
},
},
],
})
);
expect(response.statusCode).to.eql(200);
objectRemover.add(Spaces.space1.id, response.body.id, 'alert');
const alertTestRecord = await waitForTestIndexDoc('alert:test.always-firing', reference);
expect(alertTestRecord._source).to.eql({
source: 'alert:test.always-firing',
reference,
state: {},
params: {
index: esTestIndexName,
reference,
},
});
const actionTestRecord = await waitForTestIndexDoc('action:test.index-record', reference);
expect(actionTestRecord._source).to.eql({
config: {
unencrypted: `This value shouldn't get encrypted`,
},
secrets: {
encrypted: 'This value should be encrypted',
},
params: {
index: esTestIndexName,
reference,
message: 'instanceContextValue: true, instanceStateValue: true',
},
reference,
source: 'action:test.index-record',
});
});
it('should handle custom retry logic', async () => {
// We'll use this start time to query tasks created after this point
const testStart = new Date();
// 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
.post(`${getUrlPrefix(Spaces.space1.id)}/api/action`)
.set('kbn-xsrf', 'foo')
.send({
description: 'Test rate limit',
actionTypeId: 'test.rate-limit',
config: {},
})
.expect(200);
objectRemover.add(Spaces.space1.id, createdAction.id, 'action');
const reference = `create-test-2:${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: esTestIndexName,
reference: 'create-test-2',
},
actions: [
{
group: 'default',
id: createdAction.id,
params: {
reference,
index: esTestIndexName,
retryAt: retryDate.getTime(),
},
},
],
})
);
expect(response.statusCode).to.eql(200);
objectRemover.add(Spaces.space1.id, response.body.id, 'alert');
const scheduledActionTask = await retry.try(async () => {
const searchResult = await es.search({
index: '.kibana_task_manager',
body: {
query: {
bool: {
must: [
{
term: {
'task.status': 'idle',
},
},
{
term: {
'task.attempts': 1,
},
},
{
term: {
'task.taskType': 'actions:test.rate-limit',
},
},
{
range: {
'task.scheduledAt': {
gte: testStart,
},
},
},
],
},
},
},
});
expect(searchResult.hits.total.value).to.eql(1);
return searchResult.hits.hits[0];
});
expect(scheduledActionTask._source.task.runAt).to.eql(retryDate.toISOString());
});
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
.post(`${getUrlPrefix(Spaces.space1.id)}/api/alert`)
.set('kbn-xsrf', 'foo')
.send(
getTestAlertData({
alertTypeId: 'test.authorization',
alertTypeParams: {
callClusterAuthorizationIndex: authorizationIndex,
savedObjectsClientType: 'dashboard',
savedObjectsClientId: '1',
index: esTestIndexName,
reference,
},
})
);
expect(response.statusCode).to.eql(200);
objectRemover.add(Spaces.space1.id, response.body.id, 'alert');
const alertTestRecord = await waitForTestIndexDoc('alert:test.authorization', reference);
expect(alertTestRecord._source.state).to.eql({
callClusterSuccess: true,
savedObjectsClientSuccess: false,
savedObjectsClientError: {
...alertTestRecord._source.state.savedObjectsClientError,
output: {
...alertTestRecord._source.state.savedObjectsClientError.output,
statusCode: 404,
},
},
});
});
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
.post(`${getUrlPrefix(Spaces.space1.id)}/api/action`)
.set('kbn-xsrf', 'foo')
.send({
description: 'My action',
actionTypeId: 'test.authorization',
})
.expect(200);
objectRemover.add(Spaces.space1.id, createdAction.id, 'action');
const response = await supertest
.post(`${getUrlPrefix(Spaces.space1.id)}/api/alert`)
.set('kbn-xsrf', 'foo')
.send(
getTestAlertData({
alertTypeId: 'test.always-firing',
alertTypeParams: {
index: esTestIndexName,
reference,
},
actions: [
{
group: 'default',
id: createdAction.id,
params: {
callClusterAuthorizationIndex: authorizationIndex,
savedObjectsClientType: 'dashboard',
savedObjectsClientId: '1',
index: esTestIndexName,
reference,
},
},
],
})
);
expect(response.statusCode).to.eql(200);
objectRemover.add(Spaces.space1.id, response.body.id, 'alert');
const actionTestRecord = await waitForTestIndexDoc('action:test.authorization', reference);
expect(actionTestRecord._source.state).to.eql({
callClusterSuccess: true,
savedObjectsClientSuccess: false,
savedObjectsClientError: {
...actionTestRecord._source.state.savedObjectsClientError,
output: {
...actionTestRecord._source.state.savedObjectsClientError.output,
statusCode: 404,
},
},
});
});
});
}

View file

@ -0,0 +1,70 @@
/*
* 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 { Spaces } 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 createAlertTests({ getService }: FtrProviderContext) {
const supertest = getService('supertest');
const es = getService('es');
describe('create', () => {
const objectRemover = new ObjectRemover(supertest);
after(() => objectRemover.removeAll());
async function getScheduledTask(id: string) {
return await es.get({
id: `task:${id}`,
index: '.kibana_task_manager',
});
}
it('should handle create alert request appropriately', async () => {
const response = await supertest
.post(`${getUrlPrefix(Spaces.space1.id)}/api/alert`)
.set('kbn-xsrf', 'foo')
.send(getTestAlertData());
expect(response.statusCode).to.eql(200);
objectRemover.add(Spaces.space1.id, response.body.id, 'alert');
expect(response.body).to.eql({
id: response.body.id,
actions: [],
enabled: true,
alertTypeId: 'test.noop',
alertTypeParams: {},
createdBy: null,
interval: '10s',
scheduledTaskId: response.body.scheduledTaskId,
updatedBy: null,
});
expect(typeof response.body.scheduledTaskId).to.be('string');
const { _source: taskRecord } = await getScheduledTask(response.body.scheduledTaskId);
expect(taskRecord.type).to.eql('task');
expect(taskRecord.task.taskType).to.eql('alerting:test.noop');
expect(JSON.parse(taskRecord.task.params)).to.eql({
alertId: response.body.id,
spaceId: Spaces.space1.id,
});
});
it('should handle create alert request appropriately when an alert is disabled ', async () => {
const response = await supertest
.post(`${getUrlPrefix(Spaces.space1.id)}/api/alert`)
.set('kbn-xsrf', 'foo')
.send(getTestAlertData({ enabled: false }));
expect(response.statusCode).to.eql(200);
objectRemover.add(Spaces.space1.id, response.body.id, 'alert');
expect(response.body.scheduledTaskId).to.eql(undefined);
});
});
}

View file

@ -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 { getTestAlertData } from './utils';
import { Spaces } 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 createDeleteTests({ getService }: FtrProviderContext) {
const supertest = getService('supertest');
const es = getService('es');
describe('delete', () => {
const objectRemover = new ObjectRemover(supertest);
after(() => objectRemover.removeAll());
async function getScheduledTask(id: string) {
return await es.get({
id: `task:${id}`,
index: '.kibana_task_manager',
});
}
it('should handle delete alert request appropriately', async () => {
const { body: createdAlert } = await supertest
.post(`${getUrlPrefix(Spaces.space1.id)}/api/alert`)
.set('kbn-xsrf', 'foo')
.send(getTestAlertData())
.expect(200);
await supertest
.delete(`${getUrlPrefix(Spaces.space1.id)}/api/alert/${createdAlert.id}`)
.set('kbn-xsrf', 'foo')
.expect(204, '');
try {
await getScheduledTask(createdAlert.scheduledTaskId);
throw new Error('Should have removed scheduled task');
} catch (e) {
expect(e.status).to.eql(404);
}
});
});
}

View file

@ -0,0 +1,51 @@
/*
* 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 { Spaces } 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 createDisableAlertTests({ getService }: FtrProviderContext) {
const es = getService('es');
const supertest = getService('supertest');
describe('disable', () => {
const objectRemover = new ObjectRemover(supertest);
after(() => objectRemover.removeAll());
async function getScheduledTask(id: string) {
return await es.get({
id: `task:${id}`,
index: '.kibana_task_manager',
});
}
it('should handle disable alert request appropriately', async () => {
const { body: createdAlert } = await supertest
.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, '');
try {
await getScheduledTask(createdAlert.scheduledTaskId);
throw new Error('Should have removed scheduled task');
} catch (e) {
expect(e.status).to.eql(404);
}
});
});
}

View file

@ -0,0 +1,57 @@
/*
* 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 { Spaces } 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 createEnableAlertTests({ getService }: FtrProviderContext) {
const es = getService('es');
const supertest = getService('supertest');
describe('enable', () => {
const objectRemover = new ObjectRemover(supertest);
after(() => objectRemover.removeAll());
async function getScheduledTask(id: string) {
return await es.get({
id: `task:${id}`,
index: '.kibana_task_manager',
});
}
it('should handle enable 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}/_enable`)
.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(typeof updatedAlert.scheduledTaskId).to.eql('string');
const { _source: taskRecord } = await getScheduledTask(updatedAlert.scheduledTaskId);
expect(taskRecord.type).to.eql('task');
expect(taskRecord.task.taskType).to.eql('alerting:test.noop');
expect(JSON.parse(taskRecord.task.params)).to.eql({
alertId: createdAlert.id,
spaceId: Spaces.space1.id,
});
});
});
}

View file

@ -0,0 +1,54 @@
/*
* 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 { Spaces } 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 createFindTests({ getService }: FtrProviderContext) {
const supertest = getService('supertest');
describe('find', () => {
const objectRemover = new ObjectRemover(supertest);
afterEach(() => objectRemover.removeAll());
it('should handle find alert request appropriately', async () => {
const { body: createdAlert } = await supertest
.post(`${getUrlPrefix(Spaces.space1.id)}/api/alert`)
.set('kbn-xsrf', 'foo')
.send(getTestAlertData())
.expect(200);
objectRemover.add(Spaces.space1.id, createdAlert.id, 'alert');
const response = await supertest.get(
`${getUrlPrefix(
Spaces.space1.id
)}/api/alert/_find?search=test.noop&search_fields=alertTypeId`
);
expect(response.statusCode).to.eql(200);
expect(response.body.page).to.equal(1);
expect(response.body.perPage).to.be.greaterThan(0);
expect(response.body.total).to.be.greaterThan(0);
const match = response.body.data.find((obj: any) => obj.id === createdAlert.id);
expect(match).to.eql({
id: createdAlert.id,
alertTypeId: 'test.noop',
interval: '10s',
enabled: true,
actions: [],
alertTypeParams: {},
createdBy: null,
scheduledTaskId: match.scheduledTaskId,
updatedBy: null,
});
});
});
}

View file

@ -0,0 +1,56 @@
/*
* 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 { Spaces } 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 createGetTests({ getService }: FtrProviderContext) {
const supertest = getService('supertest');
describe('get', () => {
const objectRemover = new ObjectRemover(supertest);
afterEach(() => objectRemover.removeAll());
it('should handle get alert request appropriately', async () => {
const { body: createdAlert } = await supertest
.post(`${getUrlPrefix(Spaces.space1.id)}/api/alert`)
.set('kbn-xsrf', 'foo')
.send(getTestAlertData())
.expect(200);
objectRemover.add(Spaces.space1.id, createdAlert.id, 'alert');
const response = await supertest.get(
`${getUrlPrefix(Spaces.space1.id)}/api/alert/${createdAlert.id}`
);
expect(response.statusCode).to.eql(200);
expect(response.body).to.eql({
id: createdAlert.id,
alertTypeId: 'test.noop',
interval: '10s',
enabled: true,
actions: [],
alertTypeParams: {},
createdBy: null,
scheduledTaskId: response.body.scheduledTaskId,
updatedBy: null,
});
});
it(`should handle get alert request appropriately when alert doesn't exist`, async () => {
await supertest.get(`${getUrlPrefix(Spaces.space1.id)}/api/alert/1`).expect(404, {
statusCode: 404,
error: 'Not Found',
message: 'Saved object [alert/1] not found',
});
});
});
}

View file

@ -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 { FtrProviderContext } from '../../../common/ftr_provider_context';
// eslint-disable-next-line import/no-default-export
export default function alertingTests({ loadTestFile }: FtrProviderContext) {
describe('Alerting', () => {
loadTestFile(require.resolve('./create'));
loadTestFile(require.resolve('./delete'));
loadTestFile(require.resolve('./disable'));
loadTestFile(require.resolve('./enable'));
loadTestFile(require.resolve('./find'));
loadTestFile(require.resolve('./get'));
loadTestFile(require.resolve('./list_alert_types'));
loadTestFile(require.resolve('./update'));
loadTestFile(require.resolve('./alerts'));
});
}

View file

@ -0,0 +1,28 @@
/*
* 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 } from '../../../common/lib/space_test_utils';
import { FtrProviderContext } from '../../../common/ftr_provider_context';
// eslint-disable-next-line import/no-default-export
export default function listAlertTypes({ getService }: FtrProviderContext) {
const supertest = getService('supertest');
describe('list_alert_types', () => {
it('should return 200 with list of alert types', async () => {
const response = await supertest.get(`${getUrlPrefix(Spaces.space1.id)}/api/alert/types`);
expect(response.statusCode).to.eql(200);
const fixtureAlertType = response.body.find((alertType: any) => alertType.id === 'test.noop');
expect(fixtureAlertType).to.eql({
id: 'test.noop',
name: 'Test: Noop',
});
});
});
}

View file

@ -0,0 +1,47 @@
/*
* 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 { getTestAlertData } from './utils';
import { Spaces } 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 createUpdateTests({ getService }: FtrProviderContext) {
const supertest = getService('supertest');
describe('update', () => {
const objectRemover = new ObjectRemover(supertest);
after(() => objectRemover.removeAll());
it('should handle update alert request appropriately', async () => {
const { body: createdAlert } = await supertest
.post(`${getUrlPrefix(Spaces.space1.id)}/api/alert`)
.set('kbn-xsrf', 'foo')
.send(getTestAlertData())
.expect(200);
objectRemover.add(Spaces.space1.id, createdAlert.id, 'alert');
const updatedData = {
alertTypeParams: {
foo: true,
},
interval: '12s',
actions: [],
};
await supertest
.put(`${getUrlPrefix(Spaces.space1.id)}/api/alert/${createdAlert.id}`)
.set('kbn-xsrf', 'foo')
.send(updatedData)
.expect(200, {
...updatedData,
id: createdAlert.id,
updatedBy: null,
});
});
});
}

View file

@ -0,0 +1,55 @@
/*
* 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.
*/
const esTestIndexName = '.kibaka-alerting-test-data';
export function getTestAlertData(attributeOverwrites = {}) {
return {
enabled: true,
alertTypeId: 'test.noop',
interval: '10s',
actions: [],
alertTypeParams: {},
...attributeOverwrites,
};
}
export async function setupEsTestIndex(es: any) {
await es.indices.create({
index: esTestIndexName,
body: {
mappings: {
properties: {
source: {
type: 'keyword',
},
reference: {
type: 'keyword',
},
params: {
enabled: false,
type: 'object',
},
config: {
enabled: false,
type: 'object',
},
state: {
enabled: false,
type: 'object',
},
},
},
},
});
return {
name: esTestIndexName,
};
}
export async function destroyEsTestIndex(es: any) {
await es.indices.delete({ index: esTestIndexName, ignore: [404] });
}

View file

@ -0,0 +1,33 @@
/*
* 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 { SpacesService } from '../../../common/services';
import { FtrProviderContext } from '../../common/ftr_provider_context';
import { Spaces } from '../scenarios';
// eslint-disable-next-line import/no-default-export
export default function alertingApiIntegrationTests({
loadTestFile,
getService,
}: FtrProviderContext) {
const spacesService: SpacesService = getService('spaces');
const esArchiver = getService('esArchiver');
describe('alerting api integration spaces only', function() {
this.tags('ciGroup8');
before(async () => {
for (const space of Object.values(Spaces)) {
await spacesService.create(space);
}
});
after(() => esArchiver.unload('empty_kibana'));
loadTestFile(require.resolve('./actions'));
loadTestFile(require.resolve('./alerting'));
});
}