[security solutions][lists] Adds end to end tests (#74473)

## Summary

Adds initial set of end to end tests for lists

You can run all of these with the command from kibana root:

```ts
node scripts/functional_tests --config x-pack/test/lists_api_integration/security_and_spaces/config.ts
```

Fixes a few minor bugs found such as...
* Validation for importing lists was not checking if the indexes were created first
* Some wording for the error messages had duplicate words within them

### Checklist

- [x] [Unit or functional tests](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#cross-browser-compatibility) were updated or added to match the most common scenarios
This commit is contained in:
Frank Hassanabad 2020-08-11 09:25:04 -06:00 committed by GitHub
parent f621b0e2b6
commit 461d68418c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
34 changed files with 1709 additions and 6 deletions

View file

@ -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';

View file

@ -14,3 +14,20 @@ export const getCreateListItemSchemaMock = (): CreateListItemSchema => ({
meta: META,
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,
});

View file

@ -18,3 +18,22 @@ export const getCreateListSchemaMock = (): CreateListSchema => ({
type: TYPE,
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,
name: NAME,
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,
type: TYPE,
});

View file

@ -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'));
};

View file

@ -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,
});

View file

@ -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,
});

View file

@ -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({});
});
});

View file

@ -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<ListItemSchema> => ({
created_by: ELASTIC_USER,
list_id: LIST_ID,
type: TYPE,
updated_by: ELASTIC_USER,
value: VALUE,
});

View file

@ -8,6 +8,7 @@ import { ListSchema } from '../../../common/schemas';
import {
DATE_NOW,
DESCRIPTION,
ELASTIC_USER,
IMMUTABLE,
LIST_ID,
META,
@ -35,3 +36,17 @@ 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<ListSchema> => ({
created_by: ELASTIC_USER,
description: DESCRIPTION,
immutable: IMMUTABLE,
name: NAME,
type: TYPE,
updated_by: ELASTIC_USER,
version: VERSION,
});

View file

@ -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,

View file

@ -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 {

View file

@ -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) {

View file

@ -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 {

View file

@ -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 {

View file

@ -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 {

View file

@ -73,7 +73,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')}`,

View file

@ -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}`,
]
: []),
],
},
};
};
}

View file

@ -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<typeof services, {}>;

View file

@ -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';

View file

@ -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,
});

View file

@ -0,0 +1,115 @@
/*
* 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,
removeListItemServerGeneratedProperties,
} 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 = removeListItemServerGeneratedProperties(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 = removeListItemServerGeneratedProperties(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,
});
});
});
});
};

View file

@ -0,0 +1,95 @@
/*
* 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 } from '../../../../plugins/lists/common/constants';
import { FtrProviderContext } from '../../common/ftr_provider_context';
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,
removeListServerGeneratedProperties,
} from '../../utils';
// eslint-disable-next-line import/no-default-export
export default ({ getService }: FtrProviderContext) => {
const supertest = getService('supertest');
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 list', async () => {
const { body } = await supertest
.post(LIST_URL)
.set('kbn-xsrf', 'true')
.send(getCreateMinimalListSchemaMock())
.expect(400);
expect(body).to.eql({
message:
'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 simple list with a list_id', async () => {
const { body } = await supertest
.post(LIST_URL)
.set('kbn-xsrf', 'true')
.send(getCreateMinimalListSchemaMock())
.expect(200);
const bodyToCompare = removeListServerGeneratedProperties(body);
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 = removeListServerGeneratedProperties(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,
});
});
});
});
};

View file

@ -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,
});
});
});
});
};

View file

@ -0,0 +1,83 @@
/*
* 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,
removeListServerGeneratedProperties,
} 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 = removeListServerGeneratedProperties(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 = removeListServerGeneratedProperties(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,
});
});
});
});
};

View file

@ -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');
});
});
});
};

View file

@ -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,
});
});
});
});
};

View file

@ -0,0 +1,77 @@
/*
* 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,
removeListServerGeneratedProperties,
} 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 = [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({
data: [getListResponseMockWithoutAutoGeneratedValues()],
page: 1,
per_page: 20,
total: 1,
});
});
});
});
};

View file

@ -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<ListSchema> = {
...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<ListItemSchema> = {
...getListItemResponseMockWithoutAutoGeneratedValues(),
list_id: 'list_items.txt',
};
expect(bodyToCompare).to.eql(outputtedList);
});
});
});
};

View file

@ -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 { 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'));
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('./update_list_items'));
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'));
loadTestFile(require.resolve('./export_list_items'));
});
};

View file

@ -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('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 = removeListItemServerGeneratedProperties(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 = removeListItemServerGeneratedProperties(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',
});
});
});
});
};

View file

@ -0,0 +1,84 @@
/*
* 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,
removeListServerGeneratedProperties,
} 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=${getCreateMinimalListSchemaMock().id}`)
.set('kbn-xsrf', 'true')
.expect(200);
const bodyToCompare = removeListServerGeneratedProperties(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')
.expect(200);
const bodyToCompare = removeListServerGeneratedProperties(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',
});
});
});
});
};

View file

@ -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<ListItemSchema> = {
...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<ListItemSchema> = {
...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',
});
});
});
});
};

View file

@ -0,0 +1,141 @@
/*
* 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,
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';
// 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<ListSchema> = {
...getListResponseMockWithoutAutoGeneratedValues(),
name: 'some other name',
version: 2,
};
const bodyToCompare = removeListServerGeneratedProperties(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<ListSchema> = {
...getListResponseMockWithoutAutoGeneratedValues(),
name: 'some other name',
version: 2,
};
const bodyToCompare = removeListServerGeneratedProperties(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<ListSchema> = {
...getListResponseMockWithoutAutoGeneratedValues(),
name: 'some other name',
description: 'some other description',
version: 2,
};
const bodyToCompare = removeListServerGeneratedProperties(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',
});
});
});
});
};

View file

@ -0,0 +1,126 @@
/*
* 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 { ListItemSchema } from '../../plugins/lists/common/schemas';
import { ListSchema } from '../../plugins/lists/common';
import { LIST_INDEX } from '../../plugins/lists/common/constants';
/**
* 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
*/
export const createListsIndex = async (
supertest: SuperTest<supertestAsPromised.Test>,
retryCount = 20
): Promise<void> => {
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<supertestAsPromised.Test>,
retryCount = 20
): Promise<void> => {
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 list List to pass in to remove typical server generated properties
*/
export const removeListServerGeneratedProperties = (
list: Partial<ListSchema>
): Partial<ListSchema> => {
/* 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<ListItemSchema>
): Partial<ListItemSchema> => {
/* eslint-disable-next-line @typescript-eslint/naming-convention */
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<boolean>,
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'));
}
});
};
/**
* 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));
});
};