From 1d645f5c9fb406757c84f05b55842749ed604e6b Mon Sep 17 00:00:00 2001 From: FrankHassanabad Date: Mon, 3 Aug 2020 11:15:24 -0600 Subject: [PATCH 01/11] Initial addition of end to end tests for lists --- .../common/config.ts | 1 - .../lists_api_integration/common/config.ts | 69 +++++++++++++++++++ .../lists_api_integration/common/services.ts | 7 ++ .../security_and_spaces/config.ts | 14 ++++ .../security_and_spaces/tests/create_lists.ts | 33 +++++++++ 5 files changed, 123 insertions(+), 1 deletion(-) create mode 100644 x-pack/test/lists_api_integration/common/config.ts create mode 100644 x-pack/test/lists_api_integration/common/services.ts create mode 100644 x-pack/test/lists_api_integration/security_and_spaces/config.ts create mode 100644 x-pack/test/lists_api_integration/security_and_spaces/tests/create_lists.ts diff --git a/x-pack/test/detection_engine_api_integration/common/config.ts b/x-pack/test/detection_engine_api_integration/common/config.ts index 3e444bcab319a..6c7864f076a14 100644 --- a/x-pack/test/detection_engine_api_integration/common/config.ts +++ b/x-pack/test/detection_engine_api_integration/common/config.ts @@ -74,7 +74,6 @@ export function createTestConfig(name: string, options: CreateTestConfigOptions) ])}`, `--xpack.actions.enabledActionTypes=${JSON.stringify(enabledActionTypes)}`, '--xpack.eventLog.logEntries=true', - '--xpack.lists.enabled=true', ...disabledPlugins.map((key) => `--xpack.${key}.enabled=false`), `--plugin-path=${path.join(__dirname, 'fixtures', 'plugins', 'alerts')}`, `--plugin-path=${path.join(__dirname, 'fixtures', 'plugins', 'actions')}`, diff --git a/x-pack/test/lists_api_integration/common/config.ts b/x-pack/test/lists_api_integration/common/config.ts new file mode 100644 index 0000000000000..ca3cc3a5eee2f --- /dev/null +++ b/x-pack/test/lists_api_integration/common/config.ts @@ -0,0 +1,69 @@ +/* + * 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 path from 'path'; +import { CA_CERT_PATH } from '@kbn/dev-utils'; +import { FtrConfigProviderContext } from '@kbn/test/types/ftr'; +import { services } from './services'; + +interface CreateTestConfigOptions { + license: string; + disabledPlugins?: string[]; + ssl?: boolean; +} + +export function createTestConfig(name: string, options: CreateTestConfigOptions) { + const { license = 'trial', disabledPlugins = [], ssl = false } = options; + + return async ({ readConfigFile }: FtrConfigProviderContext) => { + const xPackApiIntegrationTestsConfig = await readConfigFile( + require.resolve('../../api_integration/config.ts') + ); + const servers = { + ...xPackApiIntegrationTestsConfig.get('servers'), + elasticsearch: { + ...xPackApiIntegrationTestsConfig.get('servers.elasticsearch'), + protocol: ssl ? 'https' : 'http', + }, + }; + + return { + testFiles: [require.resolve(`../${name}/tests/`)], + servers, + services, + junit: { + reportName: 'X-Pack Lists Integration Tests', + }, + esArchiver: xPackApiIntegrationTestsConfig.get('esArchiver'), + esTestCluster: { + ...xPackApiIntegrationTestsConfig.get('esTestCluster'), + license, + ssl, + serverArgs: [ + `xpack.license.self_generated.type=${license}`, + `xpack.security.enabled=${!disabledPlugins.includes('security')}`, + ], + }, + kbnTestServer: { + ...xPackApiIntegrationTestsConfig.get('kbnTestServer'), + serverArgs: [ + ...xPackApiIntegrationTestsConfig.get('kbnTestServer.serverArgs'), + ...disabledPlugins.map((key) => `--xpack.${key}.enabled=false`), + `--plugin-path=${path.join(__dirname, 'fixtures', 'plugins', 'alerts')}`, + `--plugin-path=${path.join(__dirname, 'fixtures', 'plugins', 'actions')}`, + `--plugin-path=${path.join(__dirname, 'fixtures', 'plugins', 'task_manager')}`, + `--plugin-path=${path.join(__dirname, 'fixtures', 'plugins', 'aad')}`, + ...(ssl + ? [ + `--elasticsearch.hosts=${servers.elasticsearch.protocol}://${servers.elasticsearch.hostname}:${servers.elasticsearch.port}`, + `--elasticsearch.ssl.certificateAuthorities=${CA_CERT_PATH}`, + ] + : []), + ], + }, + }; + }; +} diff --git a/x-pack/test/lists_api_integration/common/services.ts b/x-pack/test/lists_api_integration/common/services.ts new file mode 100644 index 0000000000000..a927a31469bab --- /dev/null +++ b/x-pack/test/lists_api_integration/common/services.ts @@ -0,0 +1,7 @@ +/* + * 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. + */ + +export { services } from '../../api_integration/services'; diff --git a/x-pack/test/lists_api_integration/security_and_spaces/config.ts b/x-pack/test/lists_api_integration/security_and_spaces/config.ts new file mode 100644 index 0000000000000..081b901c47fc3 --- /dev/null +++ b/x-pack/test/lists_api_integration/security_and_spaces/config.ts @@ -0,0 +1,14 @@ +/* + * 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('security_and_spaces', { + disabledPlugins: [], + license: 'trial', + ssl: true, +}); diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/create_lists.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/create_lists.ts new file mode 100644 index 0000000000000..629d58d1b2834 --- /dev/null +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/create_lists.ts @@ -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 expect from '@kbn/expect'; + +import { FtrProviderContext } from '../../common/ftr_provider_context'; +import { LIST_URL } from 'x-pack/plugins/lists/common/constants'; + +export default ({ getService }: FtrProviderContext) => { + const supertest = getService('supertest'); + const es = getService('es'); + + describe('create_lists', () => { + describe('validation errors', () => { + it('should give an error that the index must exist first if it does not exist before creating a rule', async () => { + const { body } = await supertest + .post(LIST_URL) + .set('kbn-xsrf', 'true') + .send(getSimpleRule()) + .expect(400); + + expect(body).to.eql({ + message: + 'To create a rule, the index must exist first. Index .siem-signals-default does not exist', + status_code: 400, + }); + }); + }); + }); +}); From 8a92670e43f14fe7b6a32398de9205a654cee326 Mon Sep 17 00:00:00 2001 From: FrankHassanabad Date: Wed, 5 Aug 2020 22:18:37 -0600 Subject: [PATCH 02/11] Initial end to end test setup --- x-pack/plugins/lists/common/constants.mock.ts | 1 + .../request/create_list_schema.mock.ts | 7 ++ .../schemas/response/list_schema.mock.ts | 16 +++++ .../common/ftr_provider_context.d.ts | 11 +++ .../security_and_spaces/tests/create_lists.ts | 34 ++++++++-- .../security_and_spaces/tests/index.ts | 16 +++++ x-pack/test/lists_api_integration/utils.ts | 68 +++++++++++++++++++ 7 files changed, 148 insertions(+), 5 deletions(-) create mode 100644 x-pack/test/lists_api_integration/common/ftr_provider_context.d.ts create mode 100644 x-pack/test/lists_api_integration/security_and_spaces/tests/index.ts create mode 100644 x-pack/test/lists_api_integration/utils.ts diff --git a/x-pack/plugins/lists/common/constants.mock.ts b/x-pack/plugins/lists/common/constants.mock.ts index b7609b5a3602a..428cc90d2908b 100644 --- a/x-pack/plugins/lists/common/constants.mock.ts +++ b/x-pack/plugins/lists/common/constants.mock.ts @@ -9,6 +9,7 @@ import { EntriesArray } from './schemas/types'; export const DATE_NOW = '2020-04-20T15:25:31.830Z'; export const OLD_DATE_RELATIVE_TO_DATE_NOW = '2020-04-19T15:25:31.830Z'; export const USER = 'some user'; +export const ELASTIC_USER = 'elastic'; export const LIST_INDEX = '.lists'; export const LIST_ITEM_INDEX = '.items'; export const NAME = 'some name'; diff --git a/x-pack/plugins/lists/common/schemas/request/create_list_schema.mock.ts b/x-pack/plugins/lists/common/schemas/request/create_list_schema.mock.ts index 461890b944bfa..382c5d17ea266 100644 --- a/x-pack/plugins/lists/common/schemas/request/create_list_schema.mock.ts +++ b/x-pack/plugins/lists/common/schemas/request/create_list_schema.mock.ts @@ -18,3 +18,10 @@ export const getCreateListSchemaMock = (): CreateListSchema => ({ type: TYPE, version: VERSION, }); + +export const getCreateMinimalListSchemaMock = (): CreateListSchema => ({ + description: DESCRIPTION, + id: LIST_ID, + name: NAME, + type: TYPE, +}); diff --git a/x-pack/plugins/lists/common/schemas/response/list_schema.mock.ts b/x-pack/plugins/lists/common/schemas/response/list_schema.mock.ts index 900c7ea4322a3..538ada8c6f51a 100644 --- a/x-pack/plugins/lists/common/schemas/response/list_schema.mock.ts +++ b/x-pack/plugins/lists/common/schemas/response/list_schema.mock.ts @@ -8,6 +8,7 @@ import { ListSchema } from '../../../common/schemas'; import { DATE_NOW, DESCRIPTION, + ELASTIC_USER, IMMUTABLE, LIST_ID, META, @@ -35,3 +36,18 @@ export const getListResponseMock = (): ListSchema => ({ updated_by: USER, version: VERSION, }); + +/** + * This is useful for end to end tests where we remove the auto generated parts for comparisons + * such as created_at, updated_at, and id. + */ +export const getListResponseMockWithoutAutoGeneratedValues = (): Partial => ({ + _version: 'WzAsMV0=', + created_by: ELASTIC_USER, + description: DESCRIPTION, + immutable: IMMUTABLE, + name: NAME, + type: TYPE, + updated_by: ELASTIC_USER, + version: VERSION, +}); diff --git a/x-pack/test/lists_api_integration/common/ftr_provider_context.d.ts b/x-pack/test/lists_api_integration/common/ftr_provider_context.d.ts new file mode 100644 index 0000000000000..e3add3748f56d --- /dev/null +++ b/x-pack/test/lists_api_integration/common/ftr_provider_context.d.ts @@ -0,0 +1,11 @@ +/* + * 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 { GenericFtrProviderContext } from '@kbn/test/types/ftr'; + +import { services } from './services'; + +export type FtrProviderContext = GenericFtrProviderContext; diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/create_lists.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/create_lists.ts index 629d58d1b2834..0372e93f8ba46 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/create_lists.ts +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/create_lists.ts @@ -6,12 +6,16 @@ import expect from '@kbn/expect'; +import { LIST_URL } from '../../../../plugins/lists/common/constants'; import { FtrProviderContext } from '../../common/ftr_provider_context'; -import { LIST_URL } from 'x-pack/plugins/lists/common/constants'; +import { getCreateMinimalListSchemaMock } from '../../../../plugins/lists/common/schemas/request/create_list_schema.mock'; +import { getListResponseMockWithoutAutoGeneratedValues } from '../../../../plugins/lists/common/schemas/response/list_schema.mock'; +import { createListsIndex, deleteListsIndex, removeServerGeneratedProperties } from '../../utils'; + +// eslint-disable-next-line import/no-default-export export default ({ getService }: FtrProviderContext) => { const supertest = getService('supertest'); - const es = getService('es'); describe('create_lists', () => { describe('validation errors', () => { @@ -19,15 +23,35 @@ export default ({ getService }: FtrProviderContext) => { const { body } = await supertest .post(LIST_URL) .set('kbn-xsrf', 'true') - .send(getSimpleRule()) + .send(getCreateMinimalListSchemaMock()) .expect(400); expect(body).to.eql({ message: - 'To create a rule, the index must exist first. Index .siem-signals-default does not exist', + 'To create a list, the index must exist first. Index ".lists-default" does not exist', status_code: 400, }); }); }); + + describe('creating lists', () => { + beforeEach(async () => { + await createListsIndex(supertest); + }); + + afterEach(async () => { + await deleteListsIndex(supertest); + }); + + it('should create a list with a list_id', async () => { + const { body } = await supertest + .post(LIST_URL) + .set('kbn-xsrf', 'true') + .send(getCreateMinimalListSchemaMock()); + + const bodyToCompare = removeServerGeneratedProperties(body); + expect(bodyToCompare).to.eql(getListResponseMockWithoutAutoGeneratedValues()); + }); + }); }); -}); +}; diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/index.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/index.ts new file mode 100644 index 0000000000000..b74f559e9a440 --- /dev/null +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/index.ts @@ -0,0 +1,16 @@ +/* + * 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 ({ loadTestFile }: FtrProviderContext): void => { + describe('lists api security and spaces enabled', function () { + this.tags('ciGroup1'); + + loadTestFile(require.resolve('./create_lists')); + }); +}; diff --git a/x-pack/test/lists_api_integration/utils.ts b/x-pack/test/lists_api_integration/utils.ts new file mode 100644 index 0000000000000..f2351dc42dd84 --- /dev/null +++ b/x-pack/test/lists_api_integration/utils.ts @@ -0,0 +1,68 @@ +/* + * 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 { SuperTest } from 'supertest'; +import supertestAsPromised from 'supertest-as-promised'; + +import { ListSchema } from '../../plugins/lists/common'; +import { LIST_INDEX } from '../../plugins/lists/common/constants'; + +/** + * Creates the lists index for use inside of beforeEach blocks of tests + * This will retry 20 times before giving up and hopefully still not interfere with other tests + * @param supertest The supertest client library + */ +export const createListsIndex = async ( + supertest: SuperTest, + retryCount = 20 +): Promise => { + if (retryCount > 0) { + try { + await supertest.post(LIST_INDEX).set('kbn-xsrf', 'true').send(); + } catch (err) { + // eslint-disable-next-line no-console + console.log( + `Failure trying to create the lists index, retries left are: ${retryCount - 1}`, + err + ); + await createListsIndex(supertest, retryCount - 1); + } + } else { + // eslint-disable-next-line no-console + console.log('Could not createListsIndex, no retries are left'); + } +}; + +/** + * Deletes the lists index for use inside of afterEach blocks of tests + * @param supertest The supertest client library + */ +export const deleteListsIndex = async ( + supertest: SuperTest, + retryCount = 20 +): Promise => { + if (retryCount > 0) { + try { + await supertest.delete(LIST_INDEX).set('kbn-xsrf', 'true').send(); + } catch (err) { + // eslint-disable-next-line no-console + console.log(`Failure trying to deleteListsIndex, retries left are: ${retryCount - 1}`, err); + await deleteListsIndex(supertest, retryCount - 1); + } + } else { + // eslint-disable-next-line no-console + console.log('Could not deleteListsIndex, no retries are left'); + } +}; + +/** + * This will remove server generated properties such as date times, etc... + * @param rule Rule to pass in to remove typical server generated properties + */ +export const removeServerGeneratedProperties = (rule: Partial): Partial => { + const { created_at, updated_at, id, tie_breaker_id, ...removedProperties } = rule; + return removedProperties; +}; From 7d1d9406e5e1b3ef389ddf339654a74de83e784a Mon Sep 17 00:00:00 2001 From: FrankHassanabad Date: Wed, 5 Aug 2020 22:35:18 -0600 Subject: [PATCH 03/11] Adds more basics of the tests for lists --- .../security_and_spaces/tests/create_lists.ts | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/create_lists.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/create_lists.ts index 0372e93f8ba46..1385662f40c20 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/create_lists.ts +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/create_lists.ts @@ -43,15 +43,35 @@ export default ({ getService }: FtrProviderContext) => { await deleteListsIndex(supertest); }); - it('should create a list with a list_id', async () => { + it('should create a simple list with a list_id', async () => { const { body } = await supertest .post(LIST_URL) .set('kbn-xsrf', 'true') - .send(getCreateMinimalListSchemaMock()); + .send(getCreateMinimalListSchemaMock()) + .expect(200); const bodyToCompare = removeServerGeneratedProperties(body); expect(bodyToCompare).to.eql(getListResponseMockWithoutAutoGeneratedValues()); }); + + it('should cause a 409 conflict if we attempt to create the same list_id twice', async () => { + await supertest + .post(LIST_URL) + .set('kbn-xsrf', 'true') + .send(getCreateMinimalListSchemaMock()) + .expect(200); + + const { body } = await supertest + .post(LIST_URL) + .set('kbn-xsrf', 'true') + .send(getCreateMinimalListSchemaMock()) + .expect(409); + + expect(body).to.eql({ + message: 'list id: "some-list-id" already exists', + status_code: 409, + }); + }); }); }); }; From 55bc2add70e009786601336de049ac7145b5c849 Mon Sep 17 00:00:00 2001 From: FrankHassanabad Date: Wed, 5 Aug 2020 23:20:23 -0600 Subject: [PATCH 04/11] Fixes lint issue and adds a base read_lists end to end test --- .../request/create_list_schema.mock.ts | 6 ++ .../security_and_spaces/tests/create_lists.ts | 16 +++- .../security_and_spaces/tests/index.ts | 1 + .../security_and_spaces/tests/read_lists.ts | 82 +++++++++++++++++++ x-pack/test/lists_api_integration/utils.ts | 1 + 5 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 x-pack/test/lists_api_integration/security_and_spaces/tests/read_lists.ts diff --git a/x-pack/plugins/lists/common/schemas/request/create_list_schema.mock.ts b/x-pack/plugins/lists/common/schemas/request/create_list_schema.mock.ts index 382c5d17ea266..c4e457a43387b 100644 --- a/x-pack/plugins/lists/common/schemas/request/create_list_schema.mock.ts +++ b/x-pack/plugins/lists/common/schemas/request/create_list_schema.mock.ts @@ -25,3 +25,9 @@ export const getCreateMinimalListSchemaMock = (): CreateListSchema => ({ name: NAME, type: TYPE, }); + +export const getCreateMinimalListSchemaMockWithoutId = (): CreateListSchema => ({ + description: DESCRIPTION, + name: NAME, + type: TYPE, +}); diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/create_lists.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/create_lists.ts index 1385662f40c20..44b587f567fdb 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/create_lists.ts +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/create_lists.ts @@ -8,7 +8,10 @@ import expect from '@kbn/expect'; import { LIST_URL } from '../../../../plugins/lists/common/constants'; import { FtrProviderContext } from '../../common/ftr_provider_context'; -import { getCreateMinimalListSchemaMock } from '../../../../plugins/lists/common/schemas/request/create_list_schema.mock'; +import { + getCreateMinimalListSchemaMock, + getCreateMinimalListSchemaMockWithoutId, +} from '../../../../plugins/lists/common/schemas/request/create_list_schema.mock'; import { getListResponseMockWithoutAutoGeneratedValues } from '../../../../plugins/lists/common/schemas/response/list_schema.mock'; import { createListsIndex, deleteListsIndex, removeServerGeneratedProperties } from '../../utils'; @@ -54,6 +57,17 @@ export default ({ getService }: FtrProviderContext) => { expect(bodyToCompare).to.eql(getListResponseMockWithoutAutoGeneratedValues()); }); + it('should create a simple list without a list_id', async () => { + const { body } = await supertest + .post(LIST_URL) + .set('kbn-xsrf', 'true') + .send(getCreateMinimalListSchemaMockWithoutId()) + .expect(200); + + const bodyToCompare = removeServerGeneratedProperties(body); + expect(bodyToCompare).to.eql(getListResponseMockWithoutAutoGeneratedValues()); + }); + it('should cause a 409 conflict if we attempt to create the same list_id twice', async () => { await supertest .post(LIST_URL) diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/index.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/index.ts index b74f559e9a440..b2cb89df39d3e 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/index.ts +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/index.ts @@ -12,5 +12,6 @@ export default ({ loadTestFile }: FtrProviderContext): void => { this.tags('ciGroup1'); loadTestFile(require.resolve('./create_lists')); + loadTestFile(require.resolve('./read_lists')); }); }; diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/read_lists.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/read_lists.ts new file mode 100644 index 0000000000000..4888e537b2c0f --- /dev/null +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/read_lists.ts @@ -0,0 +1,82 @@ +/* + * 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'; +import { LIST_URL } from '../../../../plugins/lists/common/constants'; + +import { + getCreateMinimalListSchemaMock, + getCreateMinimalListSchemaMockWithoutId, +} from '../../../../plugins/lists/common/schemas/request/create_list_schema.mock'; +import { createListsIndex, deleteListsIndex, removeServerGeneratedProperties } from '../../utils'; +import { getListResponseMockWithoutAutoGeneratedValues } from '../../../../plugins/lists/common/schemas/response/list_schema.mock'; + +// eslint-disable-next-line import/no-default-export +export default ({ getService }: FtrProviderContext) => { + const supertest = getService('supertest'); + + describe('read_lists', () => { + describe('reading lists', () => { + beforeEach(async () => { + await createListsIndex(supertest); + }); + + afterEach(async () => { + await deleteListsIndex(supertest); + }); + + it('should be able to read a single list using id', async () => { + // create a simple list to read + await supertest + .post(LIST_URL) + .set('kbn-xsrf', 'true') + .send(getCreateMinimalListSchemaMock()) + .expect(200); + + const { body } = await supertest + .get(`${LIST_URL}?id=some-list-id`) + .set('kbn-xsrf', 'true') + .send(getCreateMinimalListSchemaMock()) + .expect(200); + + const bodyToCompare = removeServerGeneratedProperties(body); + expect(bodyToCompare).to.eql(getListResponseMockWithoutAutoGeneratedValues()); + }); + + it('should be able to read a single list with an auto-generated list id', async () => { + // create a simple list to read + const { body: createListBody } = await supertest + .post(LIST_URL) + .set('kbn-xsrf', 'true') + .send(getCreateMinimalListSchemaMockWithoutId()) + .expect(200); + + const { body } = await supertest + .get(`${LIST_URL}?id=${createListBody.id}`) + .set('kbn-xsrf', 'true') + .send(getCreateMinimalListSchemaMock()) + .expect(200); + + const bodyToCompare = removeServerGeneratedProperties(body); + expect(bodyToCompare).to.eql(getListResponseMockWithoutAutoGeneratedValues()); + }); + + it('should return 404 if given a fake id', async () => { + const { body } = await supertest + .get(`${LIST_URL}?id=c1e1b359-7ac1-4e96-bc81-c683c092436f`) + .set('kbn-xsrf', 'true') + .expect(404); + + expect(body).to.eql({ + status_code: 404, + message: 'list id: "c1e1b359-7ac1-4e96-bc81-c683c092436f" does not exist', + }); + }); + }); + }); +}; diff --git a/x-pack/test/lists_api_integration/utils.ts b/x-pack/test/lists_api_integration/utils.ts index f2351dc42dd84..5d1d0e5b2c408 100644 --- a/x-pack/test/lists_api_integration/utils.ts +++ b/x-pack/test/lists_api_integration/utils.ts @@ -63,6 +63,7 @@ export const deleteListsIndex = async ( * @param rule Rule to pass in to remove typical server generated properties */ export const removeServerGeneratedProperties = (rule: Partial): Partial => { + /* eslint-disable-next-line @typescript-eslint/naming-convention */ const { created_at, updated_at, id, tie_breaker_id, ...removedProperties } = rule; return removedProperties; }; From ec64d17f1b61232b00c478624f1e4fe8e18705e1 Mon Sep 17 00:00:00 2001 From: FrankHassanabad Date: Thu, 6 Aug 2020 16:38:31 -0600 Subject: [PATCH 05/11] Adds more end to end tests, fixes some message bugs in the REST routes, and adds some missing unit tests --- .../request/update_list_schema.mock.ts | 27 ++++ .../request/update_list_schema.test.ts | 48 ++++++ .../schemas/response/list_schema.mock.ts | 1 - .../lists/server/routes/patch_list_route.ts | 2 +- .../routes/update_exception_list_route.ts | 2 +- .../lists/server/routes/update_list_route.ts | 2 +- .../security_and_spaces/tests/create_lists.ts | 2 +- .../security_and_spaces/tests/delete_lists.ts | 79 ++++++++++ .../security_and_spaces/tests/find_lists.ts | 73 ++++++++++ .../security_and_spaces/tests/index.ts | 3 + .../security_and_spaces/tests/update_lists.ts | 137 ++++++++++++++++++ x-pack/test/lists_api_integration/utils.ts | 6 +- 12 files changed, 374 insertions(+), 8 deletions(-) create mode 100644 x-pack/plugins/lists/common/schemas/request/update_list_schema.mock.ts create mode 100644 x-pack/plugins/lists/common/schemas/request/update_list_schema.test.ts create mode 100644 x-pack/test/lists_api_integration/security_and_spaces/tests/delete_lists.ts create mode 100644 x-pack/test/lists_api_integration/security_and_spaces/tests/find_lists.ts create mode 100644 x-pack/test/lists_api_integration/security_and_spaces/tests/update_lists.ts diff --git a/x-pack/plugins/lists/common/schemas/request/update_list_schema.mock.ts b/x-pack/plugins/lists/common/schemas/request/update_list_schema.mock.ts new file mode 100644 index 0000000000000..b044d40a5d88f --- /dev/null +++ b/x-pack/plugins/lists/common/schemas/request/update_list_schema.mock.ts @@ -0,0 +1,27 @@ +/* + * 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 { DESCRIPTION, LIST_ID, META, NAME, _VERSION } from '../../constants.mock'; + +import { UpdateListSchema } from './update_list_schema'; + +export const getUpdateListSchemaMock = (): UpdateListSchema => ({ + _version: _VERSION, + description: DESCRIPTION, + id: LIST_ID, + meta: META, + name: NAME, +}); + +/** + * Useful for end to end tests and other mechanisms which want to fill in the values + * after doing a get of the structure. + */ +export const getUpdateMinimalListSchemaMock = (): UpdateListSchema => ({ + description: DESCRIPTION, + id: LIST_ID, + name: NAME, +}); diff --git a/x-pack/plugins/lists/common/schemas/request/update_list_schema.test.ts b/x-pack/plugins/lists/common/schemas/request/update_list_schema.test.ts new file mode 100644 index 0000000000000..21d20a6b85bce --- /dev/null +++ b/x-pack/plugins/lists/common/schemas/request/update_list_schema.test.ts @@ -0,0 +1,48 @@ +/* + * 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 { left } from 'fp-ts/lib/Either'; +import { pipe } from 'fp-ts/lib/pipeable'; + +import { exactCheck, foldLeftRight, getPaths } from '../../shared_imports'; + +import { UpdateListSchema, updateListSchema } from './update_list_schema'; +import { getUpdateListSchemaMock } from './update_list_schema.mock'; + +describe('update_list_schema', () => { + test('it should validate a typical list request', () => { + const payload = getUpdateListSchemaMock(); + const decoded = updateListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should accept an undefined for "meta" but strip it out', () => { + const payload = getUpdateListSchemaMock(); + const outputPayload = getUpdateListSchemaMock(); + delete payload.meta; + const decoded = updateListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + delete outputPayload.meta; + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(outputPayload); + }); + + test('it should not allow an extra key to be sent in', () => { + const payload: UpdateListSchema & { + extraKey?: string; + } = getUpdateListSchemaMock(); + payload.extraKey = 'some new value'; + const decoded = updateListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); + expect(message.schema).toEqual({}); + }); +}); diff --git a/x-pack/plugins/lists/common/schemas/response/list_schema.mock.ts b/x-pack/plugins/lists/common/schemas/response/list_schema.mock.ts index 538ada8c6f51a..4ae77e12a8294 100644 --- a/x-pack/plugins/lists/common/schemas/response/list_schema.mock.ts +++ b/x-pack/plugins/lists/common/schemas/response/list_schema.mock.ts @@ -42,7 +42,6 @@ export const getListResponseMock = (): ListSchema => ({ * such as created_at, updated_at, and id. */ export const getListResponseMockWithoutAutoGeneratedValues = (): Partial => ({ - _version: 'WzAsMV0=', created_by: ELASTIC_USER, description: DESCRIPTION, immutable: IMMUTABLE, diff --git a/x-pack/plugins/lists/server/routes/patch_list_route.ts b/x-pack/plugins/lists/server/routes/patch_list_route.ts index e33d8d7c9c598..763f3f495ca17 100644 --- a/x-pack/plugins/lists/server/routes/patch_list_route.ts +++ b/x-pack/plugins/lists/server/routes/patch_list_route.ts @@ -32,7 +32,7 @@ export const patchListRoute = (router: IRouter): void => { const list = await lists.updateList({ _version, description, id, meta, name, version }); if (list == null) { return siemResponse.error({ - body: `list id: "${id}" found found`, + body: `list id: "${id}" not found`, statusCode: 404, }); } else { diff --git a/x-pack/plugins/lists/server/routes/update_exception_list_route.ts b/x-pack/plugins/lists/server/routes/update_exception_list_route.ts index bead10802df4f..8102210b8430d 100644 --- a/x-pack/plugins/lists/server/routes/update_exception_list_route.ts +++ b/x-pack/plugins/lists/server/routes/update_exception_list_route.ts @@ -69,7 +69,7 @@ export const updateExceptionListRoute = (router: IRouter): void => { }); if (list == null) { return siemResponse.error({ - body: `exception list id: "${id}" found found`, + body: `exception list id: "${id}" not found`, statusCode: 404, }); } else { diff --git a/x-pack/plugins/lists/server/routes/update_list_route.ts b/x-pack/plugins/lists/server/routes/update_list_route.ts index 816ad13d3770e..8d7d08be4130b 100644 --- a/x-pack/plugins/lists/server/routes/update_list_route.ts +++ b/x-pack/plugins/lists/server/routes/update_list_route.ts @@ -32,7 +32,7 @@ export const updateListRoute = (router: IRouter): void => { const list = await lists.updateList({ _version, description, id, meta, name, version }); if (list == null) { return siemResponse.error({ - body: `list id: "${id}" found found`, + body: `list id: "${id}" not found`, statusCode: 404, }); } else { diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/create_lists.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/create_lists.ts index 44b587f567fdb..99766ce20c067 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/create_lists.ts +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/create_lists.ts @@ -22,7 +22,7 @@ export default ({ getService }: FtrProviderContext) => { describe('create_lists', () => { describe('validation errors', () => { - it('should give an error that the index must exist first if it does not exist before creating a rule', async () => { + it('should give an error that the index must exist first if it does not exist before creating a list', async () => { const { body } = await supertest .post(LIST_URL) .set('kbn-xsrf', 'true') diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/delete_lists.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/delete_lists.ts new file mode 100644 index 0000000000000..a5a25cf4bd043 --- /dev/null +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/delete_lists.ts @@ -0,0 +1,79 @@ +/* + * 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'; +import { LIST_URL } from '../../../../plugins/lists/common/constants'; + +import { getCreateMinimalListSchemaMock } from '../../../../plugins/lists/common/schemas/request/create_list_schema.mock'; +import { createListsIndex, deleteListsIndex, removeServerGeneratedProperties } from '../../utils'; +import { getListResponseMockWithoutAutoGeneratedValues } from '../../../../plugins/lists/common/schemas/response/list_schema.mock'; + +// eslint-disable-next-line import/no-default-export +export default ({ getService }: FtrProviderContext) => { + const supertest = getService('supertest'); + + describe('delete_lists', () => { + describe('deleting lists', () => { + beforeEach(async () => { + await createListsIndex(supertest); + }); + + afterEach(async () => { + await deleteListsIndex(supertest); + }); + + it('should delete a single list with a list id', async () => { + // create a list + await supertest + .post(LIST_URL) + .set('kbn-xsrf', 'true') + .send(getCreateMinimalListSchemaMock()) + .expect(200); + + // delete the list by its list id + const { body } = await supertest + .delete(`${LIST_URL}?id=${getCreateMinimalListSchemaMock().id}`) + .set('kbn-xsrf', 'true') + .expect(200); + + const bodyToCompare = removeServerGeneratedProperties(body); + expect(bodyToCompare).to.eql(getListResponseMockWithoutAutoGeneratedValues()); + }); + + it('should delete a single list using an auto generated id', async () => { + // add a list + const { body: bodyWithCreatedList } = await supertest + .post(LIST_URL) + .set('kbn-xsrf', 'true') + .send(getCreateMinimalListSchemaMock()) + .expect(200); + + // delete that list by its auto-generated id + const { body } = await supertest + .delete(`${LIST_URL}?id=${bodyWithCreatedList.id}`) + .set('kbn-xsrf', 'true') + .expect(200); + + const bodyToCompare = removeServerGeneratedProperties(body); + expect(bodyToCompare).to.eql(getListResponseMockWithoutAutoGeneratedValues()); + }); + + it('should return an error if the id does not exist when trying to delete it', async () => { + const { body } = await supertest + .delete(`${LIST_URL}?id=c1e1b359-7ac1-4e96-bc81-c683c092436f`) + .set('kbn-xsrf', 'true') + .expect(404); + + expect(body).to.eql({ + message: 'list id: "c1e1b359-7ac1-4e96-bc81-c683c092436f" was not found', + status_code: 404, + }); + }); + }); + }); +}; diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/find_lists.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/find_lists.ts new file mode 100644 index 0000000000000..efd240a89b8ae --- /dev/null +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/find_lists.ts @@ -0,0 +1,73 @@ +/* + * 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'; +import { LIST_URL } from '../../../../plugins/lists/common/constants'; + +import { getCreateMinimalListSchemaMock } from '../../../../plugins/lists/common/schemas/request/create_list_schema.mock'; +import { createListsIndex, deleteListsIndex, removeServerGeneratedProperties } from '../../utils'; +import { getListResponseMockWithoutAutoGeneratedValues } from '../../../../plugins/lists/common/schemas/response/list_schema.mock'; + +// eslint-disable-next-line import/no-default-export +export default ({ getService }: FtrProviderContext): void => { + const supertest = getService('supertest'); + + describe('find_lists', () => { + describe('find lists', () => { + beforeEach(async () => { + await createListsIndex(supertest); + }); + + afterEach(async () => { + await deleteListsIndex(supertest); + }); + + it('should return an empty find body correctly if no lists are loaded', async () => { + const { body } = await supertest + .get(`${LIST_URL}/_find`) + .set('kbn-xsrf', 'true') + .send() + .expect(200); + + expect(body).to.eql({ + cursor: 'WzBd', + data: [], + page: 1, + per_page: 20, + total: 0, + }); + }); + + it('should return a single list when a single list is loaded from a find with defaults added', async () => { + // add a single list + await supertest + .post(LIST_URL) + .set('kbn-xsrf', 'true') + .send(getCreateMinimalListSchemaMock()) + .expect(200); + + // query the single list from _find + const { body } = await supertest + .get(`${LIST_URL}/_find`) + .set('kbn-xsrf', 'true') + .send() + .expect(200); + + body.data = [removeServerGeneratedProperties(body.data[0])]; + // cursor is a constant changing value so we have to delete it as well. + delete body.cursor; + expect(body).to.eql({ + data: [getListResponseMockWithoutAutoGeneratedValues()], + page: 1, + per_page: 20, + total: 1, + }); + }); + }); + }); +}; diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/index.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/index.ts index b2cb89df39d3e..f380b2a860da7 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/index.ts +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/index.ts @@ -13,5 +13,8 @@ export default ({ loadTestFile }: FtrProviderContext): void => { loadTestFile(require.resolve('./create_lists')); loadTestFile(require.resolve('./read_lists')); + loadTestFile(require.resolve('./update_lists')); + loadTestFile(require.resolve('./delete_lists')); + loadTestFile(require.resolve('./find_lists')); }); }; diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/update_lists.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/update_lists.ts new file mode 100644 index 0000000000000..242705731d19d --- /dev/null +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/update_lists.ts @@ -0,0 +1,137 @@ +/* + * 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'; +import { LIST_URL } from '../../../../plugins/lists/common/constants'; + +import { getCreateMinimalListSchemaMock } from '../../../../plugins/lists/common/schemas/request/create_list_schema.mock'; +import { createListsIndex, deleteListsIndex, removeServerGeneratedProperties } from '../../utils'; +import { getListResponseMockWithoutAutoGeneratedValues } from '../../../../plugins/lists/common/schemas/response/list_schema.mock'; +import { getUpdateMinimalListSchemaMock } from '../../../../plugins/lists/common/schemas/request/update_list_schema.mock'; +import { UpdateListSchema, ListSchema } from '../../../../plugins/lists/common/schemas'; + +// eslint-disable-next-line import/no-default-export +export default ({ getService }: FtrProviderContext) => { + const supertest = getService('supertest'); + + describe('update_lists', () => { + describe('update lists', () => { + beforeEach(async () => { + await createListsIndex(supertest); + }); + + afterEach(async () => { + await deleteListsIndex(supertest); + }); + + it('should update a single list property of name using an id', async () => { + // create a simple list + await supertest + .post(LIST_URL) + .set('kbn-xsrf', 'true') + .send(getCreateMinimalListSchemaMock()) + .expect(200); + + // update a simple list's name + const updatedList: UpdateListSchema = { + ...getUpdateMinimalListSchemaMock(), + name: 'some other name', + }; + + const { body } = await supertest + .put(LIST_URL) + .set('kbn-xsrf', 'true') + .send(updatedList) + .expect(200); + + const outputList: Partial = { + ...getListResponseMockWithoutAutoGeneratedValues(), + name: 'some other name', + version: 2, + }; + const bodyToCompare = removeServerGeneratedProperties(body); + expect(bodyToCompare).to.eql(outputList); + }); + + it('should update a single list property of name using an auto-generated id', async () => { + const { id, ...listNoId } = getCreateMinimalListSchemaMock(); + // create a simple list with no id which will use an auto-generated id + const { body: createListBody } = await supertest + .post(LIST_URL) + .set('kbn-xsrf', 'true') + .send(listNoId) + .expect(200); + + // update a simple list's name + const updatedList: UpdateListSchema = { + ...getUpdateMinimalListSchemaMock(), + id: createListBody.id, + name: 'some other name', + }; + const { body } = await supertest + .put(LIST_URL) + .set('kbn-xsrf', 'true') + .send(updatedList) + .expect(200); + + const outputList: Partial = { + ...getListResponseMockWithoutAutoGeneratedValues(), + name: 'some other name', + version: 2, + }; + const bodyToCompare = removeServerGeneratedProperties(body); + expect(bodyToCompare).to.eql(outputList); + }); + + it('should change the version of a list when it updates a property', async () => { + // create a simple list + await supertest + .post(LIST_URL) + .set('kbn-xsrf', 'true') + .send(getCreateMinimalListSchemaMock()) + .expect(200); + + // update a simple list property of name and description + const updatedList: UpdateListSchema = { + ...getUpdateMinimalListSchemaMock(), + name: 'some other name', + description: 'some other description', + }; + + const { body } = await supertest.put(LIST_URL).set('kbn-xsrf', 'true').send(updatedList); + + const outputList: Partial = { + ...getListResponseMockWithoutAutoGeneratedValues(), + name: 'some other name', + description: 'some other description', + version: 2, + }; + + const bodyToCompare = removeServerGeneratedProperties(body); + expect(bodyToCompare).to.eql(outputList); + }); + + it('should give a 404 if it is given a fake id', async () => { + const simpleList: UpdateListSchema = { + ...getUpdateMinimalListSchemaMock(), + id: '5096dec6-b6b9-4d8d-8f93-6c2602079d9d', + }; + const { body } = await supertest + .put(LIST_URL) + .set('kbn-xsrf', 'true') + .send(simpleList) + .expect(404); + + expect(body).to.eql({ + status_code: 404, + message: 'list id: "5096dec6-b6b9-4d8d-8f93-6c2602079d9d" not found', + }); + }); + }); + }); +}; diff --git a/x-pack/test/lists_api_integration/utils.ts b/x-pack/test/lists_api_integration/utils.ts index 5d1d0e5b2c408..bcadd894bd800 100644 --- a/x-pack/test/lists_api_integration/utils.ts +++ b/x-pack/test/lists_api_integration/utils.ts @@ -60,10 +60,10 @@ export const deleteListsIndex = async ( /** * This will remove server generated properties such as date times, etc... - * @param rule Rule to pass in to remove typical server generated properties + * @param list List to pass in to remove typical server generated properties */ -export const removeServerGeneratedProperties = (rule: Partial): Partial => { +export const removeServerGeneratedProperties = (list: Partial): Partial => { /* eslint-disable-next-line @typescript-eslint/naming-convention */ - const { created_at, updated_at, id, tie_breaker_id, ...removedProperties } = rule; + const { created_at, updated_at, id, tie_breaker_id, _version, ...removedProperties } = list; return removedProperties; }; From 52920f55c8ba2ca9c0c7fbcab68865f7987353ae Mon Sep 17 00:00:00 2001 From: FrankHassanabad Date: Mon, 10 Aug 2020 11:55:47 -0600 Subject: [PATCH 06/11] Added more end to end tests with list items --- .../request/create_list_item_schema.mock.ts | 11 ++ .../schemas/response/list_item_schema.mock.ts | 13 ++ .../server/routes/create_list_item_route.ts | 9 ++ .../tests/create_list_items.ts | 111 ++++++++++++++++++ .../security_and_spaces/tests/index.ts | 2 + .../tests/read_list_items.ts | 94 +++++++++++++++ .../security_and_spaces/tests/read_lists.ts | 4 +- x-pack/test/lists_api_integration/utils.ts | 2 +- 8 files changed, 242 insertions(+), 4 deletions(-) create mode 100644 x-pack/test/lists_api_integration/security_and_spaces/tests/create_list_items.ts create mode 100644 x-pack/test/lists_api_integration/security_and_spaces/tests/read_list_items.ts diff --git a/x-pack/plugins/lists/common/schemas/request/create_list_item_schema.mock.ts b/x-pack/plugins/lists/common/schemas/request/create_list_item_schema.mock.ts index f0d4af520bdbb..f486cde7525ea 100644 --- a/x-pack/plugins/lists/common/schemas/request/create_list_item_schema.mock.ts +++ b/x-pack/plugins/lists/common/schemas/request/create_list_item_schema.mock.ts @@ -14,3 +14,14 @@ export const getCreateListItemSchemaMock = (): CreateListItemSchema => ({ meta: META, value: VALUE, }); + +export const getCreateMinimalListItemSchemaMock = (): CreateListItemSchema => ({ + id: LIST_ITEM_ID, + list_id: LIST_ID, + value: VALUE, +}); + +export const getCreateMinimalListItemSchemaMockWithoutId = (): CreateListItemSchema => ({ + list_id: LIST_ID, + value: VALUE, +}); diff --git a/x-pack/plugins/lists/common/schemas/response/list_item_schema.mock.ts b/x-pack/plugins/lists/common/schemas/response/list_item_schema.mock.ts index e122f6a2bbe3b..f4e36d1d060c0 100644 --- a/x-pack/plugins/lists/common/schemas/response/list_item_schema.mock.ts +++ b/x-pack/plugins/lists/common/schemas/response/list_item_schema.mock.ts @@ -7,6 +7,7 @@ import { ListItemSchema } from '../../../common/schemas'; import { DATE_NOW, + ELASTIC_USER, LIST_ID, LIST_ITEM_ID, META, @@ -31,3 +32,15 @@ export const getListItemResponseMock = (): ListItemSchema => ({ updated_by: USER, value: VALUE, }); + +/** + * This is useful for end to end tests where we remove the auto generated parts for comparisons + * such as created_at, updated_at, and id. + */ +export const getListItemResponseMockWithoutAutoGeneratedValues = (): Partial => ({ + created_by: ELASTIC_USER, + list_id: LIST_ID, + type: TYPE, + updated_by: ELASTIC_USER, + value: VALUE, +}); diff --git a/x-pack/plugins/lists/server/routes/create_list_item_route.ts b/x-pack/plugins/lists/server/routes/create_list_item_route.ts index 0a4a1c739ae7c..bd2828d331d83 100644 --- a/x-pack/plugins/lists/server/routes/create_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/create_list_item_route.ts @@ -36,6 +36,15 @@ export const createListItemRoute = (router: IRouter): void => { statusCode: 404, }); } else { + if (id != null) { + const listItem = await lists.getListItem({ id }); + if (listItem != null) { + return siemResponse.error({ + body: `list item id: "${id}" already exists`, + statusCode: 409, + }); + } + } const createdListItem = await lists.createListItem({ deserializer: list.deserializer, id, diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/create_list_items.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/create_list_items.ts new file mode 100644 index 0000000000000..16e22f3bf4de3 --- /dev/null +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/create_list_items.ts @@ -0,0 +1,111 @@ +/* + * 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 { LIST_URL, LIST_ITEM_URL } from '../../../../plugins/lists/common/constants'; +import { FtrProviderContext } from '../../common/ftr_provider_context'; + +import { getCreateMinimalListSchemaMock } from '../../../../plugins/lists/common/schemas/request/create_list_schema.mock'; + +import { + getCreateMinimalListItemSchemaMock, + getCreateMinimalListItemSchemaMockWithoutId, +} from '../../../../plugins/lists/common/schemas/request/create_list_item_schema.mock'; +import { getListItemResponseMockWithoutAutoGeneratedValues } from '../../../../plugins/lists/common/schemas/response/list_item_schema.mock'; + +import { createListsIndex, deleteListsIndex, removeServerGeneratedProperties } from '../../utils'; + +// eslint-disable-next-line import/no-default-export +export default ({ getService }: FtrProviderContext) => { + const supertest = getService('supertest'); + + describe('create_list_items', () => { + describe('validation errors', () => { + it('should give a 404 error that the list must exist first before being able to add a list item', async () => { + const { body } = await supertest + .post(LIST_ITEM_URL) + .set('kbn-xsrf', 'true') + .send(getCreateMinimalListItemSchemaMock()) + .expect(404); + + expect(body).to.eql({ + message: 'list id: "some-list-id" does not exist', + status_code: 404, + }); + }); + }); + + describe('creating list items', () => { + beforeEach(async () => { + await createListsIndex(supertest); + }); + + afterEach(async () => { + await deleteListsIndex(supertest); + }); + + it('should create a simple list item with a list item id', async () => { + await supertest + .post(LIST_URL) + .set('kbn-xsrf', 'true') + .send(getCreateMinimalListSchemaMock()) + .expect(200); + + const { body } = await supertest + .post(LIST_ITEM_URL) + .set('kbn-xsrf', 'true') + .send(getCreateMinimalListItemSchemaMock()) + .expect(200); + + const bodyToCompare = removeServerGeneratedProperties(body); + expect(bodyToCompare).to.eql(getListItemResponseMockWithoutAutoGeneratedValues()); + }); + + it('should create a simple list item without an id', async () => { + await supertest + .post(LIST_URL) + .set('kbn-xsrf', 'true') + .send(getCreateMinimalListSchemaMock()) + .expect(200); + + const { body } = await supertest + .post(LIST_ITEM_URL) + .set('kbn-xsrf', 'true') + .send(getCreateMinimalListItemSchemaMockWithoutId()) + .expect(200); + + const bodyToCompare = removeServerGeneratedProperties(body); + expect(bodyToCompare).to.eql(getListItemResponseMockWithoutAutoGeneratedValues()); + }); + + it('should cause a 409 conflict if we attempt to create the same list item twice', async () => { + await supertest + .post(LIST_URL) + .set('kbn-xsrf', 'true') + .send(getCreateMinimalListSchemaMock()) + .expect(200); + + await supertest + .post(LIST_ITEM_URL) + .set('kbn-xsrf', 'true') + .send(getCreateMinimalListItemSchemaMock()) + .expect(200); + + const { body } = await supertest + .post(LIST_ITEM_URL) + .set('kbn-xsrf', 'true') + .send(getCreateMinimalListItemSchemaMock()) + .expect(409); + + expect(body).to.eql({ + message: 'list item id: "some-list-item-id" already exists', + status_code: 409, + }); + }); + }); + }); +}; diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/index.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/index.ts index f380b2a860da7..2141d8287429c 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/index.ts +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/index.ts @@ -12,7 +12,9 @@ export default ({ loadTestFile }: FtrProviderContext): void => { this.tags('ciGroup1'); loadTestFile(require.resolve('./create_lists')); + loadTestFile(require.resolve('./create_list_items')); loadTestFile(require.resolve('./read_lists')); + loadTestFile(require.resolve('./read_list_items')); loadTestFile(require.resolve('./update_lists')); loadTestFile(require.resolve('./delete_lists')); loadTestFile(require.resolve('./find_lists')); diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/read_list_items.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/read_list_items.ts new file mode 100644 index 0000000000000..7e4dbb3b9d4cb --- /dev/null +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/read_list_items.ts @@ -0,0 +1,94 @@ +/* + * 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 { getListItemResponseMockWithoutAutoGeneratedValues } from '../../../../plugins/lists/common/schemas/response/list_item_schema.mock'; +import { getCreateMinimalListItemSchemaMock } from '../../../../plugins/lists/common/schemas/request/create_list_item_schema.mock'; +import { FtrProviderContext } from '../../common/ftr_provider_context'; +import { LIST_URL, LIST_ITEM_URL } from '../../../../plugins/lists/common/constants'; + +import { getCreateMinimalListSchemaMock } from '../../../../plugins/lists/common/schemas/request/create_list_schema.mock'; +import { createListsIndex, deleteListsIndex, removeServerGeneratedProperties } from '../../utils'; + +// eslint-disable-next-line import/no-default-export +export default ({ getService }: FtrProviderContext) => { + const supertest = getService('supertest'); + + describe('read_list_items', () => { + describe('reading list items', () => { + beforeEach(async () => { + await createListsIndex(supertest); + }); + + afterEach(async () => { + await deleteListsIndex(supertest); + }); + + it('should be able to read a single list item using id', async () => { + await supertest + .post(LIST_URL) + .set('kbn-xsrf', 'true') + .send(getCreateMinimalListSchemaMock()) + .expect(200); + + await supertest + .post(LIST_ITEM_URL) + .set('kbn-xsrf', 'true') + .send(getCreateMinimalListItemSchemaMock()) + .expect(200); + + const { body } = await supertest + .get(`${LIST_ITEM_URL}?id=${getCreateMinimalListItemSchemaMock().id}`) + .set('kbn-xsrf', 'true') + .expect(200); + + const bodyToCompare = removeServerGeneratedProperties(body); + expect(bodyToCompare).to.eql(getListItemResponseMockWithoutAutoGeneratedValues()); + }); + + it('should be able to read a single list item with an auto-generated list id', async () => { + await supertest + .post(LIST_URL) + .set('kbn-xsrf', 'true') + .send(getCreateMinimalListSchemaMock()) + .expect(200); + + const { body: createListBody } = await supertest + .post(LIST_ITEM_URL) + .set('kbn-xsrf', 'true') + .send(getCreateMinimalListItemSchemaMock()) + .expect(200); + + const { body } = await supertest + .get(`${LIST_ITEM_URL}?id=${createListBody.id}`) + .set('kbn-xsrf', 'true') + .expect(200); + + const bodyToCompare = removeServerGeneratedProperties(body); + expect(bodyToCompare).to.eql(getListItemResponseMockWithoutAutoGeneratedValues()); + }); + + it('should return 404 if given a fake id', async () => { + await supertest + .post(LIST_URL) + .set('kbn-xsrf', 'true') + .send(getCreateMinimalListSchemaMock()) + .expect(200); + + const { body } = await supertest + .get(`${LIST_ITEM_URL}?id=c1e1b359-7ac1-4e96-bc81-c683c092436f`) + .set('kbn-xsrf', 'true') + .expect(404); + + expect(body).to.eql({ + status_code: 404, + message: 'list item id: "c1e1b359-7ac1-4e96-bc81-c683c092436f" does not exist', + }); + }); + }); + }); +}; diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/read_lists.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/read_lists.ts index 4888e537b2c0f..1328233cc636b 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/read_lists.ts +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/read_lists.ts @@ -39,9 +39,8 @@ export default ({ getService }: FtrProviderContext) => { .expect(200); const { body } = await supertest - .get(`${LIST_URL}?id=some-list-id`) + .get(`${LIST_URL}?id=$${getCreateMinimalListSchemaMock().id}`) .set('kbn-xsrf', 'true') - .send(getCreateMinimalListSchemaMock()) .expect(200); const bodyToCompare = removeServerGeneratedProperties(body); @@ -59,7 +58,6 @@ export default ({ getService }: FtrProviderContext) => { const { body } = await supertest .get(`${LIST_URL}?id=${createListBody.id}`) .set('kbn-xsrf', 'true') - .send(getCreateMinimalListSchemaMock()) .expect(200); const bodyToCompare = removeServerGeneratedProperties(body); diff --git a/x-pack/test/lists_api_integration/utils.ts b/x-pack/test/lists_api_integration/utils.ts index bcadd894bd800..8ce98e93c7a8c 100644 --- a/x-pack/test/lists_api_integration/utils.ts +++ b/x-pack/test/lists_api_integration/utils.ts @@ -11,7 +11,7 @@ import { ListSchema } from '../../plugins/lists/common'; import { LIST_INDEX } from '../../plugins/lists/common/constants'; /** - * Creates the lists index for use inside of beforeEach blocks of tests + * Creates the lists and lists items index for use inside of beforeEach blocks of tests * This will retry 20 times before giving up and hopefully still not interfere with other tests * @param supertest The supertest client library */ From 6ca0244800347b003ceb8752f9220a3af125cb24 Mon Sep 17 00:00:00 2001 From: FrankHassanabad Date: Mon, 10 Aug 2020 12:06:35 -0600 Subject: [PATCH 07/11] Fixed one bug with some refactoring and failed test --- .../security_and_spaces/tests/read_lists.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/read_lists.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/read_lists.ts index 1328233cc636b..7f6645bc41bdb 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/read_lists.ts +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/read_lists.ts @@ -39,7 +39,7 @@ export default ({ getService }: FtrProviderContext) => { .expect(200); const { body } = await supertest - .get(`${LIST_URL}?id=$${getCreateMinimalListSchemaMock().id}`) + .get(`${LIST_URL}?id=${getCreateMinimalListSchemaMock().id}`) .set('kbn-xsrf', 'true') .expect(200); From 055b2196b4b02eaf6478eec87c9db8e453bc24b5 Mon Sep 17 00:00:00 2001 From: FrankHassanabad Date: Mon, 10 Aug 2020 14:59:35 -0600 Subject: [PATCH 08/11] Added more end to end tests for lists --- .../request/create_list_item_schema.mock.ts | 6 + .../request/create_list_schema.mock.ts | 6 + .../request/update_list_item_schema.mock.ts | 10 +- .../server/routes/delete_list_item_route.ts | 2 +- .../tests/create_list_items.ts | 10 +- .../security_and_spaces/tests/create_lists.ts | 10 +- .../tests/delete_list_items.ts | 98 +++++++++++ .../security_and_spaces/tests/delete_lists.ts | 10 +- .../security_and_spaces/tests/find_lists.ts | 8 +- .../security_and_spaces/tests/index.ts | 2 + .../tests/read_list_items.ts | 10 +- .../security_and_spaces/tests/read_lists.ts | 10 +- .../tests/update_list_items.ts | 154 ++++++++++++++++++ .../security_and_spaces/tests/update_lists.ts | 12 +- x-pack/test/lists_api_integration/utils.ts | 17 +- 15 files changed, 341 insertions(+), 24 deletions(-) create mode 100644 x-pack/test/lists_api_integration/security_and_spaces/tests/delete_list_items.ts create mode 100644 x-pack/test/lists_api_integration/security_and_spaces/tests/update_list_items.ts diff --git a/x-pack/plugins/lists/common/schemas/request/create_list_item_schema.mock.ts b/x-pack/plugins/lists/common/schemas/request/create_list_item_schema.mock.ts index f486cde7525ea..5a9e50554865b 100644 --- a/x-pack/plugins/lists/common/schemas/request/create_list_item_schema.mock.ts +++ b/x-pack/plugins/lists/common/schemas/request/create_list_item_schema.mock.ts @@ -15,12 +15,18 @@ export const getCreateListItemSchemaMock = (): CreateListItemSchema => ({ value: VALUE, }); +/** + * Useful for end to end testing + */ export const getCreateMinimalListItemSchemaMock = (): CreateListItemSchema => ({ id: LIST_ITEM_ID, list_id: LIST_ID, value: VALUE, }); +/** + * Useful for end to end testing + */ export const getCreateMinimalListItemSchemaMockWithoutId = (): CreateListItemSchema => ({ list_id: LIST_ID, value: VALUE, diff --git a/x-pack/plugins/lists/common/schemas/request/create_list_schema.mock.ts b/x-pack/plugins/lists/common/schemas/request/create_list_schema.mock.ts index c4e457a43387b..194625c09fb79 100644 --- a/x-pack/plugins/lists/common/schemas/request/create_list_schema.mock.ts +++ b/x-pack/plugins/lists/common/schemas/request/create_list_schema.mock.ts @@ -19,6 +19,9 @@ export const getCreateListSchemaMock = (): CreateListSchema => ({ version: VERSION, }); +/** + * Useful for end to end tests and other mechanisms which want to fill in the values + */ export const getCreateMinimalListSchemaMock = (): CreateListSchema => ({ description: DESCRIPTION, id: LIST_ID, @@ -26,6 +29,9 @@ export const getCreateMinimalListSchemaMock = (): CreateListSchema => ({ type: TYPE, }); +/** + * Useful for end to end tests and other mechanisms which want to fill in the values + */ export const getCreateMinimalListSchemaMockWithoutId = (): CreateListSchema => ({ description: DESCRIPTION, name: NAME, diff --git a/x-pack/plugins/lists/common/schemas/request/update_list_item_schema.mock.ts b/x-pack/plugins/lists/common/schemas/request/update_list_item_schema.mock.ts index c95de1e99b4f0..be8ba3516a754 100644 --- a/x-pack/plugins/lists/common/schemas/request/update_list_item_schema.mock.ts +++ b/x-pack/plugins/lists/common/schemas/request/update_list_item_schema.mock.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { ID, META, VALUE } from '../../constants.mock'; +import { ID, LIST_ITEM_ID, META, VALUE } from '../../constants.mock'; import { UpdateListItemSchema } from './update_list_item_schema'; @@ -13,3 +13,11 @@ export const getUpdateListItemSchemaMock = (): UpdateListItemSchema => ({ meta: META, value: VALUE, }); + +/** + * Useful for end to end testing + */ +export const getUpdateMinimalListItemSchemaMock = (): UpdateListItemSchema => ({ + id: LIST_ITEM_ID, + value: VALUE, +}); diff --git a/x-pack/plugins/lists/server/routes/delete_list_item_route.ts b/x-pack/plugins/lists/server/routes/delete_list_item_route.ts index 2284068552485..fa1adf8a39ed8 100644 --- a/x-pack/plugins/lists/server/routes/delete_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/delete_list_item_route.ts @@ -33,7 +33,7 @@ export const deleteListItemRoute = (router: IRouter): void => { const deleted = await lists.deleteListItem({ id }); if (deleted == null) { return siemResponse.error({ - body: `list item with id: "${id}" item not found`, + body: `list item with id: "${id}" not found`, statusCode: 404, }); } else { diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/create_list_items.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/create_list_items.ts index 16e22f3bf4de3..906e9a9ef4456 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/create_list_items.ts +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/create_list_items.ts @@ -17,7 +17,11 @@ import { } from '../../../../plugins/lists/common/schemas/request/create_list_item_schema.mock'; import { getListItemResponseMockWithoutAutoGeneratedValues } from '../../../../plugins/lists/common/schemas/response/list_item_schema.mock'; -import { createListsIndex, deleteListsIndex, removeServerGeneratedProperties } from '../../utils'; +import { + createListsIndex, + deleteListsIndex, + removeListItemServerGeneratedProperties, +} from '../../utils'; // eslint-disable-next-line import/no-default-export export default ({ getService }: FtrProviderContext) => { @@ -61,7 +65,7 @@ export default ({ getService }: FtrProviderContext) => { .send(getCreateMinimalListItemSchemaMock()) .expect(200); - const bodyToCompare = removeServerGeneratedProperties(body); + const bodyToCompare = removeListItemServerGeneratedProperties(body); expect(bodyToCompare).to.eql(getListItemResponseMockWithoutAutoGeneratedValues()); }); @@ -78,7 +82,7 @@ export default ({ getService }: FtrProviderContext) => { .send(getCreateMinimalListItemSchemaMockWithoutId()) .expect(200); - const bodyToCompare = removeServerGeneratedProperties(body); + const bodyToCompare = removeListItemServerGeneratedProperties(body); expect(bodyToCompare).to.eql(getListItemResponseMockWithoutAutoGeneratedValues()); }); diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/create_lists.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/create_lists.ts index 99766ce20c067..b9d61eeacfee8 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/create_lists.ts +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/create_lists.ts @@ -14,7 +14,11 @@ import { } from '../../../../plugins/lists/common/schemas/request/create_list_schema.mock'; import { getListResponseMockWithoutAutoGeneratedValues } from '../../../../plugins/lists/common/schemas/response/list_schema.mock'; -import { createListsIndex, deleteListsIndex, removeServerGeneratedProperties } from '../../utils'; +import { + createListsIndex, + deleteListsIndex, + removeListServerGeneratedProperties, +} from '../../utils'; // eslint-disable-next-line import/no-default-export export default ({ getService }: FtrProviderContext) => { @@ -53,7 +57,7 @@ export default ({ getService }: FtrProviderContext) => { .send(getCreateMinimalListSchemaMock()) .expect(200); - const bodyToCompare = removeServerGeneratedProperties(body); + const bodyToCompare = removeListServerGeneratedProperties(body); expect(bodyToCompare).to.eql(getListResponseMockWithoutAutoGeneratedValues()); }); @@ -64,7 +68,7 @@ export default ({ getService }: FtrProviderContext) => { .send(getCreateMinimalListSchemaMockWithoutId()) .expect(200); - const bodyToCompare = removeServerGeneratedProperties(body); + const bodyToCompare = removeListServerGeneratedProperties(body); expect(bodyToCompare).to.eql(getListResponseMockWithoutAutoGeneratedValues()); }); diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/delete_list_items.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/delete_list_items.ts new file mode 100644 index 0000000000000..83ba9728efdc9 --- /dev/null +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/delete_list_items.ts @@ -0,0 +1,98 @@ +/* + * 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 { getListItemResponseMockWithoutAutoGeneratedValues } from '../../../../plugins/lists/common/schemas/response/list_item_schema.mock'; +import { getCreateMinimalListItemSchemaMock } from '../../../../plugins/lists/common/schemas/request/create_list_item_schema.mock'; +import { FtrProviderContext } from '../../common/ftr_provider_context'; +import { LIST_URL, LIST_ITEM_URL } from '../../../../plugins/lists/common/constants'; + +import { getCreateMinimalListSchemaMock } from '../../../../plugins/lists/common/schemas/request/create_list_schema.mock'; +import { + createListsIndex, + deleteListsIndex, + removeListItemServerGeneratedProperties, +} from '../../utils'; + +// eslint-disable-next-line import/no-default-export +export default ({ getService }: FtrProviderContext) => { + const supertest = getService('supertest'); + + describe('delete_list_items', () => { + describe('deleting list items', () => { + beforeEach(async () => { + await createListsIndex(supertest); + }); + + afterEach(async () => { + await deleteListsIndex(supertest); + }); + + it('should delete a single list item with a list item id', async () => { + // create a list + await supertest + .post(LIST_URL) + .set('kbn-xsrf', 'true') + .send(getCreateMinimalListSchemaMock()) + .expect(200); + + // create a list item + await supertest + .post(LIST_ITEM_URL) + .set('kbn-xsrf', 'true') + .send(getCreateMinimalListItemSchemaMock()) + .expect(200); + + // delete the list item by its list item id + const { body } = await supertest + .delete(`${LIST_ITEM_URL}?id=${getCreateMinimalListItemSchemaMock().id}`) + .set('kbn-xsrf', 'true') + .expect(200); + + const bodyToCompare = removeListItemServerGeneratedProperties(body); + expect(bodyToCompare).to.eql(getListItemResponseMockWithoutAutoGeneratedValues()); + }); + + it('should delete a single list using an auto generated id', async () => { + // create a list + await supertest + .post(LIST_URL) + .set('kbn-xsrf', 'true') + .send(getCreateMinimalListSchemaMock()) + .expect(200); + + // create a list item + const { body: bodyWithCreateListItem } = await supertest + .post(LIST_ITEM_URL) + .set('kbn-xsrf', 'true') + .send(getCreateMinimalListItemSchemaMock()) + .expect(200); + + // delete that list by its auto-generated id + const { body } = await supertest + .delete(`${LIST_ITEM_URL}?id=${bodyWithCreateListItem.id}`) + .set('kbn-xsrf', 'true') + .expect(200); + + const bodyToCompare = removeListItemServerGeneratedProperties(body); + expect(bodyToCompare).to.eql(getListItemResponseMockWithoutAutoGeneratedValues()); + }); + + it('should return an error if the id does not exist when trying to delete it', async () => { + const { body } = await supertest + .delete(`${LIST_ITEM_URL}?id=c1e1b359-7ac1-4e96-bc81-c683c092436f`) + .set('kbn-xsrf', 'true') + .expect(404); + + expect(body).to.eql({ + message: 'list item with id: "c1e1b359-7ac1-4e96-bc81-c683c092436f" not found', + status_code: 404, + }); + }); + }); + }); +}; diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/delete_lists.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/delete_lists.ts index a5a25cf4bd043..3703e1b6ca306 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/delete_lists.ts +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/delete_lists.ts @@ -10,7 +10,11 @@ import { FtrProviderContext } from '../../common/ftr_provider_context'; import { LIST_URL } from '../../../../plugins/lists/common/constants'; import { getCreateMinimalListSchemaMock } from '../../../../plugins/lists/common/schemas/request/create_list_schema.mock'; -import { createListsIndex, deleteListsIndex, removeServerGeneratedProperties } from '../../utils'; +import { + createListsIndex, + deleteListsIndex, + removeListServerGeneratedProperties, +} from '../../utils'; import { getListResponseMockWithoutAutoGeneratedValues } from '../../../../plugins/lists/common/schemas/response/list_schema.mock'; // eslint-disable-next-line import/no-default-export @@ -41,7 +45,7 @@ export default ({ getService }: FtrProviderContext) => { .set('kbn-xsrf', 'true') .expect(200); - const bodyToCompare = removeServerGeneratedProperties(body); + const bodyToCompare = removeListServerGeneratedProperties(body); expect(bodyToCompare).to.eql(getListResponseMockWithoutAutoGeneratedValues()); }); @@ -59,7 +63,7 @@ export default ({ getService }: FtrProviderContext) => { .set('kbn-xsrf', 'true') .expect(200); - const bodyToCompare = removeServerGeneratedProperties(body); + const bodyToCompare = removeListServerGeneratedProperties(body); expect(bodyToCompare).to.eql(getListResponseMockWithoutAutoGeneratedValues()); }); diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/find_lists.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/find_lists.ts index efd240a89b8ae..7efe28a0b01a1 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/find_lists.ts +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/find_lists.ts @@ -10,7 +10,11 @@ import { FtrProviderContext } from '../../common/ftr_provider_context'; import { LIST_URL } from '../../../../plugins/lists/common/constants'; import { getCreateMinimalListSchemaMock } from '../../../../plugins/lists/common/schemas/request/create_list_schema.mock'; -import { createListsIndex, deleteListsIndex, removeServerGeneratedProperties } from '../../utils'; +import { + createListsIndex, + deleteListsIndex, + removeListServerGeneratedProperties, +} from '../../utils'; import { getListResponseMockWithoutAutoGeneratedValues } from '../../../../plugins/lists/common/schemas/response/list_schema.mock'; // eslint-disable-next-line import/no-default-export @@ -58,7 +62,7 @@ export default ({ getService }: FtrProviderContext): void => { .send() .expect(200); - body.data = [removeServerGeneratedProperties(body.data[0])]; + body.data = [removeListServerGeneratedProperties(body.data[0])]; // cursor is a constant changing value so we have to delete it as well. delete body.cursor; expect(body).to.eql({ diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/index.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/index.ts index 2141d8287429c..dd77c9f2f7557 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/index.ts +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/index.ts @@ -16,7 +16,9 @@ export default ({ loadTestFile }: FtrProviderContext): void => { loadTestFile(require.resolve('./read_lists')); loadTestFile(require.resolve('./read_list_items')); loadTestFile(require.resolve('./update_lists')); + loadTestFile(require.resolve('./update_list_items')); loadTestFile(require.resolve('./delete_lists')); + loadTestFile(require.resolve('./delete_list_items')); loadTestFile(require.resolve('./find_lists')); }); }; diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/read_list_items.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/read_list_items.ts index 7e4dbb3b9d4cb..5469973d70e50 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/read_list_items.ts +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/read_list_items.ts @@ -12,7 +12,11 @@ import { FtrProviderContext } from '../../common/ftr_provider_context'; import { LIST_URL, LIST_ITEM_URL } from '../../../../plugins/lists/common/constants'; import { getCreateMinimalListSchemaMock } from '../../../../plugins/lists/common/schemas/request/create_list_schema.mock'; -import { createListsIndex, deleteListsIndex, removeServerGeneratedProperties } from '../../utils'; +import { + createListsIndex, + deleteListsIndex, + removeListItemServerGeneratedProperties, +} from '../../utils'; // eslint-disable-next-line import/no-default-export export default ({ getService }: FtrProviderContext) => { @@ -46,7 +50,7 @@ export default ({ getService }: FtrProviderContext) => { .set('kbn-xsrf', 'true') .expect(200); - const bodyToCompare = removeServerGeneratedProperties(body); + const bodyToCompare = removeListItemServerGeneratedProperties(body); expect(bodyToCompare).to.eql(getListItemResponseMockWithoutAutoGeneratedValues()); }); @@ -68,7 +72,7 @@ export default ({ getService }: FtrProviderContext) => { .set('kbn-xsrf', 'true') .expect(200); - const bodyToCompare = removeServerGeneratedProperties(body); + const bodyToCompare = removeListItemServerGeneratedProperties(body); expect(bodyToCompare).to.eql(getListItemResponseMockWithoutAutoGeneratedValues()); }); diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/read_lists.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/read_lists.ts index 7f6645bc41bdb..c3c8cb39d023b 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/read_lists.ts +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/read_lists.ts @@ -13,7 +13,11 @@ import { getCreateMinimalListSchemaMock, getCreateMinimalListSchemaMockWithoutId, } from '../../../../plugins/lists/common/schemas/request/create_list_schema.mock'; -import { createListsIndex, deleteListsIndex, removeServerGeneratedProperties } from '../../utils'; +import { + createListsIndex, + deleteListsIndex, + removeListServerGeneratedProperties, +} from '../../utils'; import { getListResponseMockWithoutAutoGeneratedValues } from '../../../../plugins/lists/common/schemas/response/list_schema.mock'; // eslint-disable-next-line import/no-default-export @@ -43,7 +47,7 @@ export default ({ getService }: FtrProviderContext) => { .set('kbn-xsrf', 'true') .expect(200); - const bodyToCompare = removeServerGeneratedProperties(body); + const bodyToCompare = removeListServerGeneratedProperties(body); expect(bodyToCompare).to.eql(getListResponseMockWithoutAutoGeneratedValues()); }); @@ -60,7 +64,7 @@ export default ({ getService }: FtrProviderContext) => { .set('kbn-xsrf', 'true') .expect(200); - const bodyToCompare = removeServerGeneratedProperties(body); + const bodyToCompare = removeListServerGeneratedProperties(body); expect(bodyToCompare).to.eql(getListResponseMockWithoutAutoGeneratedValues()); }); diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/update_list_items.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/update_list_items.ts new file mode 100644 index 0000000000000..3ff496216eb71 --- /dev/null +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/update_list_items.ts @@ -0,0 +1,154 @@ +/* + * 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 { getListItemResponseMockWithoutAutoGeneratedValues } from '../../../../plugins/lists/common/schemas/response/list_item_schema.mock'; +import { getCreateMinimalListItemSchemaMock } from '../../../../plugins/lists/common/schemas/request/create_list_item_schema.mock'; +import { FtrProviderContext } from '../../common/ftr_provider_context'; +import { LIST_URL, LIST_ITEM_URL } from '../../../../plugins/lists/common/constants'; + +import { getCreateMinimalListSchemaMock } from '../../../../plugins/lists/common/schemas/request/create_list_schema.mock'; +import { + createListsIndex, + deleteListsIndex, + removeListItemServerGeneratedProperties, +} from '../../utils'; +import { getUpdateMinimalListItemSchemaMock } from '../../../../plugins/lists/common/schemas/request/update_list_item_schema.mock'; +import { + UpdateListItemSchema, + CreateListItemSchema, + ListItemSchema, +} from '../../../../plugins/lists/common/schemas'; + +// eslint-disable-next-line import/no-default-export +export default ({ getService }: FtrProviderContext) => { + const supertest = getService('supertest'); + + describe('update_list_items', () => { + describe('update list items', () => { + beforeEach(async () => { + await createListsIndex(supertest); + }); + + afterEach(async () => { + await deleteListsIndex(supertest); + }); + + it('should update a single list item property of value using an id', async () => { + // create a simple list + await supertest + .post(LIST_URL) + .set('kbn-xsrf', 'true') + .send(getCreateMinimalListSchemaMock()) + .expect(200); + + // create a simple list item + await supertest + .post(LIST_ITEM_URL) + .set('kbn-xsrf', 'true') + .send(getCreateMinimalListItemSchemaMock()) + .expect(200); + + // update a simple list item's value + const updatedListItem: UpdateListItemSchema = { + ...getUpdateMinimalListItemSchemaMock(), + value: '192.168.0.2', + }; + + const { body } = await supertest + .put(LIST_ITEM_URL) + .set('kbn-xsrf', 'true') + .send(updatedListItem) + .expect(200); + + const outputListItem: Partial = { + ...getListItemResponseMockWithoutAutoGeneratedValues(), + value: '192.168.0.2', + }; + const bodyToCompare = removeListItemServerGeneratedProperties(body); + expect(bodyToCompare).to.eql(outputListItem); + }); + + it('should update a single list item of value using an auto-generated id of both list and list item', async () => { + const { id, ...listNoId } = getCreateMinimalListSchemaMock(); + // create a simple list with no id which will use an auto-generated id + const { body: createListBody } = await supertest + .post(LIST_URL) + .set('kbn-xsrf', 'true') + .send(listNoId) + .expect(200); + + // create a simple list item also with an auto-generated id using the list's auto-generated id + const listItem: CreateListItemSchema = { + ...getCreateMinimalListItemSchemaMock(), + list_id: createListBody.id, + }; + const { body: createListItemBody } = await supertest + .post(LIST_ITEM_URL) + .set('kbn-xsrf', 'true') + .send(listItem) + .expect(200); + + // update a simple list item's value + const updatedList: UpdateListItemSchema = { + ...getUpdateMinimalListItemSchemaMock(), + id: createListItemBody.id, + value: '192.168.0.2', + }; + const { body } = await supertest + .put(LIST_ITEM_URL) + .set('kbn-xsrf', 'true') + .send(updatedList) + .expect(200); + + const outputListItem: Partial = { + ...getListItemResponseMockWithoutAutoGeneratedValues(), + value: '192.168.0.2', + }; + const bodyToCompare = { + ...removeListItemServerGeneratedProperties(body), + list_id: outputListItem.list_id, + }; + expect(bodyToCompare).to.eql(outputListItem); + }); + + it('should give a 404 if it is given a fake id', async () => { + // create a simple list + await supertest + .post(LIST_URL) + .set('kbn-xsrf', 'true') + .send(getCreateMinimalListSchemaMock()) + .expect(200); + + // create a simple list item + await supertest + .post(LIST_ITEM_URL) + .set('kbn-xsrf', 'true') + .send(getCreateMinimalListItemSchemaMock()) + .expect(200); + + // update a simple list item's value + const updatedListItem: UpdateListItemSchema = { + ...getUpdateMinimalListItemSchemaMock(), + id: 'some-other-id', + value: '192.168.0.2', + }; + + const { body } = await supertest + .put(LIST_ITEM_URL) + .set('kbn-xsrf', 'true') + .send(updatedListItem) + .expect(404); + + expect(body).to.eql({ + status_code: 404, + message: 'list item id: "some-other-id" not found', + }); + }); + }); + }); +}; diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/update_lists.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/update_lists.ts index 242705731d19d..04d77ffe21370 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/update_lists.ts +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/update_lists.ts @@ -10,7 +10,11 @@ import { FtrProviderContext } from '../../common/ftr_provider_context'; import { LIST_URL } from '../../../../plugins/lists/common/constants'; import { getCreateMinimalListSchemaMock } from '../../../../plugins/lists/common/schemas/request/create_list_schema.mock'; -import { createListsIndex, deleteListsIndex, removeServerGeneratedProperties } from '../../utils'; +import { + createListsIndex, + deleteListsIndex, + removeListServerGeneratedProperties, +} from '../../utils'; import { getListResponseMockWithoutAutoGeneratedValues } from '../../../../plugins/lists/common/schemas/response/list_schema.mock'; import { getUpdateMinimalListSchemaMock } from '../../../../plugins/lists/common/schemas/request/update_list_schema.mock'; import { UpdateListSchema, ListSchema } from '../../../../plugins/lists/common/schemas'; @@ -54,7 +58,7 @@ export default ({ getService }: FtrProviderContext) => { name: 'some other name', version: 2, }; - const bodyToCompare = removeServerGeneratedProperties(body); + const bodyToCompare = removeListServerGeneratedProperties(body); expect(bodyToCompare).to.eql(outputList); }); @@ -84,7 +88,7 @@ export default ({ getService }: FtrProviderContext) => { name: 'some other name', version: 2, }; - const bodyToCompare = removeServerGeneratedProperties(body); + const bodyToCompare = removeListServerGeneratedProperties(body); expect(bodyToCompare).to.eql(outputList); }); @@ -112,7 +116,7 @@ export default ({ getService }: FtrProviderContext) => { version: 2, }; - const bodyToCompare = removeServerGeneratedProperties(body); + const bodyToCompare = removeListServerGeneratedProperties(body); expect(bodyToCompare).to.eql(outputList); }); diff --git a/x-pack/test/lists_api_integration/utils.ts b/x-pack/test/lists_api_integration/utils.ts index 8ce98e93c7a8c..d3c894c2ab546 100644 --- a/x-pack/test/lists_api_integration/utils.ts +++ b/x-pack/test/lists_api_integration/utils.ts @@ -7,6 +7,7 @@ import { SuperTest } from 'supertest'; import supertestAsPromised from 'supertest-as-promised'; +import { ListItemSchema } from '../../plugins/lists/common/schemas'; import { ListSchema } from '../../plugins/lists/common'; import { LIST_INDEX } from '../../plugins/lists/common/constants'; @@ -62,7 +63,21 @@ export const deleteListsIndex = async ( * This will remove server generated properties such as date times, etc... * @param list List to pass in to remove typical server generated properties */ -export const removeServerGeneratedProperties = (list: Partial): Partial => { +export const removeListServerGeneratedProperties = ( + list: Partial +): Partial => { + /* eslint-disable-next-line @typescript-eslint/naming-convention */ + const { created_at, updated_at, id, tie_breaker_id, _version, ...removedProperties } = list; + return removedProperties; +}; + +/** + * This will remove server generated properties such as date times, etc... + * @param list List to pass in to remove typical server generated properties + */ +export const removeListItemServerGeneratedProperties = ( + list: Partial +): Partial => { /* eslint-disable-next-line @typescript-eslint/naming-convention */ const { created_at, updated_at, id, tie_breaker_id, _version, ...removedProperties } = list; return removedProperties; From acc8a42e64443af1b8c88ca18c5b691e714b432d Mon Sep 17 00:00:00 2001 From: FrankHassanabad Date: Mon, 10 Aug 2020 21:40:21 -0600 Subject: [PATCH 09/11] Updated tests to have import and fixed a few bugs with the import being able to import when there is not indexes created first --- .../request/import_list_item_schema.mock.ts | 9 ++ .../server/routes/import_list_item_route.ts | 7 ++ .../tests/import_list_items.ts | 112 ++++++++++++++++++ .../security_and_spaces/tests/index.ts | 1 + x-pack/test/lists_api_integration/utils.ts | 26 ++++ 5 files changed, 155 insertions(+) create mode 100644 x-pack/test/lists_api_integration/security_and_spaces/tests/import_list_items.ts diff --git a/x-pack/plugins/lists/common/schemas/request/import_list_item_schema.mock.ts b/x-pack/plugins/lists/common/schemas/request/import_list_item_schema.mock.ts index 69e4d2f8293c7..57bb66f746f67 100644 --- a/x-pack/plugins/lists/common/schemas/request/import_list_item_schema.mock.ts +++ b/x-pack/plugins/lists/common/schemas/request/import_list_item_schema.mock.ts @@ -9,3 +9,12 @@ import { ImportListItemSchema } from './import_list_item_schema'; export const getImportListItemSchemaMock = (): ImportListItemSchema => ({ file: {}, }); + +/** + * This is useful for end to end tests, it will return a buffer given a string array + * of things to import. + * @param input Array of strings of things to import + */ +export const getImportListItemAsBuffer = (input: string[]): Buffer => { + return Buffer.from(input.join('\r\n')); +}; diff --git a/x-pack/plugins/lists/server/routes/import_list_item_route.ts b/x-pack/plugins/lists/server/routes/import_list_item_route.ts index ce5fdaccae251..d46c943d95fe9 100644 --- a/x-pack/plugins/lists/server/routes/import_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/import_list_item_route.ts @@ -41,6 +41,13 @@ export const importListItemRoute = (router: IRouter, config: ConfigType): void = const stream = createStreamFromBuffer(request.body); const { deserializer, list_id: listId, serializer, type } = request.query; const lists = getListClient(context); + const listExists = await lists.getListIndexExists(); + if (!listExists) { + return siemResponse.error({ + body: `To import a list item, the index must exist first. Index "${lists.getListIndex()}" does not exist`, + statusCode: 400, + }); + } if (listId != null) { const list = await lists.getList({ id: listId }); if (list == null) { diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/import_list_items.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/import_list_items.ts new file mode 100644 index 0000000000000..4befb6bbaf050 --- /dev/null +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/import_list_items.ts @@ -0,0 +1,112 @@ +/* + * 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 { ListItemSchema } from '../../../../plugins/lists/common/schemas'; +import { getListItemResponseMockWithoutAutoGeneratedValues } from '../../../../plugins/lists/common/schemas/response/list_item_schema.mock'; +import { ListSchema } from '../../../../plugins/lists/common'; +import { getListResponseMockWithoutAutoGeneratedValues } from '../../../../plugins/lists/common/schemas/response/list_schema.mock'; +import { FtrProviderContext } from '../../common/ftr_provider_context'; + +import { LIST_ITEM_URL } from '../../../../plugins/lists/common/constants'; + +import { + createListsIndex, + deleteListsIndex, + removeListServerGeneratedProperties, + removeListItemServerGeneratedProperties, + waitFor, +} from '../../utils'; + +import { getImportListItemAsBuffer } from '../../../../plugins/lists/common/schemas/request/import_list_item_schema.mock'; + +// eslint-disable-next-line import/no-default-export +export default ({ getService }: FtrProviderContext): void => { + const supertest = getService('supertest'); + + describe('import_list_items', () => { + describe('importing list items without an index', () => { + it('should not import a list item if the index does not exist yet', async () => { + const { body } = await supertest + .post(`${LIST_ITEM_URL}/_import?type=ip`) + .set('kbn-xsrf', 'true') + .attach('file', getImportListItemAsBuffer(['127.0.0.1', '127.0.0.2']), 'list_items.txt') + .expect('Content-Type', 'application/json; charset=utf-8') + .expect(400); + + expect(body).to.eql({ + status_code: 400, + message: + 'To import a list item, the index must exist first. Index ".lists-default" does not exist', + }); + }); + }); + + describe('importing rules with an index', () => { + beforeEach(async () => { + await createListsIndex(supertest); + }); + + afterEach(async () => { + await deleteListsIndex(supertest); + }); + + it('should set the response content types to be expected when importing two items', async () => { + await supertest + .post(`${LIST_ITEM_URL}/_import?type=ip`) + .set('kbn-xsrf', 'true') + .attach('file', getImportListItemAsBuffer(['127.0.0.1', '127.0.0.2']), 'list_items.txt') + .expect('Content-Type', 'application/json; charset=utf-8') + .expect(200); + }); + + it('should report that it imported a simple list successfully', async () => { + const { body } = await supertest + .post(`${LIST_ITEM_URL}/_import?type=ip`) + .set('kbn-xsrf', 'true') + .attach('file', getImportListItemAsBuffer(['127.0.0.1', '127.0.0.2']), 'list_items.txt') + .expect('Content-Type', 'application/json; charset=utf-8') + .expect(200); + + const bodyToCompare = removeListServerGeneratedProperties(body); + const outputtedList: Partial = { + ...getListResponseMockWithoutAutoGeneratedValues(), + name: 'list_items.txt', + description: 'File uploaded from file system of list_items.txt', + }; + expect(bodyToCompare).to.eql(outputtedList); + }); + + it('should be able to read imported list items back out correctly', async () => { + await supertest + .post(`${LIST_ITEM_URL}/_import?type=ip`) + .set('kbn-xsrf', 'true') + .attach('file', getImportListItemAsBuffer(['127.0.0.1', '127.0.0.2']), 'list_items.txt') + .expect(200); + + // Although we try to be aggressive with waitFor in the lists code base, there is still not guarantees + // that we will have the data just yet so we have to do a waitFor here for when it shows up + await waitFor(async () => { + const { status } = await supertest + .get(`${LIST_ITEM_URL}?list_id=list_items.txt&value=127.0.0.1`) + .send(); + return status !== 404; + }); + const { body } = await supertest + .get(`${LIST_ITEM_URL}?list_id=list_items.txt&value=127.0.0.1`) + .send() + .expect(200); + + const bodyToCompare = removeListItemServerGeneratedProperties(body[0]); + const outputtedList: Partial = { + ...getListItemResponseMockWithoutAutoGeneratedValues(), + list_id: 'list_items.txt', + }; + expect(bodyToCompare).to.eql(outputtedList); + }); + }); + }); +}; diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/index.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/index.ts index dd77c9f2f7557..e351293cff5ed 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/index.ts +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/index.ts @@ -20,5 +20,6 @@ export default ({ loadTestFile }: FtrProviderContext): void => { loadTestFile(require.resolve('./delete_lists')); loadTestFile(require.resolve('./delete_list_items')); loadTestFile(require.resolve('./find_lists')); + loadTestFile(require.resolve('./import_list_items')); }); }; diff --git a/x-pack/test/lists_api_integration/utils.ts b/x-pack/test/lists_api_integration/utils.ts index d3c894c2ab546..4f231ee935004 100644 --- a/x-pack/test/lists_api_integration/utils.ts +++ b/x-pack/test/lists_api_integration/utils.ts @@ -82,3 +82,29 @@ export const removeListItemServerGeneratedProperties = ( const { created_at, updated_at, id, tie_breaker_id, _version, ...removedProperties } = list; return removedProperties; }; + +// Similar to ReactJs's waitFor from here: https://testing-library.com/docs/dom-testing-library/api-async#waitfor +export const waitFor = async ( + functionToTest: () => Promise, + maxTimeout: number = 5000, + timeoutWait: number = 10 +) => { + await new Promise(async (resolve, reject) => { + let found = false; + let numberOfTries = 0; + while (!found && numberOfTries < Math.floor(maxTimeout / timeoutWait)) { + const itPasses = await functionToTest(); + if (itPasses) { + found = true; + } else { + numberOfTries++; + } + await new Promise((resolveTimeout) => setTimeout(resolveTimeout, timeoutWait)); + } + if (found) { + resolve(); + } else { + reject(new Error('timed out waiting for function condition to be true')); + } + }); +}; From 3e0e4bf85094a61a4c128b62d292807778adca1e Mon Sep 17 00:00:00 2001 From: FrankHassanabad Date: Mon, 10 Aug 2020 22:15:41 -0600 Subject: [PATCH 10/11] Added find_list_items unit tests --- .../tests/find_list_items.ts | 116 ++++++++++++++++++ .../security_and_spaces/tests/index.ts | 1 + 2 files changed, 117 insertions(+) create mode 100644 x-pack/test/lists_api_integration/security_and_spaces/tests/find_list_items.ts diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/find_list_items.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/find_list_items.ts new file mode 100644 index 0000000000000..4c1f3dfdb6703 --- /dev/null +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/find_list_items.ts @@ -0,0 +1,116 @@ +/* + * 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 { LIST_ITEM_ID, LIST_ID } from '../../../../plugins/lists/common/constants.mock'; +import { getListItemResponseMockWithoutAutoGeneratedValues } from '../../../../plugins/lists/common/schemas/response/list_item_schema.mock'; +import { getCreateMinimalListItemSchemaMock } from '../../../../plugins/lists/common/schemas/request/create_list_item_schema.mock'; +import { FtrProviderContext } from '../../common/ftr_provider_context'; +import { LIST_URL, LIST_ITEM_URL } from '../../../../plugins/lists/common/constants'; + +import { getCreateMinimalListSchemaMock } from '../../../../plugins/lists/common/schemas/request/create_list_schema.mock'; +import { + createListsIndex, + deleteListsIndex, + removeListItemServerGeneratedProperties, +} from '../../utils'; + +// eslint-disable-next-line import/no-default-export +export default ({ getService }: FtrProviderContext): void => { + const supertest = getService('supertest'); + + describe('find_list_items', () => { + describe('find list items', () => { + beforeEach(async () => { + await createListsIndex(supertest); + }); + + afterEach(async () => { + await deleteListsIndex(supertest); + }); + + it('should give a validation error if the list_id is not supplied', async () => { + const { body } = await supertest + .get(`${LIST_ITEM_URL}/_find`) + .set('kbn-xsrf', 'true') + .send() + .expect(400); + + expect(body).to.eql({ + error: 'Bad Request', + message: '[request query]: Invalid value "undefined" supplied to "list_id"', + statusCode: 400, + }); + }); + + it('should give a 404 if the list has not been created yet', async () => { + const { body } = await supertest + .get(`${LIST_ITEM_URL}/_find?list_id=${LIST_ITEM_ID}`) + .set('kbn-xsrf', 'true') + .send() + .expect(404); + + expect(body).to.eql({ + message: 'list id: "some-list-item-id" does not exist', + status_code: 404, + }); + }); + + it('should return an empty find body correctly if no list items are loaded', async () => { + await supertest + .post(LIST_URL) + .set('kbn-xsrf', 'true') + .send(getCreateMinimalListSchemaMock()) + .expect(200); + + const { body } = await supertest + .get(`${LIST_ITEM_URL}/_find?list_id=${LIST_ID}`) + .set('kbn-xsrf', 'true') + .send() + .expect(200); + + expect(body).to.eql({ + cursor: 'WzBd', + data: [], + page: 1, + per_page: 20, + total: 0, + }); + }); + + it('should return a single list item when a single list item is loaded from a find with defaults added', async () => { + await supertest + .post(LIST_URL) + .set('kbn-xsrf', 'true') + .send(getCreateMinimalListSchemaMock()) + .expect(200); + + await supertest + .post(LIST_ITEM_URL) + .set('kbn-xsrf', 'true') + .send(getCreateMinimalListItemSchemaMock()) + .expect(200); + + const { body } = await supertest + .get(`${LIST_ITEM_URL}/_find?list_id=${LIST_ID}`) + .set('kbn-xsrf', 'true') + .send() + .expect(200); + + body.data = [removeListItemServerGeneratedProperties(body.data[0])]; + // cursor is a constant changing value so we have to delete it as well. + delete body.cursor; + expect(body).to.eql({ + data: [getListItemResponseMockWithoutAutoGeneratedValues()], + page: 1, + per_page: 20, + total: 1, + }); + }); + }); + }); +}; diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/index.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/index.ts index e351293cff5ed..f131541ce439d 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/index.ts +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/index.ts @@ -20,6 +20,7 @@ export default ({ loadTestFile }: FtrProviderContext): void => { loadTestFile(require.resolve('./delete_lists')); loadTestFile(require.resolve('./delete_list_items')); loadTestFile(require.resolve('./find_lists')); + loadTestFile(require.resolve('./find_list_items')); loadTestFile(require.resolve('./import_list_items')); }); }; From 940d5829ababf3910150b33b25fc0e077a5c1da8 Mon Sep 17 00:00:00 2001 From: FrankHassanabad Date: Mon, 10 Aug 2020 22:54:09 -0600 Subject: [PATCH 11/11] Added export_list_items end to end tests --- .../tests/export_list_items.ts | 104 ++++++++++++++++++ .../security_and_spaces/tests/index.ts | 1 + x-pack/test/lists_api_integration/utils.ts | 16 +++ 3 files changed, 121 insertions(+) create mode 100644 x-pack/test/lists_api_integration/security_and_spaces/tests/export_list_items.ts diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/export_list_items.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/export_list_items.ts new file mode 100644 index 0000000000000..6fe783fc497f2 --- /dev/null +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/export_list_items.ts @@ -0,0 +1,104 @@ +/* + * 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 { getCreateMinimalListItemSchemaMock } from '../../../../plugins/lists/common/schemas/request/create_list_item_schema.mock'; +import { getCreateMinimalListSchemaMock } from '../../../../plugins/lists/common/schemas/request/create_list_schema.mock'; +import { LIST_ID, NAME } from '../../../../plugins/lists/common/constants.mock'; +import { CreateListItemSchema } from '../../../../plugins/lists/common/schemas'; +import { FtrProviderContext } from '../../common/ftr_provider_context'; + +import { LIST_ITEM_URL, LIST_URL } from '../../../../plugins/lists/common/constants'; + +import { createListsIndex, deleteListsIndex, binaryToString } from '../../utils'; + +// eslint-disable-next-line import/no-default-export +export default ({ getService }: FtrProviderContext): void => { + const supertest = getService('supertest'); + + describe('export_list_items', () => { + describe('exporting lists', () => { + beforeEach(async () => { + await createListsIndex(supertest); + }); + + afterEach(async () => { + await deleteListsIndex(supertest); + }); + + it('should set the response content types to be expected', async () => { + await supertest + .post(LIST_URL) + .set('kbn-xsrf', 'true') + .send(getCreateMinimalListSchemaMock()) + .expect(200); + + await supertest + .post(LIST_ITEM_URL) + .set('kbn-xsrf', 'true') + .send(getCreateMinimalListItemSchemaMock()) + .expect(200); + + await supertest + .post(`${LIST_ITEM_URL}/_export?list_id=${LIST_ID}`) + .set('kbn-xsrf', 'true') + .expect('Content-Disposition', `attachment; filename="${NAME}"`) + .expect(200); + }); + + it('should export a single list item with a list id', async () => { + await supertest + .post(LIST_URL) + .set('kbn-xsrf', 'true') + .send(getCreateMinimalListSchemaMock()) + .expect(200); + + await supertest + .post(LIST_ITEM_URL) + .set('kbn-xsrf', 'true') + .send(getCreateMinimalListItemSchemaMock()) + .expect(200); + + const { body } = await supertest + .post(`${LIST_ITEM_URL}/_export?list_id=${LIST_ID}`) + .set('kbn-xsrf', 'true') + .expect(200) + .parse(binaryToString); + + expect(body.toString()).to.eql('127.0.0.1\n'); + }); + + it('should export two list items with a list id', async () => { + await supertest + .post(LIST_URL) + .set('kbn-xsrf', 'true') + .send(getCreateMinimalListSchemaMock()) + .expect(200); + + await supertest + .post(LIST_ITEM_URL) + .set('kbn-xsrf', 'true') + .send(getCreateMinimalListItemSchemaMock()) + .expect(200); + + const secondList: CreateListItemSchema = { + ...getCreateMinimalListItemSchemaMock(), + id: 'list-item-2', + value: '127.0.0.2', + }; + await supertest.post(LIST_ITEM_URL).set('kbn-xsrf', 'true').send(secondList).expect(200); + + const { body } = await supertest + .post(`${LIST_ITEM_URL}/_export?list_id=${LIST_ID}`) + .set('kbn-xsrf', 'true') + .expect(200) + .parse(binaryToString); + + expect(body.toString()).to.eql('127.0.0.2\n127.0.0.1\n'); + }); + }); + }); +}; diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/index.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/index.ts index f131541ce439d..302877a680aa6 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/index.ts +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/index.ts @@ -22,5 +22,6 @@ export default ({ loadTestFile }: FtrProviderContext): void => { loadTestFile(require.resolve('./find_lists')); loadTestFile(require.resolve('./find_list_items')); loadTestFile(require.resolve('./import_list_items')); + loadTestFile(require.resolve('./export_list_items')); }); }; diff --git a/x-pack/test/lists_api_integration/utils.ts b/x-pack/test/lists_api_integration/utils.ts index 4f231ee935004..272768fdf50b3 100644 --- a/x-pack/test/lists_api_integration/utils.ts +++ b/x-pack/test/lists_api_integration/utils.ts @@ -108,3 +108,19 @@ export const waitFor = async ( } }); }; + +/** + * Useful for export_api testing to convert from a multi-part binary back to a string + * @param res Response + * @param callback Callback + */ +export const binaryToString = (res: any, callback: any): void => { + res.setEncoding('binary'); + res.data = ''; + res.on('data', (chunk: any) => { + res.data += chunk; + }); + res.on('end', () => { + callback(null, Buffer.from(res.data)); + }); +};