diff --git a/x-pack/package.json b/x-pack/package.json index ba1758ed9bb90..a4da3fe05765e 100644 --- a/x-pack/package.json +++ b/x-pack/package.json @@ -174,4 +174,4 @@ "engines": { "yarn": "^1.6.0" } -} +} \ No newline at end of file diff --git a/x-pack/scripts/functional_tests.js b/x-pack/scripts/functional_tests.js index 1b05203e4dd09..33abe151b7d29 100644 --- a/x-pack/scripts/functional_tests.js +++ b/x-pack/scripts/functional_tests.js @@ -14,5 +14,6 @@ require('@kbn/test').runTestsCli([ require.resolve('../test/api_integration/config.js'), require.resolve('../test/saml_api_integration/config.js'), require.resolve('../test/rbac_api_integration/config.js'), - require.resolve('../test/spaces_api_integration/config.js'), + require.resolve('../test/spaces_api_integration/spaces_only/config.js'), + require.resolve('../test/spaces_api_integration/security_and_spaces/config.js'), ]); diff --git a/x-pack/test/spaces_api_integration/apis/saved_objects/bulk_get.js b/x-pack/test/spaces_api_integration/apis/saved_objects/bulk_get.js deleted file mode 100644 index 791efe7fbe194..0000000000000 --- a/x-pack/test/spaces_api_integration/apis/saved_objects/bulk_get.js +++ /dev/null @@ -1,145 +0,0 @@ -/* - * 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 'expect.js'; -import { SPACES } from '../lib/spaces'; -import { getIdPrefix, getUrlPrefix } from '../lib/space_test_utils'; - -export default function ({ getService }) { - const supertest = getService('supertest'); - const esArchiver = getService('esArchiver'); - - const BULK_REQUESTS = [ - { - type: 'visualization', - id: 'dd7caf20-9efd-11e7-acb3-3dab96693fab', - }, - { - type: 'dashboard', - id: 'does not exist', - }, - { - type: 'config', - id: '7.0.0-alpha1', - }, - ]; - - const createBulkRequests = (spaceId) => BULK_REQUESTS.map(r => ({ - ...r, - id: `${getIdPrefix(spaceId)}${r.id}` - })); - - describe('_bulk_get', () => { - const expectNotFoundResults = (spaceId) => resp => { - expect(resp.body).to.eql({ - saved_objects: [ - { - id: `${getIdPrefix(spaceId)}dd7caf20-9efd-11e7-acb3-3dab96693fab`, - type: 'visualization', - error: { - statusCode: 404, - message: 'Not found', - }, - }, - { - id: `${getIdPrefix(spaceId)}does not exist`, - type: 'dashboard', - error: { - statusCode: 404, - message: 'Not found', - }, - }, - //todo(legrego) fix when config is space aware - { - id: `${getIdPrefix(spaceId)}7.0.0-alpha1`, - type: 'config', - error: { - statusCode: 404, - message: 'Not found', - }, - }, - ], - }); - }; - - const expectResults = (spaceId) => resp => { - expect(resp.body).to.eql({ - saved_objects: [ - { - id: `${getIdPrefix(spaceId)}dd7caf20-9efd-11e7-acb3-3dab96693fab`, - type: 'visualization', - updated_at: '2017-09-21T18:51:23.794Z', - version: resp.body.saved_objects[0].version, - attributes: { - title: 'Count of requests', - description: '', - version: 1, - // cheat for some of the more complex attributes - visState: resp.body.saved_objects[0].attributes.visState, - uiStateJSON: resp.body.saved_objects[0].attributes.uiStateJSON, - kibanaSavedObjectMeta: - resp.body.saved_objects[0].attributes.kibanaSavedObjectMeta, - }, - }, - { - id: `${getIdPrefix(spaceId)}does not exist`, - type: 'dashboard', - error: { - statusCode: 404, - message: 'Not found', - }, - }, - //todo(legrego) fix when config is space aware - { - id: `${getIdPrefix(spaceId)}7.0.0-alpha1`, - type: 'config', - error: { - statusCode: 404, - message: 'Not found', - }, - }, - ], - }); - }; - - const bulkGetTest = (description, { spaceId, tests, otherSpaceId = spaceId }) => { - describe(description, () => { - before(() => esArchiver.load('saved_objects/spaces')); - after(() => esArchiver.unload('saved_objects/spaces')); - - it(`should return ${tests.default.statusCode}`, async () => { - await supertest - .post(`${getUrlPrefix(spaceId)}/api/saved_objects/_bulk_get`) - .send(createBulkRequests(otherSpaceId)) - .expect(tests.default.statusCode) - .then(tests.default.response); - }); - }); - }; - - bulkGetTest(`objects within the current space (space_1)`, { - ...SPACES.SPACE_1, - tests: { - default: { - statusCode: 200, - response: expectResults(SPACES.SPACE_1.spaceId), - }, - } - }); - - bulkGetTest(`objects within another space`, { - ...SPACES.SPACE_1, - otherSpaceId: SPACES.SPACE_2.spaceId, - tests: { - default: { - statusCode: 200, - response: expectNotFoundResults(SPACES.SPACE_2.spaceId) - }, - } - }); - - }); -} diff --git a/x-pack/test/spaces_api_integration/apis/saved_objects/create.js b/x-pack/test/spaces_api_integration/apis/saved_objects/create.js deleted file mode 100644 index 6677e8b42dedd..0000000000000 --- a/x-pack/test/spaces_api_integration/apis/saved_objects/create.js +++ /dev/null @@ -1,143 +0,0 @@ -/* - * 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 'expect.js'; -import { getUrlPrefix } from '../lib/space_test_utils'; -import { SPACES } from '../lib/spaces'; -import { DEFAULT_SPACE_ID } from '../../../../plugins/spaces/common/constants'; - -export default function ({ getService }) { - const supertest = getService('supertest'); - const es = getService('es'); - const esArchiver = getService('esArchiver'); - - describe('create', () => { - const expectSpaceAwareResults = (spaceId) => async (resp) => { - expect(resp.body).to.have.property('id').match(/^[0-9a-f-]{36}$/); - - // loose ISO8601 UTC time with milliseconds validation - expect(resp.body).to.have.property('updated_at').match(/^[\d-]{10}T[\d:\.]{12}Z$/); - - expect(resp.body).to.eql({ - id: resp.body.id, - type: 'visualization', - updated_at: resp.body.updated_at, - version: 1, - attributes: { - title: 'My favorite vis' - } - }); - - const expectedSpacePrefix = spaceId === DEFAULT_SPACE_ID ? '' : `${spaceId}:`; - - // query ES directory to assert on space id - const { _source } = await es.get({ - id: `${expectedSpacePrefix}visualization:${resp.body.id}`, - type: 'doc', - index: '.kibana' - }); - - const { - namespace: actualSpaceId = '**not defined**' - } = _source; - - if (spaceId === DEFAULT_SPACE_ID) { - expect(actualSpaceId).to.eql('**not defined**'); - } else { - expect(actualSpaceId).to.eql(spaceId); - } - }; - - const expectNotSpaceAwareResults = () => async (resp) => { - expect(resp.body).to.have.property('id').match(/^[0-9a-f-]{36}$/); - - // loose ISO8601 UTC time with milliseconds validation - expect(resp.body).to.have.property('updated_at').match(/^[\d-]{10}T[\d:\.]{12}Z$/); - - expect(resp.body).to.eql({ - id: resp.body.id, - type: 'space', - updated_at: resp.body.updated_at, - version: 1, - attributes: { - name: 'My favorite space', - } - }); - - // query ES directory to assert on space id - const { _source } = await es.get({ - id: `space:${resp.body.id}`, - type: 'doc', - index: '.kibana' - }); - - const { - namespace: actualSpaceId = '**not defined**' - } = _source; - - expect(actualSpaceId).to.eql('**not defined**'); - }; - - const createTest = (description, { spaceId, tests }) => { - describe(description, () => { - before(() => esArchiver.load('saved_objects/spaces')); - after(() => esArchiver.unload('saved_objects/spaces')); - it(`should return ${tests.spaceAware.statusCode} for a space-aware type`, async () => { - await supertest - .post(`${getUrlPrefix(spaceId)}/api/saved_objects/visualization`) - .send({ - attributes: { - title: 'My favorite vis' - } - }) - .expect(tests.spaceAware.statusCode) - .then(tests.spaceAware.response); - }); - - it(`should return ${tests.notSpaceAware.statusCode} for a non space-aware type`, async () => { - await supertest - .post(`${getUrlPrefix(spaceId)}/api/saved_objects/space`) - .send({ - attributes: { - name: 'My favorite space', - } - }) - .expect(tests.notSpaceAware.statusCode) - .then(tests.notSpaceAware.response); - }); - - }); - }; - - createTest('in the current space (space_1)', { - ...SPACES.SPACE_1, - tests: { - spaceAware: { - statusCode: 200, - response: expectSpaceAwareResults(SPACES.SPACE_1.spaceId), - }, - notSpaceAware: { - statusCode: 200, - response: expectNotSpaceAwareResults(SPACES.SPACE_1.spaceId), - } - } - }); - - createTest('in the default space', { - ...SPACES.DEFAULT, - tests: { - spaceAware: { - statusCode: 200, - response: expectSpaceAwareResults(SPACES.DEFAULT.spaceId), - }, - notSpaceAware: { - statusCode: 200, - response: expectNotSpaceAwareResults(SPACES.SPACE_1.spaceId), - } - } - }); - }); -} diff --git a/x-pack/test/spaces_api_integration/apis/saved_objects/delete.js b/x-pack/test/spaces_api_integration/apis/saved_objects/delete.js deleted file mode 100644 index 5dd8b3221751a..0000000000000 --- a/x-pack/test/spaces_api_integration/apis/saved_objects/delete.js +++ /dev/null @@ -1,95 +0,0 @@ -/* - * 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 'expect.js'; -import { SPACES } from '../lib/spaces'; -import { getUrlPrefix, getIdPrefix } from '../lib/space_test_utils'; - -export default function ({ getService }) { - const supertest = getService('supertest'); - const esArchiver = getService('esArchiver'); - - describe('delete', () => { - - const expectEmpty = () => (resp) => { - expect(resp.body).to.eql({}); - }; - - const expectNotFound = (type, id) => (resp) => { - expect(resp.body).to.eql({ - statusCode: 404, - error: 'Not Found', - message: `Saved object [${type}/${id}] not found` - }); - }; - - const deleteTest = (description, { spaceId, tests }) => { - describe(description, () => { - before(() => esArchiver.load('saved_objects/spaces')); - after(() => esArchiver.unload('saved_objects/spaces')); - - it(`should return ${tests.spaceAware.statusCode} when deleting a space-aware doc`, async () => ( - await supertest - .delete(`${getUrlPrefix(spaceId)}/api/saved_objects/dashboard/${getIdPrefix(spaceId)}be3733a0-9efe-11e7-acb3-3dab96693fab`) - .expect(tests.spaceAware.statusCode) - .then(tests.spaceAware.response()) - )); - - it(`should return ${tests.notSpaceAware.statusCode} when deleting a non-space-aware doc`, async () => ( - await supertest - .delete(`${getUrlPrefix(spaceId)}/api/saved_objects/space/space_2`) - .expect(tests.notSpaceAware.statusCode) - .then(tests.notSpaceAware.response()) - )); - - it(`should return ${tests.inOtherSpace.statusCode} when deleting a doc belonging to another space`, async () => { - const expectedObjectId = `${getIdPrefix('space_2')}be3733a0-9efe-11e7-acb3-3dab96693fab`; - - await supertest - .delete(`${getUrlPrefix(spaceId)}/api/saved_objects/dashboard/${expectedObjectId}`) - .expect(tests.inOtherSpace.statusCode) - .then(tests.inOtherSpace.response('dashboard', expectedObjectId)); - }); - }); - }; - - deleteTest(`in the default space`, { - ...SPACES.DEFAULT, - tests: { - spaceAware: { - statusCode: 200, - response: expectEmpty - }, - notSpaceAware: { - statusCode: 200, - response: expectEmpty - }, - inOtherSpace: { - statusCode: 404, - response: expectNotFound - } - } - }); - - deleteTest(`in the current space (space_1)`, { - ...SPACES.SPACE_1, - tests: { - spaceAware: { - statusCode: 200, - response: expectEmpty - }, - notSpaceAware: { - statusCode: 200, - response: expectEmpty - }, - inOtherSpace: { - statusCode: 404, - response: expectNotFound - } - } - }); - }); -} diff --git a/x-pack/test/spaces_api_integration/apis/saved_objects/find.js b/x-pack/test/spaces_api_integration/apis/saved_objects/find.js deleted file mode 100644 index 7f6ca951c8be2..0000000000000 --- a/x-pack/test/spaces_api_integration/apis/saved_objects/find.js +++ /dev/null @@ -1,186 +0,0 @@ -/* - * 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 'expect.js'; -import { SPACES } from '../lib/spaces'; -import { getIdPrefix, getUrlPrefix } from '../lib/space_test_utils'; - -export default function ({ getService }) { - const supertest = getService('supertest'); - const esArchiver = getService('esArchiver'); - - describe('find', () => { - - const expectVisualizationResults = (spaceId) => (resp) => { - expect(resp.body).to.eql({ - page: 1, - per_page: 20, - total: 1, - saved_objects: [ - { - type: 'visualization', - id: `${getIdPrefix(spaceId)}dd7caf20-9efd-11e7-acb3-3dab96693fab`, - // no space id on the saved object because the field is not requested as part of a find operation - version: 1, - attributes: { - 'title': 'Count of requests' - } - } - ] - }); - }; - - const expectAllResults = (spaceId) => (resp) => { - // TODO(legrego): update once config is space-aware - - const sortById = ({ id: id1 }, { id: id2 }) => id1 < id2 ? -1 : 1; - - resp.body.saved_objects.sort(sortById); - - const expectedSavedObjects = [{ - id: '7.0.0-alpha1', - type: 'config', - updated_at: '2017-09-21T18:49:16.302Z', - version: 1, - }, - { - id: `${getIdPrefix(spaceId)}91200a00-9efd-11e7-acb3-3dab96693fab`, - type: 'index-pattern', - updated_at: '2017-09-21T18:49:16.270Z', - version: 1, - }, - - { - id: `${getIdPrefix(spaceId)}be3733a0-9efe-11e7-acb3-3dab96693fab`, - type: 'dashboard', - updated_at: '2017-09-21T18:57:40.826Z', - version: 1, - }, - { - id: `${getIdPrefix(spaceId)}dd7caf20-9efd-11e7-acb3-3dab96693fab`, - type: 'visualization', - updated_at: '2017-09-21T18:51:23.794Z', - version: 1, - }] - .sort(sortById); - - expectedSavedObjects.forEach((object, index) => { - if (resp.body.saved_objects[index]) { - object.attributes = resp.body.saved_objects[index].attributes; - } - }); - - expect(resp.body).to.eql({ - page: 1, - per_page: 20, - total: expectedSavedObjects.length, - saved_objects: expectedSavedObjects, - }); - }; - - const createExpectEmpty = (page, perPage, total) => (resp) => { - expect(resp.body).to.eql({ - page: page, - per_page: perPage, - total: total, - saved_objects: [] - }); - }; - - const findTest = (description, { spaceId, tests }) => { - describe(description, () => { - before(() => esArchiver.load('saved_objects/spaces')); - after(() => esArchiver.unload('saved_objects/spaces')); - - it(`should return ${tests.normal.statusCode} with ${tests.normal.description}`, async () => ( - await supertest - .get(`${getUrlPrefix(spaceId)}/api/saved_objects/_find?type=visualization&fields=title`) - .expect(tests.normal.statusCode) - .then(tests.normal.response) - )); - - describe('page beyond total', () => { - it(`should return ${tests.pageBeyondTotal.statusCode} with ${tests.pageBeyondTotal.description}`, async () => ( - await supertest - .get(`${getUrlPrefix(spaceId)}/api/saved_objects/_find?type=visualization&page=100&per_page=100`) - .expect(tests.pageBeyondTotal.statusCode) - .then(tests.pageBeyondTotal.response) - )); - }); - - describe('unknown search field', () => { - it(`should return ${tests.unknownSearchField.statusCode} with ${tests.unknownSearchField.description}`, async () => ( - await supertest - .get(`${getUrlPrefix(spaceId)}/api/saved_objects/_find?type=wigwags&search_fields=a`) - .expect(tests.unknownSearchField.statusCode) - .then(tests.unknownSearchField.response) - )); - }); - - describe('no type', () => { - it(`should return ${tests.noType.statusCode} with ${tests.noType.description}`, async () => ( - await supertest - .get(`${getUrlPrefix(spaceId)}/api/saved_objects/_find`) - .expect(tests.noType.statusCode) - .then(tests.noType.response) - )); - }); - }); - }; - - findTest(`objects only within the current space (space_1)`, { - ...SPACES.SPACE_1, - tests: { - normal: { - description: 'only the visualization', - statusCode: 200, - response: expectVisualizationResults(SPACES.SPACE_1.spaceId), - }, - pageBeyondTotal: { - description: 'empty result', - statusCode: 200, - response: createExpectEmpty(100, 100, 1), - }, - unknownSearchField: { - description: 'empty result', - statusCode: 200, - response: createExpectEmpty(1, 20, 0), - }, - noType: { - description: 'all objects', - statusCode: 200, - response: expectAllResults(SPACES.SPACE_1.spaceId), - }, - } - }); - - findTest(`objects only within the current space (default)`, { - ...SPACES.DEFAULT, - tests: { - normal: { - description: 'only the visualization', - statusCode: 200, - response: expectVisualizationResults(SPACES.DEFAULT.spaceId), - }, - pageBeyondTotal: { - description: 'empty result', - statusCode: 200, - response: createExpectEmpty(100, 100, 1), - }, - unknownSearchField: { - description: 'empty result', - statusCode: 200, - response: createExpectEmpty(1, 20, 0), - }, - noType: { - description: 'all objects', - statusCode: 200, - response: expectAllResults(SPACES.DEFAULT.spaceId), - }, - } - }); - }); -} diff --git a/x-pack/test/spaces_api_integration/apis/saved_objects/get.js b/x-pack/test/spaces_api_integration/apis/saved_objects/get.js deleted file mode 100644 index 9a163aec53d88..0000000000000 --- a/x-pack/test/spaces_api_integration/apis/saved_objects/get.js +++ /dev/null @@ -1,112 +0,0 @@ -/* - * 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 'expect.js'; -import { getIdPrefix, getUrlPrefix } from '../lib/space_test_utils'; -import { SPACES } from '../lib/spaces'; - -export default function ({ getService }) { - const supertest = getService('supertest'); - const esArchiver = getService('esArchiver'); - - describe('get', () => { - - const expectResults = (spaceId) => () => (resp) => { - - // The default space does not assign a space id. - const expectedSpaceId = spaceId === 'default' ? undefined : spaceId; - - const expectedBody = { - id: `${getIdPrefix(spaceId)}dd7caf20-9efd-11e7-acb3-3dab96693fab`, - type: 'visualization', - updated_at: '2017-09-21T18:51:23.794Z', - version: resp.body.version, - - attributes: { - title: 'Count of requests', - description: '', - version: 1, - // cheat for some of the more complex attributes - visState: resp.body.attributes.visState, - uiStateJSON: resp.body.attributes.uiStateJSON, - kibanaSavedObjectMeta: resp.body.attributes.kibanaSavedObjectMeta - } - }; - - if (expectedSpaceId) { - expectedBody.spaceId = expectedSpaceId; - } - - expect(resp.body).to.eql(expectedBody); - }; - - const expectNotFound = (type, id) => (resp) => { - expect(resp.body).to.eql({ - error: 'Not Found', - message: `Saved object [${type}/${id}] not found`, - statusCode: 404, - }); - }; - - const getTest = (description, { spaceId, tests, otherSpaceId = spaceId }) => { - describe(description, () => { - before(async () => esArchiver.load(`saved_objects/spaces`)); - after(async () => esArchiver.unload(`saved_objects/spaces`)); - - it(`should return ${tests.exists.statusCode}`, async () => { - const objectId = `${getIdPrefix(otherSpaceId)}dd7caf20-9efd-11e7-acb3-3dab96693fab`; - - return supertest - .get(`${getUrlPrefix(spaceId)}/api/saved_objects/visualization/${objectId}`) - .expect(tests.exists.statusCode) - .then(tests.exists.response('visualization', objectId)); - }); - }); - }; - - getTest(`can access objects belonging to the current space (space_1)`, { - ...SPACES.SPACE_1, - tests: { - exists: { - statusCode: 200, - response: expectResults(SPACES.SPACE_1.spaceId), - }, - } - }); - - getTest(`cannot access objects belonging to a different space (space_1)`, { - ...SPACES.SPACE_1, - otherSpaceId: SPACES.SPACE_2.spaceId, - tests: { - exists: { - statusCode: 404, - response: expectNotFound - }, - } - }); - - getTest(`can access objects belonging to the current space (default)`, { - ...SPACES.DEFAULT, - tests: { - exists: { - statusCode: 200, - response: expectResults(SPACES.DEFAULT.spaceId), - }, - } - }); - - getTest(`cannot access objects belonging to a different space (default)`, { - ...SPACES.DEFAULT, - otherSpaceId: SPACES.SPACE_1.spaceId, - tests: { - exists: { - statusCode: 404, - response: expectNotFound - }, - } - }); - }); -} diff --git a/x-pack/test/spaces_api_integration/apis/saved_objects/lib/authentication.js b/x-pack/test/spaces_api_integration/apis/saved_objects/lib/authentication.js deleted file mode 100644 index 8b140fd3b2a30..0000000000000 --- a/x-pack/test/spaces_api_integration/apis/saved_objects/lib/authentication.js +++ /dev/null @@ -1,32 +0,0 @@ -/* - * 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 const AUTHENTICATION = { - NOT_A_KIBANA_USER: { - USERNAME: 'not_a_kibana_user', - PASSWORD: 'password' - }, - SUPERUSER: { - USERNAME: 'elastic', - PASSWORD: 'changeme' - }, - KIBANA_LEGACY_USER: { - USERNAME: 'a_kibana_legacy_user', - PASSWORD: 'password' - }, - KIBANA_LEGACY_DASHBOARD_ONLY_USER: { - USERNAME: 'a_kibana_legacy_dashboard_only_user', - PASSWORD: 'password' - }, - KIBANA_RBAC_USER: { - USERNAME: 'a_kibana_rbac_user', - PASSWORD: 'password' - }, - KIBANA_RBAC_DASHBOARD_ONLY_USER: { - USERNAME: 'a_kibana_rbac_dashboard_only_user', - PASSWORD: 'password' - } -}; diff --git a/x-pack/test/spaces_api_integration/apis/saved_objects/update.js b/x-pack/test/spaces_api_integration/apis/saved_objects/update.js deleted file mode 100644 index 60103e206af98..0000000000000 --- a/x-pack/test/spaces_api_integration/apis/saved_objects/update.js +++ /dev/null @@ -1,158 +0,0 @@ -/* - * 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 'expect.js'; -import { SPACES } from '../lib/spaces'; -import { getUrlPrefix, getIdPrefix } from '../lib/space_test_utils'; - -export default function ({ getService }) { - const supertest = getService('supertest'); - const esArchiver = getService('esArchiver'); - - describe('update', () => { - const expectSpaceAwareResults = () => resp => { - - // loose ISO8601 UTC time with milliseconds validation - expect(resp.body).to.have.property('updated_at').match(/^[\d-]{10}T[\d:\.]{12}Z$/); - - expect(resp.body).to.eql({ - id: resp.body.id, - type: 'visualization', - updated_at: resp.body.updated_at, - version: 2, - attributes: { - title: 'My second favorite vis' - } - }); - }; - - const expectNonSpaceAwareResults = () => resp => { - - // loose ISO8601 UTC time with milliseconds validation - expect(resp.body).to.have.property('updated_at').match(/^[\d-]{10}T[\d:\.]{12}Z$/); - - expect(resp.body).to.eql({ - id: resp.body.id, - type: 'space', - updated_at: resp.body.updated_at, - version: 2, - attributes: { - name: 'My second favorite space' - } - }); - }; - - const expectNotFound = (type, id) => resp => { - expect(resp.body).eql({ - statusCode: 404, - error: 'Not Found', - message: `Saved object [${type}/${id}] not found` - }); - }; - - const updateTest = (description, { spaceId, tests }) => { - describe(description, () => { - before(() => esArchiver.load('saved_objects/spaces')); - after(() => esArchiver.unload('saved_objects/spaces')); - it(`should return ${tests.spaceAware.statusCode} for a space-aware doc`, async () => { - await supertest - .put(`${getUrlPrefix(spaceId)}/api/saved_objects/visualization/${getIdPrefix(spaceId)}dd7caf20-9efd-11e7-acb3-3dab96693fab`) - .send({ - attributes: { - title: 'My second favorite vis' - } - }) - .expect(tests.spaceAware.statusCode) - .then(tests.spaceAware.response()); - }); - - it(`should return ${tests.notSpaceAware.statusCode} for a non space-aware doc`, async () => { - await supertest - .put(`${getUrlPrefix(spaceId)}/api/saved_objects/space/space_1`) - .send({ - attributes: { - name: 'My second favorite space' - } - }) - .expect(tests.notSpaceAware.statusCode) - .then(tests.notSpaceAware.response()); - }); - - it(`should return ${tests.inOtherSpace.statusCode} for a doc in another space`, async () => { - const id = `${getIdPrefix('space_2')}dd7caf20-9efd-11e7-acb3-3dab96693fab`; - await supertest - .put(`${getUrlPrefix(spaceId)}/api/saved_objects/visualization/${id}`) - .send({ - attributes: { - title: 'My second favorite vis' - } - }) - .expect(tests.inOtherSpace.statusCode) - .then(tests.inOtherSpace.response(`visualization`, `${id}`)); - }); - - describe('unknown id', () => { - it(`should return ${tests.doesntExist.statusCode}`, async () => { - await supertest - .put(`${getUrlPrefix(spaceId)}/api/saved_objects/visualization/not an id`) - .send({ - attributes: { - title: 'My second favorite vis' - } - }) - .expect(tests.doesntExist.statusCode) - .then(tests.doesntExist.response(`visualization`, `not an id`)); - }); - }); - }); - }; - - updateTest(`in the default space`, { - ...SPACES.DEFAULT, - tests: { - spaceAware: { - statusCode: 200, - response: expectSpaceAwareResults, - }, - notSpaceAware: { - statusCode: 200, - response: expectNonSpaceAwareResults, - }, - inOtherSpace: { - statusCode: 404, - response: expectNotFound, - }, - doesntExist: { - statusCode: 404, - response: expectNotFound, - }, - } - }); - - updateTest('in the current space (space_1)', { - ...SPACES.SPACE_1, - tests: { - spaceAware: { - statusCode: 200, - response: expectSpaceAwareResults, - }, - notSpaceAware: { - statusCode: 200, - response: expectNonSpaceAwareResults, - }, - inOtherSpace: { - statusCode: 404, - response: expectNotFound, - }, - doesntExist: { - statusCode: 404, - response: expectNotFound, - }, - } - }); - - }); -} diff --git a/x-pack/test/spaces_api_integration/apis/spaces/create.js b/x-pack/test/spaces_api_integration/apis/spaces/create.js deleted file mode 100644 index a4160785d8de5..0000000000000 --- a/x-pack/test/spaces_api_integration/apis/spaces/create.js +++ /dev/null @@ -1,150 +0,0 @@ -/* - * 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 'expect.js'; -import { SPACES } from '../lib/spaces'; -import { getUrlPrefix } from '../lib/space_test_utils'; - -export default function ({ getService }) { - const supertest = getService('supertest'); - const esArchiver = getService('esArchiver'); - - describe('create', () => { - const createExpectResult = expectedResult => resp => { - expect(resp.body).to.eql(expectedResult); - }; - - const expectConflictResponse = resp => { - const spaceId = 'space_1'; - expect(resp.body).to.only.have.keys(['error', 'message', 'statusCode']); - expect(resp.body.error).to.equal('Conflict'); - expect(resp.body.statusCode).to.equal(409); - expect(resp.body.message).to.match(new RegExp(`\\[doc]\\[space:${spaceId}]: version conflict, document already exists.*`)); - }; - - const createTest = (description, { currentSpace, tests }) => { - describe(description, () => { - before(async () => esArchiver.load(`saved_objects/spaces`)); - after(async () => esArchiver.unload(`saved_objects/spaces`)); - - it(`should return ${tests.newSpace.statusCode}`, async () => { - return supertest - .post(`${getUrlPrefix(currentSpace.id)}/api/spaces/v1/space`) - .send(tests.newSpace.space) - .expect(tests.newSpace.statusCode) - .then(tests.newSpace.response); - }); - - describe('when it already exists', () => { - it(`should return ${tests.alreadyExists.statusCode}`, async () => { - return supertest - .post(`${getUrlPrefix(currentSpace.id)}/api/spaces/v1/space`) - .send({ - name: 'space_1', - id: 'space_1', - color: '#ffffff', - description: 'a description', - }) - .expect(tests.alreadyExists.statusCode) - .then(tests.alreadyExists.response); - }); - }); - - describe('when _reserved is specified', () => { - it(`should return ${tests.reservedSpecified.statusCode} and ignore _reserved`, async () => { - return supertest - .post(`${getUrlPrefix(currentSpace.id)}/api/spaces/v1/space`) - .send(tests.reservedSpecified.space) - .expect(tests.reservedSpecified.statusCode) - .then(tests.reservedSpecified.response); - }); - }); - }); - }; - - createTest(`from the default space`, { - currentSpace: SPACES.DEFAULT, - tests: { - newSpace: { - space: { - name: 'marketing', - id: 'marketing', - description: 'a description', - color: '#5c5959', - }, - statusCode: 200, - response: createExpectResult({ - name: 'marketing', - id: 'marketing', - description: 'a description', - color: '#5c5959', - }), - }, - alreadyExists: { - statusCode: 409, - response: expectConflictResponse, - }, - reservedSpecified: { - space: { - name: 'reserved space', - id: 'reserved', - description: 'a description', - color: '#5c5959', - _reserved: true, - }, - statusCode: 200, - response: createExpectResult({ - name: 'reserved space', - id: 'reserved', - description: 'a description', - color: '#5c5959', - }) - } - }, - }); - - createTest(`from space_1`, { - currentSpace: SPACES.SPACE_1, - tests: { - newSpace: { - space: { - name: 'marketing', - id: 'marketing', - description: 'a description', - color: '#5c5959', - }, - statusCode: 200, - response: createExpectResult({ - name: 'marketing', - id: 'marketing', - description: 'a description', - color: '#5c5959', - }), - }, - alreadyExists: { - statusCode: 409, - response: expectConflictResponse, - }, - reservedSpecified: { - space: { - name: 'reserved space', - id: 'reserved', - description: 'a description', - color: '#5c5959', - _reserved: true, - }, - statusCode: 200, - response: createExpectResult({ - name: 'reserved space', - id: 'reserved', - description: 'a description', - color: '#5c5959', - }) - }, - }, - }); - }); -} diff --git a/x-pack/test/spaces_api_integration/apis/spaces/delete.js b/x-pack/test/spaces_api_integration/apis/spaces/delete.js deleted file mode 100644 index fe30fcc687007..0000000000000 --- a/x-pack/test/spaces_api_integration/apis/spaces/delete.js +++ /dev/null @@ -1,104 +0,0 @@ -/* - * 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 'expect.js'; -import { SPACES } from '../lib/spaces'; -import { getUrlPrefix } from '../lib/space_test_utils'; - -export default function ({ getService }) { - const supertest = getService('supertest'); - const esArchiver = getService('esArchiver'); - - describe('delete', () => { - const expectEmptyResponse = resp => { - expect(resp.body).to.eql(''); - }; - - const expectNotFound = resp => { - expect(resp.body).to.eql({ - error: 'Not Found', - statusCode: 404, - message: `Saved object [space/space_3] not found` - }); - }; - - const expectReservedSpaceResponse = resp => { - expect(resp.body).to.eql({ - error: 'Bad Request', - statusCode: 400, - message: `This Space cannot be deleted because it is reserved.` - }); - }; - - const deleteTest = (description, { currentSpace, tests }) => { - describe(description, () => { - before(async () => esArchiver.load(`saved_objects/spaces`)); - after(async () => esArchiver.unload(`saved_objects/spaces`)); - - it(`should return ${tests.exists.statusCode}`, async () => { - return supertest - .delete(`${getUrlPrefix(currentSpace.id)}/api/spaces/v1/space/${SPACES.SPACE_1.spaceId}`) - .expect(tests.exists.statusCode) - .then(tests.exists.response); - }); - - describe(`when the space is the default space`, async () => { - it(`should return ${tests.defaultSpace.statusCode}`, async () => { - return supertest - .delete(`${getUrlPrefix(currentSpace.id)}/api/spaces/v1/space/${SPACES.DEFAULT.spaceId}`) - .expect(tests.defaultSpace.statusCode) - .then(tests.defaultSpace.response); - }); - }); - - describe(`when the space doesn't exist`, () => { - it(`should return ${tests.doesntExist.statusCode}`, async () => { - return supertest - .delete(`${getUrlPrefix(currentSpace.id)}/api/spaces/v1/space/space_3`) - .expect(tests.doesntExist.statusCode) - .then(tests.doesntExist.response); - }); - }); - }); - }; - - deleteTest(`from the default space`, { - currentSpace: SPACES.DEFAULT, - tests: { - exists: { - statusCode: 204, - response: expectEmptyResponse, - }, - defaultSpace: { - statusCode: 400, - response: expectReservedSpaceResponse, - }, - doesntExist: { - statusCode: 404, - response: expectNotFound, - }, - }, - }); - - deleteTest(`from space_1`, { - currentSpace: SPACES.SPACE_1, - tests: { - exists: { - statusCode: 204, - response: expectEmptyResponse, - }, - defaultSpace: { - statusCode: 400, - response: expectReservedSpaceResponse, - }, - doesntExist: { - statusCode: 404, - response: expectNotFound, - }, - }, - }); - }); -} diff --git a/x-pack/test/spaces_api_integration/apis/spaces/get.js b/x-pack/test/spaces_api_integration/apis/spaces/get.js deleted file mode 100644 index 0604b8fcb029c..0000000000000 --- a/x-pack/test/spaces_api_integration/apis/spaces/get.js +++ /dev/null @@ -1,83 +0,0 @@ -/* - * 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 'expect.js'; -import { SPACES } from '../lib/spaces'; -import { getUrlPrefix } from '../lib/space_test_utils'; - -export default function ({ getService }) { - const supertest = getService('supertest'); - const esArchiver = getService('esArchiver'); - - describe('get', () => { - - const allSpaces = [ - { id: 'default', - name: 'Default Space', - description: 'This is the default space', - _reserved: true }, - { id: 'space_1', - name: 'Space 1', - description: 'This is the first test space' }, - { id: 'space_2', - name: 'Space 2', - description: 'This is the second test space' } - ]; - - const createExpectResultSpace = (spaceId) => (resp) => { - const result = allSpaces.find(space => space.id === spaceId); - expect(resp.body).to.eql(result); - }; - - //todo: Add 404 test - const getTest = (description, { currentSpace, spaceId, tests }) => { - describe(description, () => { - before(async () => esArchiver.load(`saved_objects/spaces`)); - after(async () => esArchiver.unload(`saved_objects/spaces`)); - - it(`should return ${tests.exists.statusCode}`, async () => { - return supertest - .get(`${getUrlPrefix(currentSpace.id)}/api/spaces/v1/space/${spaceId}`) - .expect(tests.exists.statusCode) - .then(tests.exists.response); - }); - }); - }; - - getTest(`can access default space from default space`, { - currentSpace: SPACES.DEFAULT, - spaceId: SPACES.DEFAULT.spaceId, - tests: { - exists: { - statusCode: 200, - response: createExpectResultSpace(SPACES.DEFAULT.spaceId), - }, - } - }); - - getTest(`can access space_1 from the default space`, { - currentSpace: SPACES.DEFAULT, - spaceId: SPACES.SPACE_1.spaceId, - tests: { - exists: { - statusCode: 200, - response: createExpectResultSpace(SPACES.SPACE_1.spaceId), - }, - } - }); - - getTest(`can access space_2 from space_1`, { - currentSpace: SPACES.SPACE_1, - spaceId: SPACES.SPACE_2.spaceId, - tests: { - exists: { - statusCode: 200, - response: createExpectResultSpace(SPACES.SPACE_2.spaceId), - }, - } - }); - }); -} diff --git a/x-pack/test/spaces_api_integration/apis/spaces/get_all.js b/x-pack/test/spaces_api_integration/apis/spaces/get_all.js deleted file mode 100644 index ff7d0f45296c1..0000000000000 --- a/x-pack/test/spaces_api_integration/apis/spaces/get_all.js +++ /dev/null @@ -1,67 +0,0 @@ -/* - * 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 'expect.js'; -import { SPACES } from '../lib/spaces'; -import { getUrlPrefix } from '../lib/space_test_utils'; - -export default function ({ getService }) { - const supertest = getService('supertest'); - const esArchiver = getService('esArchiver'); - - describe('get all', () => { - - const expectResults = (resp) => { - const expectedBody = [ - { id: 'default', - name: 'Default Space', - description: 'This is the default space', - _reserved: true }, - { id: 'space_1', - name: 'Space 1', - description: 'This is the first test space' }, - { id: 'space_2', - name: 'Space 2', - description: 'This is the second test space' } - ]; - expect(resp.body).to.eql(expectedBody); - }; - - const getTest = (description, { spaceId, tests }) => { - describe(description, () => { - before(async () => esArchiver.load(`saved_objects/spaces`)); - after(async () => esArchiver.unload(`saved_objects/spaces`)); - - it(`should return ${tests.exists.statusCode}`, async () => { - return supertest - .get(`${getUrlPrefix(spaceId)}/api/spaces/v1/spaces`) - .expect(tests.exists.statusCode) - .then(tests.exists.response); - }); - }); - }; - - getTest(`can access all spaces from space_1`, { - ...SPACES.SPACE_1, - tests: { - exists: { - statusCode: 200, - response: expectResults, - }, - } - }); - - getTest(`can access all spaces from the default space`, { - ...SPACES.DEFAULT, - tests: { - exists: { - statusCode: 200, - response: expectResults, - }, - } - }); - }); -} diff --git a/x-pack/test/spaces_api_integration/apis/spaces/select.js b/x-pack/test/spaces_api_integration/apis/spaces/select.js deleted file mode 100644 index e8599dc63b1d1..0000000000000 --- a/x-pack/test/spaces_api_integration/apis/spaces/select.js +++ /dev/null @@ -1,76 +0,0 @@ -/* - * 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 'expect.js'; -import { SPACES } from '../lib/spaces'; -import { getUrlPrefix } from '../lib/space_test_utils'; - -export default function ({ getService }) { - const supertest = getService('supertest'); - const esArchiver = getService('esArchiver'); - - describe('select', () => { - - const expectDefaultSpaceResponse = (resp) => { - expect(resp.body).to.eql({ - location: `/app/kibana` - }); - }; - - const createExpectSpaceResponse = (spaceId) => (resp) => { - expect(resp.body).to.eql({ - location: `/s/${spaceId}/app/kibana` - }); - }; - - const selectTest = (description, { currentSpace, spaceId, tests }) => { - describe(description, () => { - before(async () => esArchiver.load(`saved_objects/spaces`)); - after(async () => esArchiver.unload(`saved_objects/spaces`)); - - it(`should return ${tests.exists.statusCode}`, async () => { - return supertest - .post(`${getUrlPrefix(currentSpace.id)}/api/spaces/v1/space/${spaceId}/select`) - .expect(tests.exists.statusCode) - .then(tests.exists.response); - }); - }); - }; - - selectTest(`can select default space from default space`, { - currentSpace: SPACES.DEFAULT, - spaceId: SPACES.DEFAULT.spaceId, - tests: { - exists: { - statusCode: 200, - response: expectDefaultSpaceResponse, - }, - } - }); - - selectTest(`can select space_1 from the default space`, { - currentSpace: SPACES.DEFAULT, - spaceId: SPACES.SPACE_1.spaceId, - tests: { - exists: { - statusCode: 200, - response: createExpectSpaceResponse(SPACES.SPACE_1.spaceId), - }, - } - }); - - selectTest(`can access space_2 from space_1`, { - currentSpace: SPACES.SPACE_1, - spaceId: SPACES.SPACE_2.spaceId, - tests: { - exists: { - statusCode: 200, - response: createExpectSpaceResponse(SPACES.SPACE_2.spaceId), - }, - } - }); - }); -} diff --git a/x-pack/test/spaces_api_integration/apis/spaces/update.js b/x-pack/test/spaces_api_integration/apis/spaces/update.js deleted file mode 100644 index 26f0271cd3959..0000000000000 --- a/x-pack/test/spaces_api_integration/apis/spaces/update.js +++ /dev/null @@ -1,117 +0,0 @@ -/* - * 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 'expect.js'; -import { SPACES } from '../lib/spaces'; -import { getUrlPrefix } from '../lib/space_test_utils'; - -export default function ({ getService }) { - const supertest = getService('supertest'); - const esArchiver = getService('esArchiver'); - - describe('update', () => { - const createExpectResult = expectedResult => resp => { - expect(resp.body).to.eql(expectedResult); - }; - - const createExpectNotFound = spaceId => resp => { - expect(resp.body).to.eql({ - error: 'Not Found', - statusCode: 404, - message: `Saved object [space/${spaceId}] not found` - }); - }; - - const updateTest = (description, { currentSpace, tests }) => { - describe(description, () => { - before(async () => esArchiver.load(`saved_objects/spaces`)); - after(async () => esArchiver.unload(`saved_objects/spaces`)); - - it(`should return ${tests.alreadyExists.statusCode}`, async () => { - return supertest - .put(`${getUrlPrefix(currentSpace.id)}/api/spaces/v1/space/${tests.alreadyExists.space.id}`) - .send(tests.alreadyExists.space) - .expect(tests.alreadyExists.statusCode) - .then(tests.alreadyExists.response); - }); - - describe(`when space doesn't exist`, () => { - it(`should return ${tests.newSpace.statusCode}`, async () => { - return supertest - .put(`${getUrlPrefix(currentSpace.id)}/api/spaces/v1/space/${tests.newSpace.space.id}`) - .send(tests.newSpace.space) - .expect(tests.newSpace.statusCode) - .then(tests.newSpace.response); - }); - }); - }); - }; - - updateTest(`from the default space`, { - currentSpace: SPACES.DEFAULT, - tests: { - alreadyExists: { - space: { - name: 'space 1', - id: 'space_1', - description: 'a description', - color: '#5c5959', - _reserved: true, - }, - statusCode: 200, - response: createExpectResult({ - name: 'space 1', - id: 'space_1', - description: 'a description', - color: '#5c5959', - }), - }, - newSpace: { - space: { - name: 'marketing', - id: 'marketing', - description: 'a description', - color: '#5c5959', - }, - statusCode: 404, - response: createExpectNotFound('marketing'), - }, - }, - }); - - updateTest(`from space_1`, { - currentSpace: SPACES.SPACE_1, - tests: { - alreadyExists: { - space: { - name: 'space 1', - id: 'space_1', - description: 'a description', - color: '#5c5959', - _reserved: true, - }, - statusCode: 200, - response: createExpectResult({ - name: 'space 1', - id: 'space_1', - description: 'a description', - color: '#5c5959', - }), - }, - newSpace: { - space: { - name: 'marketing', - id: 'marketing', - description: 'a description', - color: '#5c5959', - }, - statusCode: 404, - response: createExpectNotFound('marketing'), - }, - }, - }); - }); -} diff --git a/x-pack/test/spaces_api_integration/common/config.js b/x-pack/test/spaces_api_integration/common/config.js new file mode 100644 index 0000000000000..594891e7ddad7 --- /dev/null +++ b/x-pack/test/spaces_api_integration/common/config.js @@ -0,0 +1,67 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import path from 'path'; +import { resolveKibanaPath } from '@kbn/plugin-helpers'; +import { EsProvider } from './services/es'; + + +export function createTestConfig(name, { license = 'trial', disabledPlugins = [] } = {}) { + + return async function ({ readConfigFile }) { + + const config = { + kibana: { + api: await readConfigFile(resolveKibanaPath('test/api_integration/config.js')), + functional: await readConfigFile(require.resolve('../../../../test/functional/config.js')) + }, + xpack: { + api: await readConfigFile(require.resolve('../../api_integration/config.js')) + } + }; + + console.log('resolving', require.resolve(`../${name}/apis/`)); + return { + testFiles: [require.resolve(`../${name}/apis/`)], + servers: config.xpack.api.get('servers'), + services: { + es: EsProvider, + esSupertestWithoutAuth: config.xpack.api.get('services.esSupertestWithoutAuth'), + supertest: config.kibana.api.get('services.supertest'), + supertestWithoutAuth: config.xpack.api.get('services.supertestWithoutAuth'), + esArchiver: config.kibana.functional.get('services.esArchiver'), + kibanaServer: config.kibana.functional.get('services.kibanaServer'), + }, + junit: { + reportName: 'X-Pack Spaces API Integration Tests -- ' + name, + }, + + esArchiver: { + directory: path.join(__dirname, 'fixtures', 'es_archiver') + }, + + esTestCluster: { + ...config.xpack.api.get('esTestCluster'), + license, + serverArgs: [ + `xpack.license.self_generated.type=${license}`, + `xpack.security.enabled=${!disabledPlugins.includes('security') && license === 'trial'}`, + ], + }, + + kbnTestServer: { + ...config.xpack.api.get('kbnTestServer'), + serverArgs: [ + ...config.xpack.api.get('kbnTestServer.serverArgs'), + '--optimize.enabled=false', + '--server.xsrf.disableProtection=true', + `--plugin-path=${path.join(__dirname, 'fixtures', 'namespace_agnostic_type_plugin')}`, + ...disabledPlugins.map(key => `--xpack.${key}.enabled=false`), + ], + }, + }; + }; +} diff --git a/x-pack/test/spaces_api_integration/fixtures/es_archiver/saved_objects/spaces/data.json b/x-pack/test/spaces_api_integration/common/fixtures/es_archiver/saved_objects/spaces/data.json similarity index 100% rename from x-pack/test/spaces_api_integration/fixtures/es_archiver/saved_objects/spaces/data.json rename to x-pack/test/spaces_api_integration/common/fixtures/es_archiver/saved_objects/spaces/data.json diff --git a/x-pack/test/spaces_api_integration/fixtures/es_archiver/saved_objects/spaces/mappings.json b/x-pack/test/spaces_api_integration/common/fixtures/es_archiver/saved_objects/spaces/mappings.json similarity index 100% rename from x-pack/test/spaces_api_integration/fixtures/es_archiver/saved_objects/spaces/mappings.json rename to x-pack/test/spaces_api_integration/common/fixtures/es_archiver/saved_objects/spaces/mappings.json diff --git a/x-pack/test/spaces_api_integration/common/lib/authentication.ts b/x-pack/test/spaces_api_integration/common/lib/authentication.ts new file mode 100644 index 0000000000000..20aa0b5e955e5 --- /dev/null +++ b/x-pack/test/spaces_api_integration/common/lib/authentication.ts @@ -0,0 +1,72 @@ +/* + * 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 const AUTHENTICATION = { + NOT_A_KIBANA_USER: { + USERNAME: 'not_a_kibana_user', + PASSWORD: 'password', + }, + SUPERUSER: { + USERNAME: 'elastic', + PASSWORD: 'changeme', + }, + KIBANA_LEGACY_USER: { + USERNAME: 'a_kibana_legacy_user', + PASSWORD: 'password', + }, + KIBANA_LEGACY_DASHBOARD_ONLY_USER: { + USERNAME: 'a_kibana_legacy_dashboard_only_user', + PASSWORD: 'password', + }, + KIBANA_DUAL_PRIVILEGES_USER: { + USERNAME: 'a_kibana_dual_privileges_user', + PASSWORD: 'password', + }, + KIBANA_DUAL_PRIVILEGES_DASHBOARD_ONLY_USER: { + USERNAME: 'a_kibana_dual_privileges_dashboard_only_user', + PASSWORD: 'password', + }, + KIBANA_RBAC_USER: { + USERNAME: 'a_kibana_rbac_user', + PASSWORD: 'password', + }, + KIBANA_RBAC_DASHBOARD_ONLY_USER: { + USERNAME: 'a_kibana_rbac_dashboard_only_user', + PASSWORD: 'password', + }, + KIBANA_RBAC_DEFAULT_SPACE_ALL_USER: { + USERNAME: 'a_kibana_rbac_default_space_all_user', + PASSWORD: 'password', + }, + KIBANA_RBAC_DEFAULT_SPACE_READ_USER: { + USERNAME: 'a_kibana_rbac_default_space_read_user', + PASSWORD: 'password', + }, + KIBANA_RBAC_SPACE_1_ALL_USER: { + USERNAME: 'a_kibana_rbac_space_1_all_user', + PASSWORD: 'password', + }, + KIBANA_RBAC_SPACE_1_READ_USER: { + USERNAME: 'a_kibana_rbac_space_1_read_user', + PASSWORD: 'password', + }, + KIBANA_RBAC_SPACE_2_ALL_USER: { + USERNAME: 'a_kibana_rbac_space_2_all_user', + PASSWORD: 'password', + }, + KIBANA_RBAC_SPACE_2_READ_USER: { + USERNAME: 'a_kibana_rbac_space_2_read_user', + PASSWORD: 'password', + }, + KIBANA_RBAC_SPACE_1_2_ALL_USER: { + USERNAME: 'a_kibana_rbac_space_1_2_all_user', + PASSWORD: 'password', + }, + KIBANA_RBAC_SPACE_1_2_READ_USER: { + USERNAME: 'a_kibana_rbac_space_1_2_read_user', + PASSWORD: 'password', + }, +}; diff --git a/x-pack/test/spaces_api_integration/common/lib/create_users_and_roles.ts b/x-pack/test/spaces_api_integration/common/lib/create_users_and_roles.ts new file mode 100644 index 0000000000000..1ce40b5c3a8aa --- /dev/null +++ b/x-pack/test/spaces_api_integration/common/lib/create_users_and_roles.ts @@ -0,0 +1,286 @@ +/* + * 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 { AUTHENTICATION } from './authentication'; + +export const createUsersAndRoles = async (es, supertest) => { + await supertest.put('/api/security/role/kibana_legacy_user').send({ + elasticsearch: { + indices: [ + { + names: ['.kibana'], + privileges: ['manage', 'read', 'index', 'delete'], + }, + ], + }, + }); + + await supertest.put('/api/security/role/kibana_legacy_dashboard_only_user').send({ + elasticsearch: { + indices: [ + { + names: ['.kibana'], + privileges: ['read', 'view_index_metadata'], + }, + ], + }, + }); + + await supertest.put('/api/security/role/kibana_dual_privileges_user').send({ + elasticsearch: { + indices: [ + { + names: ['.kibana'], + privileges: ['manage', 'read', 'index', 'delete'], + }, + ], + }, + kibana: { + global: ['all'], + }, + }); + + await supertest.put('/api/security/role/kibana_dual_privileges_dashboard_only_user').send({ + elasticsearch: { + indices: [ + { + names: ['.kibana'], + privileges: ['read', 'view_index_metadata'], + }, + ], + }, + kibana: { + global: ['read'], + }, + }); + + await supertest.put('/api/security/role/kibana_rbac_user').send({ + kibana: { + global: ['all'], + }, + }); + + await supertest.put('/api/security/role/kibana_rbac_dashboard_only_user').send({ + kibana: { + global: ['read'], + }, + }); + + await supertest.put('/api/security/role/kibana_rbac_default_space_all_user').send({ + kibana: { + space: { + default: ['all'], + }, + }, + }); + + await supertest.put('/api/security/role/kibana_rbac_default_space_read_user').send({ + kibana: { + space: { + default: ['read'], + }, + }, + }); + + await supertest.put('/api/security/role/kibana_rbac_space_1_all_user').send({ + kibana: { + space: { + space_1: ['all'], + }, + }, + }); + + await supertest.put('/api/security/role/kibana_rbac_space_1_read_user').send({ + kibana: { + space: { + space_1: ['read'], + }, + }, + }); + + await supertest.put('/api/security/role/kibana_rbac_space_2_all_user').send({ + kibana: { + space: { + space_2: ['all'], + }, + }, + }); + + await supertest.put('/api/security/role/kibana_rbac_space_2_read_user').send({ + kibana: { + space: { + space_2: ['read'], + }, + }, + }); + + await supertest.put('/api/security/role/kibana_rbac_space_1_2_all_user').send({ + kibana: { + space: { + space_1: ['all'], + space_2: ['all'], + }, + }, + }); + + await supertest.put('/api/security/role/kibana_rbac_space_1_2_read_user').send({ + kibana: { + space: { + space_1: ['read'], + space_2: ['read'], + }, + }, + }); + + await es.shield.putUser({ + username: AUTHENTICATION.NOT_A_KIBANA_USER.USERNAME, + body: { + password: AUTHENTICATION.NOT_A_KIBANA_USER.PASSWORD, + roles: [], + full_name: 'not a kibana user', + email: 'not_a_kibana_user@elastic.co', + }, + }); + + await es.shield.putUser({ + username: AUTHENTICATION.KIBANA_LEGACY_USER.USERNAME, + body: { + password: AUTHENTICATION.KIBANA_LEGACY_USER.PASSWORD, + roles: ['kibana_legacy_user'], + full_name: 'a kibana legacy user', + email: 'a_kibana_legacy_user@elastic.co', + }, + }); + + await es.shield.putUser({ + username: AUTHENTICATION.KIBANA_LEGACY_DASHBOARD_ONLY_USER.USERNAME, + body: { + password: AUTHENTICATION.KIBANA_LEGACY_DASHBOARD_ONLY_USER.PASSWORD, + roles: ['kibana_legacy_dashboard_only_user'], + full_name: 'a kibana legacy dashboard only user', + email: 'a_kibana_legacy_dashboard_only_user@elastic.co', + }, + }); + + await es.shield.putUser({ + username: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_USER.USERNAME, + body: { + password: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_USER.PASSWORD, + roles: ['kibana_dual_privileges_user'], + full_name: 'a kibana dual_privileges user', + email: 'a_kibana_dual_privileges_user@elastic.co', + }, + }); + + await es.shield.putUser({ + username: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_DASHBOARD_ONLY_USER.USERNAME, + body: { + password: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_DASHBOARD_ONLY_USER.PASSWORD, + roles: ['kibana_dual_privileges_dashboard_only_user'], + full_name: 'a kibana dual_privileges dashboard only user', + email: 'a_kibana_dual_privileges_dashboard_only_user@elastic.co', + }, + }); + + await es.shield.putUser({ + username: AUTHENTICATION.KIBANA_RBAC_USER.USERNAME, + body: { + password: AUTHENTICATION.KIBANA_RBAC_USER.PASSWORD, + roles: ['kibana_rbac_user'], + full_name: 'a kibana user', + email: 'a_kibana_rbac_user@elastic.co', + }, + }); + + await es.shield.putUser({ + username: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER.USERNAME, + body: { + password: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER.PASSWORD, + roles: ['kibana_rbac_dashboard_only_user'], + full_name: 'a kibana dashboard only user', + email: 'a_kibana_rbac_dashboard_only_user@elastic.co', + }, + }); + + await es.shield.putUser({ + username: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_ALL_USER.USERNAME, + body: { + password: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_ALL_USER.PASSWORD, + roles: ['kibana_rbac_default_space_all_user'], + full_name: 'a kibana default space all user', + email: 'a_kibana_rbac_default_space_all_user@elastic.co', + }, + }); + + await es.shield.putUser({ + username: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_READ_USER.USERNAME, + body: { + password: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_READ_USER.PASSWORD, + roles: ['kibana_rbac_default_space_read_user'], + full_name: 'a kibana default space read-only user', + email: 'a_kibana_rbac_default_space_read_user@elastic.co', + }, + }); + + await es.shield.putUser({ + username: AUTHENTICATION.KIBANA_RBAC_SPACE_1_ALL_USER.USERNAME, + body: { + password: AUTHENTICATION.KIBANA_RBAC_SPACE_1_ALL_USER.PASSWORD, + roles: ['kibana_rbac_space_1_all_user'], + full_name: 'a kibana rbac space 1 all user', + email: 'a_kibana_rbac_space_1_all_user@elastic.co', + }, + }); + + await es.shield.putUser({ + username: AUTHENTICATION.KIBANA_RBAC_SPACE_1_READ_USER.USERNAME, + body: { + password: AUTHENTICATION.KIBANA_RBAC_SPACE_1_READ_USER.PASSWORD, + roles: ['kibana_rbac_space_1_read_user'], + full_name: 'a kibana rbac space 1 read-only user', + email: 'a_kibana_rbac_space_1_readonly_user@elastic.co', + }, + }); + + await es.shield.putUser({ + username: AUTHENTICATION.KIBANA_RBAC_SPACE_2_ALL_USER.USERNAME, + body: { + password: AUTHENTICATION.KIBANA_RBAC_SPACE_2_ALL_USER.PASSWORD, + roles: ['kibana_rbac_space_2_all_user'], + full_name: 'a kibana rbac space 2 all user', + email: 'a_kibana_rbac_space_2_all_user@elastic.co', + }, + }); + + await es.shield.putUser({ + username: AUTHENTICATION.KIBANA_RBAC_SPACE_2_READ_USER.USERNAME, + body: { + password: AUTHENTICATION.KIBANA_RBAC_SPACE_2_READ_USER.PASSWORD, + roles: ['kibana_rbac_space_2_read_user'], + full_name: 'a kibana rbac space 2 read-only user', + email: 'a_kibana_rbac_space_2_readonly_user@elastic.co', + }, + }); + + await es.shield.putUser({ + username: AUTHENTICATION.KIBANA_RBAC_SPACE_1_2_ALL_USER.USERNAME, + body: { + password: AUTHENTICATION.KIBANA_RBAC_SPACE_1_2_ALL_USER.PASSWORD, + roles: ['kibana_rbac_space_1_2_all_user'], + full_name: 'a kibana rbac space 1 and 2 all user', + email: 'a_kibana_rbac_space_1_2_all_user@elastic.co', + }, + }); + + await es.shield.putUser({ + username: AUTHENTICATION.KIBANA_RBAC_SPACE_1_2_READ_USER.USERNAME, + body: { + password: AUTHENTICATION.KIBANA_RBAC_SPACE_1_2_READ_USER.PASSWORD, + roles: ['kibana_rbac_space_1_2_read_user'], + full_name: 'a kibana rbac space 1 and 2 read-only user', + email: 'a_kibana_rbac_space_1_2_readonly_user@elastic.co', + }, + }); +}; diff --git a/x-pack/test/spaces_api_integration/apis/lib/space_test_utils.js b/x-pack/test/spaces_api_integration/common/lib/space_test_utils.ts similarity index 82% rename from x-pack/test/spaces_api_integration/apis/lib/space_test_utils.js rename to x-pack/test/spaces_api_integration/common/lib/space_test_utils.ts index 4afa5910a5189..f233bc1d11d7c 100644 --- a/x-pack/test/spaces_api_integration/apis/lib/space_test_utils.js +++ b/x-pack/test/spaces_api_integration/common/lib/space_test_utils.ts @@ -6,10 +6,10 @@ import { DEFAULT_SPACE_ID } from '../../../../plugins/spaces/common/constants'; -export function getUrlPrefix(spaceId) { +export function getUrlPrefix(spaceId?: string) { return spaceId && spaceId !== DEFAULT_SPACE_ID ? `/s/${spaceId}` : ``; } -export function getIdPrefix(spaceId) { +export function getIdPrefix(spaceId?: string) { return spaceId === DEFAULT_SPACE_ID ? '' : `${spaceId}-`; } diff --git a/x-pack/test/spaces_api_integration/apis/lib/spaces.js b/x-pack/test/spaces_api_integration/common/lib/spaces.ts similarity index 98% rename from x-pack/test/spaces_api_integration/apis/lib/spaces.js rename to x-pack/test/spaces_api_integration/common/lib/spaces.ts index 905b360c99949..a9c552d4ccd78 100644 --- a/x-pack/test/spaces_api_integration/apis/lib/spaces.js +++ b/x-pack/test/spaces_api_integration/common/lib/spaces.ts @@ -13,5 +13,5 @@ export const SPACES = { }, DEFAULT: { spaceId: 'default', - } + }, }; diff --git a/x-pack/test/spaces_api_integration/common/lib/types.ts b/x-pack/test/spaces_api_integration/common/lib/types.ts new file mode 100644 index 0000000000000..1027fdc909632 --- /dev/null +++ b/x-pack/test/spaces_api_integration/common/lib/types.ts @@ -0,0 +1,36 @@ +/* + * 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 type DescribeFn = (text: string, fn: () => void) => void; + +export interface TestResultDescriptor { + statusCode: number; + response: (resp: any) => void; + space?: any; +} + +export interface TestsObject { + [key: string]: TestResultDescriptor; +} + +export interface TestOptions { + auth?: { + username?: string; + password?: string; + }; + currentSpaceId?: string; + spaceId?: string; + tests: TestsObject; +} + +export type LoadTestFileFn = (path: string) => string; + +export type GetServiceFn = (service: string) => any; + +export interface TestInvoker { + getService: GetServiceFn; + loadTestFile: LoadTestFileFn; +} diff --git a/x-pack/test/spaces_api_integration/common/services/es.js b/x-pack/test/spaces_api_integration/common/services/es.js new file mode 100644 index 0000000000000..c4fa7c504e12c --- /dev/null +++ b/x-pack/test/spaces_api_integration/common/services/es.js @@ -0,0 +1,20 @@ +/* + * 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 { format as formatUrl } from 'url'; + +import elasticsearch from 'elasticsearch'; +import shieldPlugin from '../../../../server/lib/esjs_shield_plugin'; + +export function EsProvider({ getService }) { + const config = getService('config'); + + return new elasticsearch.Client({ + host: formatUrl(config.get('servers.elasticsearch')), + requestTimeout: config.get('timeouts.esRequestTimeout'), + plugins: [shieldPlugin] + }); +} diff --git a/x-pack/test/spaces_api_integration/common/suites/spaces/create.ts b/x-pack/test/spaces_api_integration/common/suites/spaces/create.ts new file mode 100644 index 0000000000000..38e27e6077cbf --- /dev/null +++ b/x-pack/test/spaces_api_integration/common/suites/spaces/create.ts @@ -0,0 +1,105 @@ +/* + * 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 'expect.js'; +import { SuperTest } from 'supertest'; +import { getUrlPrefix } from '../../lib/space_test_utils'; +import { DescribeFn, TestOptions } from '../../lib/types'; + +export function createTestSuiteFactory(esArchiver: any, supertest: SuperTest) { + const makeCreateTest = (describeFn: DescribeFn) => ( + description: string, + { + auth = { + username: undefined, + password: undefined, + }, + spaceId, + tests, + }: TestOptions + ) => { + describeFn(description, () => { + before(() => esArchiver.load('saved_objects/spaces')); + after(() => esArchiver.unload('saved_objects/spaces')); + + it(`should return ${tests.newSpace.statusCode}`, async () => { + return supertest + .post(`${getUrlPrefix(spaceId)}/api/spaces/v1/space`) + .auth(auth.username, auth.password) + .send(tests.newSpace.space) + .expect(tests.newSpace.statusCode) + .then(tests.newSpace.response); + }); + + describe('when it already exists', () => { + it(`should return ${tests.alreadyExists.statusCode}`, async () => { + return supertest + .post(`${getUrlPrefix(spaceId)}/api/spaces/v1/space`) + .auth(auth.username, auth.password) + .send({ + name: 'space_1', + id: 'space_1', + color: '#ffffff', + description: 'a description', + }) + .expect(tests.alreadyExists.statusCode) + .then(tests.alreadyExists.response); + }); + }); + + describe('when _reserved is specified', () => { + it(`should return ${tests.reservedSpecified.statusCode} and ignore _reserved`, async () => { + return supertest + .post(`${getUrlPrefix(spaceId)}/api/spaces/v1/space`) + .auth(auth.username, auth.password) + .send(tests.reservedSpecified.space) + .expect(tests.reservedSpecified.statusCode) + .then(tests.reservedSpecified.response); + }); + }); + }); + }; + + const createTest = makeCreateTest(describe); + + const createExpectResult = (expectedResult: any) => (resp: any) => { + expect(resp.body).to.eql(expectedResult); + }; + + const createExpectConflictResponse = () => (resp: any) => { + const spaceId = 'space_1'; + expect(resp.body).to.only.have.keys(['error', 'message', 'statusCode']); + expect(resp.body.error).to.equal('Conflict'); + expect(resp.body.statusCode).to.equal(409); + expect(resp.body.message).to.match( + new RegExp(`\\[doc]\\[space:${spaceId}]: version conflict, document already exists.*`) + ); + }; + + const createExpectForbiddenResponse = () => (resp: any) => { + expect(resp.body).to.eql({ + statusCode: 403, + error: 'Forbidden', + message: 'Unauthorized to create spaces', + }); + }; + + const createExpectLegacyForbiddenResponse = () => (resp: any) => { + expect(resp.body).to.eql({ + statusCode: 403, + error: 'Forbidden', + message: `action [indices:data/write/index] is unauthorized for user [a_kibana_legacy_dashboard_only_user]: [security_exception] action [indices:data/write/index] is unauthorized for user [a_kibana_legacy_dashboard_only_user]`, + }); + }; + + return { + createTest, + createExpectResult, + createExpectConflictResponse, + createExpectForbiddenResponse, + createExpectLegacyForbiddenResponse, + }; +} diff --git a/x-pack/test/spaces_api_integration/common/suites/spaces/delete.ts b/x-pack/test/spaces_api_integration/common/suites/spaces/delete.ts new file mode 100644 index 0000000000000..de20f6cc27920 --- /dev/null +++ b/x-pack/test/spaces_api_integration/common/suites/spaces/delete.ts @@ -0,0 +1,108 @@ +/* + * 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 'expect.js'; +import { SuperTest } from 'supertest'; +import { getUrlPrefix } from '../../lib/space_test_utils'; +import { DescribeFn, TestOptions } from '../../lib/types'; + +export function deleteTestSuiteFactory(esArchiver: any, supertest: SuperTest) { + const makeDeleteTest = (describeFn: DescribeFn) => ( + description: string, + { + auth = { + username: undefined, + password: undefined, + }, + spaceId, + tests, + }: TestOptions + ) => { + describeFn(description, () => { + before(() => esArchiver.load('saved_objects/spaces')); + after(() => esArchiver.unload('saved_objects/spaces')); + + it(`should return ${tests.exists.statusCode}`, async () => { + return supertest + .delete(`${getUrlPrefix(spaceId)}/api/spaces/v1/space/space_2`) + .auth(auth.username, auth.password) + .expect(tests.exists.statusCode) + .then(tests.exists.response); + }); + + describe(`when the space is reserved`, async () => { + it(`should return ${tests.reservedSpace.statusCode}`, async () => { + return supertest + .delete(`${getUrlPrefix(spaceId)}/api/spaces/v1/space/default`) + .auth(auth.username, auth.password) + .expect(tests.reservedSpace.statusCode) + .then(tests.reservedSpace.response); + }); + }); + + describe(`when the space doesn't exist`, () => { + it(`should return ${tests.doesntExist.statusCode}`, async () => { + return supertest + .delete(`${getUrlPrefix(spaceId)}/api/spaces/v1/space/space_3`) + .auth(auth.username, auth.password) + .expect(tests.doesntExist.statusCode) + .then(tests.doesntExist.response); + }); + }); + }); + }; + + const deleteTest = makeDeleteTest(describe); + + const createExpectResult = (expectedResult: any) => (resp: any) => { + expect(resp.body).to.eql(expectedResult); + }; + + const createExpectEmptyResult = () => (resp: any) => { + expect(resp.body).to.eql(''); + }; + + const createExpectNotFoundResult = () => (resp: any) => { + expect(resp.body).to.eql({ + error: 'Not Found', + statusCode: 404, + message: `Saved object [space/space_3] not found`, + }); + }; + + const createExpectReservedSpaceResult = () => (resp: any) => { + expect(resp.body).to.eql({ + error: 'Bad Request', + statusCode: 400, + message: `This Space cannot be deleted because it is reserved.`, + }); + }; + + const createExpectForbiddenResult = () => (resp: any) => { + expect(resp.body).to.eql({ + statusCode: 403, + error: 'Forbidden', + message: 'Unauthorized to delete spaces', + }); + }; + + const createExpectLegacyForbiddenResult = () => (resp: any) => { + expect(resp.body).to.eql({ + statusCode: 403, + error: 'Forbidden', + message: `action [indices:data/write/delete] is unauthorized for user [a_kibana_legacy_dashboard_only_user]: [security_exception] action [indices:data/write/delete] is unauthorized for user [a_kibana_legacy_dashboard_only_user]`, + }); + }; + + return { + deleteTest, + createExpectResult, + createExpectForbiddenResult, + createExpectEmptyResult, + createExpectNotFoundResult, + createExpectReservedSpaceResult, + createExpectLegacyForbiddenResult, + }; +} diff --git a/x-pack/test/spaces_api_integration/common/suites/spaces/get.ts b/x-pack/test/spaces_api_integration/common/suites/spaces/get.ts new file mode 100644 index 0000000000000..a8f9ab8c97cfe --- /dev/null +++ b/x-pack/test/spaces_api_integration/common/suites/spaces/get.ts @@ -0,0 +1,101 @@ +/* + * 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 'expect.js'; +import { SuperAgent } from 'superagent'; +import { getUrlPrefix } from '../../lib/space_test_utils'; +import { DescribeFn, TestOptions } from '../../lib/types'; + +export function getTestSuiteFactory(esArchiver: any, supertest: SuperAgent) { + const nonExistantSpaceId = 'not-a-space'; + + const makeGetTest = (describeFn: DescribeFn) => ( + description: string, + { + auth = { + username: undefined, + password: undefined, + }, + currentSpaceId, + spaceId, + tests, + }: TestOptions + ) => { + describeFn(description, () => { + before(() => esArchiver.load('saved_objects/spaces')); + after(() => esArchiver.unload('saved_objects/spaces')); + + it(`should return ${tests.default.statusCode}`, async () => { + return supertest + .get(`${getUrlPrefix(currentSpaceId)}/api/spaces/v1/space/${spaceId}`) + .auth(auth.username, auth.password) + .expect(tests.default.statusCode) + .then(tests.default.response); + }); + }); + }; + + const getTest = makeGetTest(describe); + + const createExpectResults = (spaceId: string) => (resp: any) => { + const allSpaces = [ + { + id: 'default', + name: 'Default Space', + description: 'This is the default space', + _reserved: true, + }, + { + id: 'space_1', + name: 'Space 1', + description: 'This is the first test space', + }, + { + id: 'space_2', + name: 'Space 2', + description: 'This is the second test space', + }, + ]; + expect(resp.body).to.eql(allSpaces.find(space => space.id === spaceId)); + }; + + const createExpectEmptyResult = () => (resp: any) => { + expect(resp.body).to.eql(''); + }; + + const createExpectNotFoundResult = (spaceId: string) => (resp: any) => { + expect(resp.body).to.eql({ + error: 'Not Found', + statusCode: 404, + message: `Saved object [space/${spaceId}] not found`, + }); + }; + + const createExpectReservedSpaceResult = () => (resp: any) => { + expect(resp.body).to.eql({ + error: 'Bad Request', + statusCode: 400, + message: `This Space cannot be deleted because it is reserved.`, + }); + }; + + const createExpectForbiddenResult = (spaceId: string) => (resp: any) => { + expect(resp.body).to.eql({ + statusCode: 403, + error: 'Forbidden', + message: `Unauthorized to get ${spaceId} space`, + }); + }; + + return { + getTest, + nonExistantSpaceId, + createExpectResults, + createExpectForbiddenResult, + createExpectEmptyResult, + createExpectNotFoundResult, + createExpectReservedSpaceResult, + }; +} diff --git a/x-pack/test/spaces_api_integration/common/suites/spaces/get_all.ts b/x-pack/test/spaces_api_integration/common/suites/spaces/get_all.ts new file mode 100644 index 0000000000000..d4ba6e875e1b1 --- /dev/null +++ b/x-pack/test/spaces_api_integration/common/suites/spaces/get_all.ts @@ -0,0 +1,97 @@ +/* + * 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 'expect.js'; +import { SuperTest } from 'supertest'; +import { getUrlPrefix } from '../../lib/space_test_utils'; +import { DescribeFn, TestOptions } from '../../lib/types'; + +export function getAllTestSuiteFactory(esArchiver: any, supertest: SuperTest) { + const makeGetAllTest = (describeFn: DescribeFn) => ( + description: string, + { + auth = { + username: undefined, + password: undefined, + }, + spaceId, + tests, + }: TestOptions + ) => { + describeFn(description, () => { + before(() => esArchiver.load('saved_objects/spaces')); + after(() => esArchiver.unload('saved_objects/spaces')); + + it(`should return ${tests.exists.statusCode}`, async () => { + return supertest + .get(`${getUrlPrefix(spaceId)}/api/spaces/v1/spaces`) + .auth(auth.username, auth.password) + .expect(tests.exists.statusCode) + .then(tests.exists.response); + }); + }); + }; + + const getAllTest = makeGetAllTest(describe); + + const createExpectResults = (...spaceIds: string[]) => (resp: any) => { + const expectedBody = [ + { + id: 'default', + name: 'Default Space', + description: 'This is the default space', + _reserved: true, + }, + { + id: 'space_1', + name: 'Space 1', + description: 'This is the first test space', + }, + { + id: 'space_2', + name: 'Space 2', + description: 'This is the second test space', + }, + ].filter(entry => spaceIds.includes(entry.id)); + expect(resp.body).to.eql(expectedBody); + }; + + const createExpectEmptyResult = () => (resp: any) => { + expect(resp.body).to.eql(''); + }; + + const createExpectNotFoundResult = () => (resp: any) => { + expect(resp.body).to.eql({ + error: 'Not Found', + statusCode: 404, + message: `Saved object [space/space_3] not found`, + }); + }; + + const createExpectReservedSpaceResult = () => (resp: any) => { + expect(resp.body).to.eql({ + error: 'Bad Request', + statusCode: 400, + message: `This Space cannot be deleted because it is reserved.`, + }); + }; + + const createExpectForbiddenResult = () => (resp: any) => { + expect(resp.body).to.eql({ + statusCode: 403, + error: 'Forbidden', + message: 'Unauthorized to delete spaces', + }); + }; + + return { + getAllTest, + createExpectResults, + createExpectForbiddenResult, + createExpectEmptyResult, + createExpectNotFoundResult, + createExpectReservedSpaceResult, + }; +} diff --git a/x-pack/test/spaces_api_integration/common/suites/spaces/select.ts b/x-pack/test/spaces_api_integration/common/suites/spaces/select.ts new file mode 100644 index 0000000000000..f52d060fea092 --- /dev/null +++ b/x-pack/test/spaces_api_integration/common/suites/spaces/select.ts @@ -0,0 +1,113 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import expect from 'expect.js'; +import { SuperTest } from 'supertest'; +import { DEFAULT_SPACE_ID } from '../../../../../plugins/spaces/common/constants'; +import { getUrlPrefix } from '../../lib/space_test_utils'; +import { DescribeFn, TestOptions } from '../../lib/types'; + +export function selectTestSuiteFactory(esArchiver: any, supertest: SuperTest) { + const nonExistantSpaceId = 'not-a-space'; + + const makeSelectTest = (describeFn: DescribeFn) => ( + description: string, + { + auth = { + username: undefined, + password: undefined, + }, + currentSpaceId = '', + spaceId = '', + tests, + }: TestOptions + ) => { + describeFn(description, () => { + before(() => esArchiver.load('saved_objects/spaces')); + after(() => esArchiver.unload('saved_objects/spaces')); + + it(`should return ${tests.default.statusCode}`, async () => { + return supertest + .post(`${getUrlPrefix(currentSpaceId)}/api/spaces/v1/space/${spaceId}/select`) + .auth(auth.username, auth.password) + .expect(tests.default.statusCode) + .then(tests.default.response); + }); + }); + }; + + const selectTest = makeSelectTest(describe); + // @ts-ignore + selectTest.only = makeSelectTest(describe.only); + + const createExpectResults = (spaceId: string) => (resp: any) => { + const allSpaces = [ + { + id: 'default', + name: 'Default Space', + description: 'This is the default space', + _reserved: true, + }, + { + id: 'space_1', + name: 'Space 1', + description: 'This is the first test space', + }, + { + id: 'space_2', + name: 'Space 2', + description: 'This is the second test space', + }, + ]; + expect(resp.body).to.eql(allSpaces.find(space => space.id === spaceId)); + }; + + const createExpectEmptyResult = () => (resp: any) => { + expect(resp.body).to.eql(''); + }; + + const createExpectNotFoundResult = (spaceId: string) => (resp: any) => { + expect(resp.body).to.eql({ + error: 'Not Found', + statusCode: 404, + message: `Saved object [space/${spaceId}] not found`, + }); + }; + const createExpectForbiddenResult = (spaceId: any) => (resp: any) => { + expect(resp.body).to.eql({ + statusCode: 403, + error: 'Forbidden', + message: `Unauthorized to get ${spaceId} space`, + }); + }; + + const createExpectDefaultSpaceResponse = () => (resp: any) => { + expect(resp.body).to.eql({ + location: `/app/kibana`, + }); + }; + + const createExpectSpaceResponse = (spaceId: string) => (resp: any) => { + if (spaceId === DEFAULT_SPACE_ID) { + createExpectDefaultSpaceResponse()(resp); + } else { + expect(resp.body).to.eql({ + location: `/s/${spaceId}/app/kibana`, + }); + } + }; + + return { + selectTest, + nonExistantSpaceId, + createExpectDefaultSpaceResponse, + createExpectSpaceResponse, + createExpectResults, + createExpectForbiddenResult, + createExpectEmptyResult, + createExpectNotFoundResult, + }; +} diff --git a/x-pack/test/spaces_api_integration/common/suites/spaces/update.ts b/x-pack/test/spaces_api_integration/common/suites/spaces/update.ts new file mode 100644 index 0000000000000..f8c37bed922e3 --- /dev/null +++ b/x-pack/test/spaces_api_integration/common/suites/spaces/update.ts @@ -0,0 +1,86 @@ +/* + * 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 'expect.js'; +import { SuperTest } from 'supertest'; +import { getUrlPrefix } from '../../lib/space_test_utils'; +import { DescribeFn, TestOptions } from '../../lib/types'; + +export function updateTestSuiteFactory(esArchiver: any, supertest: SuperTest) { + const makeUpdateTest = (describeFn: DescribeFn) => ( + description: string, + { + auth = { + username: undefined, + password: undefined, + }, + spaceId, + tests, + }: TestOptions + ) => { + describeFn(description, () => { + before(() => esArchiver.load('saved_objects/spaces')); + after(() => esArchiver.unload('saved_objects/spaces')); + + it(`should return ${tests.alreadyExists.statusCode}`, async () => { + return supertest + .put(`${getUrlPrefix(spaceId)}/api/spaces/v1/space/${tests.alreadyExists.space.id}`) + .auth(auth.username, auth.password) + .send(tests.alreadyExists.space) + .expect(tests.alreadyExists.statusCode) + .then(tests.alreadyExists.response); + }); + + describe(`when space doesn't exist`, () => { + it(`should return ${tests.newSpace.statusCode}`, async () => { + return supertest + .put(`${getUrlPrefix(spaceId)}/api/spaces/v1/space/${tests.newSpace.space.id}`) + .auth(auth.username, auth.password) + .send(tests.newSpace.space) + .expect(tests.newSpace.statusCode) + .then(tests.newSpace.response); + }); + }); + }); + }; + + const updateTest = makeUpdateTest(describe); + + const createExpectResult = (expectedResult: any) => (resp: any) => { + expect(resp.body).to.eql(expectedResult); + }; + + const createExpectNotFoundResult = (spaceId: string) => (resp: any) => { + expect(resp.body).to.eql({ + error: 'Not Found', + statusCode: 404, + message: `Saved object [space/${spaceId}] not found`, + }); + }; + + const createExpectForbiddenResult = () => (resp: any) => { + expect(resp.body).to.eql({ + statusCode: 403, + error: 'Forbidden', + message: 'Unauthorized to update spaces', + }); + }; + + const createExpectLegacyForbiddenResult = () => (resp: any) => { + expect(resp.body).to.eql({ + statusCode: 403, + error: 'Forbidden', + message: `action [indices:data/write/update] is unauthorized for user [a_kibana_legacy_dashboard_only_user]: [security_exception] action [indices:data/write/update] is unauthorized for user [a_kibana_legacy_dashboard_only_user]`, + }); + }; + + return { + updateTest, + createExpectResult, + createExpectNotFoundResult, + createExpectForbiddenResult, + createExpectLegacyForbiddenResult, + }; +} diff --git a/x-pack/test/spaces_api_integration/config.js b/x-pack/test/spaces_api_integration/config.js deleted file mode 100644 index d93381cbd76db..0000000000000 --- a/x-pack/test/spaces_api_integration/config.js +++ /dev/null @@ -1,57 +0,0 @@ -/* - * 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 { resolveKibanaPath } from '@kbn/plugin-helpers'; - -export default async function ({ readConfigFile }) { - - const config = { - kibana: { - api: await readConfigFile(resolveKibanaPath('test/api_integration/config.js')), - common: await readConfigFile(require.resolve('../../../test/common/config.js')), - functional: await readConfigFile(require.resolve('../../../test/functional/config.js')) - }, - xpack: { - api: await readConfigFile(require.resolve('../api_integration/config.js')), - functional: await readConfigFile(require.resolve('../functional/config.js')) - } - }; - - return { - testFiles: [require.resolve('./apis')], - servers: config.xpack.api.get('servers'), - services: { - es: config.kibana.common.get('services.es'), - supertest: config.kibana.api.get('services.supertest'), - supertestWithoutAuth: config.xpack.api.get('services.supertestWithoutAuth'), - esArchiver: config.kibana.functional.get('services.esArchiver'), - }, - junit: { - reportName: 'X-Pack Spaces API Integration Tests', - }, - - esArchiver: { - directory: path.join(__dirname, 'fixtures', 'es_archiver') - }, - - esTestCluster: { - ...config.xpack.api.get('esTestCluster'), - serverArgs: [ - ...config.xpack.api.get('esTestCluster.serverArgs'), - ], - }, - - kbnTestServer: { - ...config.xpack.api.get('kbnTestServer'), - serverArgs: [ - ...config.xpack.api.get('kbnTestServer.serverArgs'), - '--optimize.enabled=false', - '--server.xsrf.disableProtection=true', - ], - }, - }; -} diff --git a/x-pack/test/spaces_api_integration/security_and_spaces/apis/index.js b/x-pack/test/spaces_api_integration/security_and_spaces/apis/index.js new file mode 100644 index 0000000000000..ce8387f9845fc --- /dev/null +++ b/x-pack/test/spaces_api_integration/security_and_spaces/apis/index.js @@ -0,0 +1,19 @@ +/* + * 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 { createUsersAndRoles } from "../../common/lib/create_users_and_roles"; + +export default function ({ loadTestFile, getService }) { + const es = getService('es'); + const supertest = getService('supertest'); + + describe('apis spaces', () => { + before(async () => { + await createUsersAndRoles(es, supertest); + }); + + loadTestFile(require.resolve('./spaces')); + }); +} diff --git a/x-pack/test/spaces_api_integration/security_and_spaces/apis/spaces/create.ts b/x-pack/test/spaces_api_integration/security_and_spaces/apis/spaces/create.ts new file mode 100644 index 0000000000000..1783a44b8f883 --- /dev/null +++ b/x-pack/test/spaces_api_integration/security_and_spaces/apis/spaces/create.ts @@ -0,0 +1,324 @@ +/* + * 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 { AUTHENTICATION } from '../../../common/lib/authentication'; +import { SPACES } from '../../../common/lib/spaces'; +import { TestInvoker } from '../../../common/lib/types'; +import { createTestSuiteFactory } from '../../../common/suites/spaces/create'; + +// tslint:disable:no-default-export +export default function createSpacesOnlySuite({ getService }: TestInvoker) { + const supertestWithoutAuth = getService('supertestWithoutAuth'); + const esArchiver = getService('esArchiver'); + + const { + createTest, + createExpectResult, + createExpectConflictResponse, + createExpectForbiddenResponse, + createExpectLegacyForbiddenResponse, + } = createTestSuiteFactory(esArchiver, supertestWithoutAuth); + + describe('create', () => { + [ + { + spaceId: SPACES.DEFAULT.spaceId, + userWithAllGlobally: AUTHENTICATION.KIBANA_RBAC_USER, + userWithReadGlobally: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER, + userWithAllAtSpace: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_ALL_USER, + userWithLegacyAll: AUTHENTICATION.KIBANA_LEGACY_USER, + userWithLegacyRead: AUTHENTICATION.KIBANA_LEGACY_DASHBOARD_ONLY_USER, + userWithDualAll: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_USER, + userwithDualRead: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_DASHBOARD_ONLY_USER, + }, + { + spaceId: SPACES.SPACE_1.spaceId, + userWithAllGlobally: AUTHENTICATION.KIBANA_RBAC_USER, + userWithReadGlobally: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER, + userWithAllAtSpace: AUTHENTICATION.KIBANA_RBAC_SPACE_1_ALL_USER, + userWithLegacyAll: AUTHENTICATION.KIBANA_LEGACY_USER, + userWithLegacyRead: AUTHENTICATION.KIBANA_LEGACY_DASHBOARD_ONLY_USER, + userWithDualAll: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_USER, + userwithDualRead: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_DASHBOARD_ONLY_USER, + }, + ].forEach(scenario => { + createTest(`${scenario.userWithAllGlobally.USERNAME} within the ${scenario.spaceId} space`, { + spaceId: scenario.spaceId, + auth: { + username: scenario.userWithAllGlobally.USERNAME, + password: scenario.userWithAllGlobally.PASSWORD, + }, + tests: { + newSpace: { + space: { + name: 'marketing', + id: 'marketing', + description: 'a description', + color: '#5c5959', + }, + statusCode: 200, + response: createExpectResult({ + name: 'marketing', + id: 'marketing', + description: 'a description', + color: '#5c5959', + }), + }, + alreadyExists: { + statusCode: 409, + response: createExpectConflictResponse(), + }, + reservedSpecified: { + space: { + name: 'reserved space', + id: 'reserved', + description: 'a description', + color: '#5c5959', + _reserved: true, + }, + statusCode: 200, + response: createExpectResult({ + name: 'reserved space', + id: 'reserved', + description: 'a description', + color: '#5c5959', + }), + }, + }, + }); + + createTest(`${scenario.userWithDualAll.USERNAME} within the ${scenario.spaceId} space`, { + spaceId: scenario.spaceId, + auth: { + username: scenario.userWithDualAll.USERNAME, + password: scenario.userWithDualAll.PASSWORD, + }, + tests: { + newSpace: { + space: { + name: 'marketing', + id: 'marketing', + description: 'a description', + color: '#5c5959', + }, + statusCode: 200, + response: createExpectResult({ + name: 'marketing', + id: 'marketing', + description: 'a description', + color: '#5c5959', + }), + }, + alreadyExists: { + statusCode: 409, + response: createExpectConflictResponse(), + }, + reservedSpecified: { + space: { + name: 'reserved space', + id: 'reserved', + description: 'a description', + color: '#5c5959', + _reserved: true, + }, + statusCode: 200, + response: createExpectResult({ + name: 'reserved space', + id: 'reserved', + description: 'a description', + color: '#5c5959', + }), + }, + }, + }); + + createTest(`${scenario.userWithLegacyAll.USERNAME} within the ${scenario.spaceId} space`, { + spaceId: scenario.spaceId, + auth: { + username: scenario.userWithLegacyAll.USERNAME, + password: scenario.userWithLegacyAll.PASSWORD, + }, + tests: { + newSpace: { + space: { + name: 'marketing', + id: 'marketing', + description: 'a description', + color: '#5c5959', + }, + statusCode: 200, + response: createExpectResult({ + name: 'marketing', + id: 'marketing', + description: 'a description', + color: '#5c5959', + }), + }, + alreadyExists: { + statusCode: 409, + response: createExpectConflictResponse(), + }, + reservedSpecified: { + space: { + name: 'reserved space', + id: 'reserved', + description: 'a description', + color: '#5c5959', + _reserved: true, + }, + statusCode: 200, + response: createExpectResult({ + name: 'reserved space', + id: 'reserved', + description: 'a description', + color: '#5c5959', + }), + }, + }, + }); + + createTest(`${scenario.userWithReadGlobally.USERNAME} within the ${scenario.spaceId} space`, { + spaceId: scenario.spaceId, + auth: { + username: scenario.userWithReadGlobally.USERNAME, + password: scenario.userWithReadGlobally.PASSWORD, + }, + tests: { + newSpace: { + space: { + name: 'marketing', + id: 'marketing', + description: 'a description', + color: '#5c5959', + }, + statusCode: 403, + response: createExpectForbiddenResponse(), + }, + alreadyExists: { + statusCode: 403, + response: createExpectForbiddenResponse(), + }, + reservedSpecified: { + space: { + name: 'reserved space', + id: 'reserved', + description: 'a description', + color: '#5c5959', + _reserved: true, + }, + statusCode: 403, + response: createExpectForbiddenResponse(), + }, + }, + }); + + createTest(`${scenario.userwithDualRead.USERNAME} within the ${scenario.spaceId} space`, { + spaceId: scenario.spaceId, + auth: { + username: scenario.userwithDualRead.USERNAME, + password: scenario.userwithDualRead.PASSWORD, + }, + tests: { + newSpace: { + space: { + name: 'marketing', + id: 'marketing', + description: 'a description', + color: '#5c5959', + }, + statusCode: 403, + response: createExpectForbiddenResponse(), + }, + alreadyExists: { + statusCode: 403, + response: createExpectForbiddenResponse(), + }, + reservedSpecified: { + space: { + name: 'reserved space', + id: 'reserved', + description: 'a description', + color: '#5c5959', + _reserved: true, + }, + statusCode: 403, + response: createExpectForbiddenResponse(), + }, + }, + }); + + createTest(`${scenario.userWithLegacyRead.USERNAME} within the ${scenario.spaceId} space`, { + spaceId: scenario.spaceId, + auth: { + username: scenario.userWithLegacyRead.USERNAME, + password: scenario.userWithLegacyRead.PASSWORD, + }, + tests: { + newSpace: { + space: { + name: 'marketing', + id: 'marketing', + description: 'a description', + color: '#5c5959', + }, + statusCode: 403, + response: createExpectLegacyForbiddenResponse(), + }, + alreadyExists: { + statusCode: 403, + response: createExpectLegacyForbiddenResponse(), + }, + reservedSpecified: { + space: { + name: 'reserved space', + id: 'reserved', + description: 'a description', + color: '#5c5959', + _reserved: true, + }, + statusCode: 403, + response: createExpectLegacyForbiddenResponse(), + }, + }, + }); + + createTest(`${scenario.userWithAllAtSpace.USERNAME} within the ${scenario.spaceId} space`, { + spaceId: scenario.spaceId, + auth: { + username: scenario.userWithAllAtSpace.USERNAME, + password: scenario.userWithAllAtSpace.PASSWORD, + }, + tests: { + newSpace: { + space: { + name: 'marketing', + id: 'marketing', + description: 'a description', + color: '#5c5959', + }, + statusCode: 403, + response: createExpectForbiddenResponse(), + }, + alreadyExists: { + statusCode: 403, + response: createExpectForbiddenResponse(), + }, + reservedSpecified: { + space: { + name: 'reserved space', + id: 'reserved', + description: 'a description', + color: '#5c5959', + _reserved: true, + }, + statusCode: 403, + response: createExpectForbiddenResponse(), + }, + }, + }); + }); + }); +} diff --git a/x-pack/test/spaces_api_integration/security_and_spaces/apis/spaces/delete.ts b/x-pack/test/spaces_api_integration/security_and_spaces/apis/spaces/delete.ts new file mode 100644 index 0000000000000..4b76d42145958 --- /dev/null +++ b/x-pack/test/spaces_api_integration/security_and_spaces/apis/spaces/delete.ts @@ -0,0 +1,204 @@ +/* + * 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 { AUTHENTICATION } from '../../../common/lib/authentication'; +import { SPACES } from '../../../common/lib/spaces'; +import { TestInvoker } from '../../../common/lib/types'; +import { deleteTestSuiteFactory } from '../../../common/suites/spaces/delete'; + +// tslint:disable:no-default-export +export default function deleteSpaceTestSuite({ getService }: TestInvoker) { + const supertestWithoutAuth = getService('supertestWithoutAuth'); + const esArchiver = getService('esArchiver'); + + const { + deleteTest, + createExpectEmptyResult, + createExpectReservedSpaceResult, + createExpectNotFoundResult, + createExpectForbiddenResult, + createExpectLegacyForbiddenResult, + } = deleteTestSuiteFactory(esArchiver, supertestWithoutAuth); + + describe('delete', () => { + [ + { + spaceId: SPACES.DEFAULT.spaceId, + userWithAllGlobally: AUTHENTICATION.KIBANA_RBAC_USER, + userWithReadGlobally: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER, + userWithAllAtSpace: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_ALL_USER, + userWithLegacyAll: AUTHENTICATION.KIBANA_LEGACY_USER, + userWithLegacyRead: AUTHENTICATION.KIBANA_LEGACY_DASHBOARD_ONLY_USER, + userWithDualAll: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_USER, + userwithDualRead: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_DASHBOARD_ONLY_USER, + }, + { + spaceId: SPACES.SPACE_1.spaceId, + userWithAllGlobally: AUTHENTICATION.KIBANA_RBAC_USER, + userWithReadGlobally: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER, + userWithAllAtSpace: AUTHENTICATION.KIBANA_RBAC_SPACE_1_ALL_USER, + userWithLegacyAll: AUTHENTICATION.KIBANA_LEGACY_USER, + userWithLegacyRead: AUTHENTICATION.KIBANA_LEGACY_DASHBOARD_ONLY_USER, + userWithDualAll: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_USER, + userwithDualRead: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_DASHBOARD_ONLY_USER, + }, + ].forEach(scenario => { + deleteTest(`${scenario.userWithAllGlobally.USERNAME} from the ${scenario.spaceId} space`, { + spaceId: scenario.spaceId, + auth: { + username: scenario.userWithAllGlobally.USERNAME, + password: scenario.userWithAllGlobally.PASSWORD, + }, + tests: { + exists: { + statusCode: 204, + response: createExpectEmptyResult(), + }, + reservedSpace: { + statusCode: 400, + response: createExpectReservedSpaceResult(), + }, + doesntExist: { + statusCode: 404, + response: createExpectNotFoundResult(), + }, + }, + }); + + deleteTest(`${scenario.userWithDualAll.USERNAME} from the ${scenario.spaceId} space`, { + spaceId: scenario.spaceId, + auth: { + username: scenario.userWithDualAll.USERNAME, + password: scenario.userWithDualAll.PASSWORD, + }, + tests: { + exists: { + statusCode: 204, + response: createExpectEmptyResult(), + }, + reservedSpace: { + statusCode: 400, + response: createExpectReservedSpaceResult(), + }, + doesntExist: { + statusCode: 404, + response: createExpectNotFoundResult(), + }, + }, + }); + + deleteTest(`${scenario.userWithLegacyAll.USERNAME} from the ${scenario.spaceId} space`, { + spaceId: scenario.spaceId, + auth: { + username: scenario.userWithLegacyAll.USERNAME, + password: scenario.userWithLegacyAll.PASSWORD, + }, + tests: { + exists: { + statusCode: 204, + response: createExpectEmptyResult(), + }, + reservedSpace: { + statusCode: 400, + response: createExpectReservedSpaceResult(), + }, + doesntExist: { + statusCode: 404, + response: createExpectNotFoundResult(), + }, + }, + }); + + deleteTest(`${scenario.userWithReadGlobally.USERNAME} from the ${scenario.spaceId} space`, { + spaceId: scenario.spaceId, + auth: { + username: scenario.userWithReadGlobally.USERNAME, + password: scenario.userWithReadGlobally.PASSWORD, + }, + tests: { + exists: { + statusCode: 403, + response: createExpectForbiddenResult(), + }, + reservedSpace: { + statusCode: 403, + response: createExpectForbiddenResult(), + }, + doesntExist: { + statusCode: 403, + response: createExpectForbiddenResult(), + }, + }, + }); + + deleteTest(`${scenario.userwithDualRead.USERNAME} from the ${scenario.spaceId} space`, { + spaceId: scenario.spaceId, + auth: { + username: scenario.userwithDualRead.USERNAME, + password: scenario.userwithDualRead.PASSWORD, + }, + tests: { + exists: { + statusCode: 403, + response: createExpectForbiddenResult(), + }, + reservedSpace: { + statusCode: 403, + response: createExpectForbiddenResult(), + }, + doesntExist: { + statusCode: 403, + response: createExpectForbiddenResult(), + }, + }, + }); + + deleteTest(`${scenario.userWithLegacyRead.USERNAME} from the ${scenario.spaceId} space`, { + spaceId: scenario.spaceId, + auth: { + username: scenario.userWithLegacyRead.USERNAME, + password: scenario.userWithLegacyRead.PASSWORD, + }, + tests: { + exists: { + statusCode: 403, + response: createExpectLegacyForbiddenResult(), + }, + reservedSpace: { + statusCode: 400, + response: createExpectReservedSpaceResult(), + }, + doesntExist: { + statusCode: 404, + response: createExpectNotFoundResult(), + }, + }, + }); + + deleteTest(`${scenario.userWithAllAtSpace} from the ${scenario.spaceId} space`, { + spaceId: scenario.spaceId, + auth: { + username: scenario.userWithAllAtSpace.USERNAME, + password: scenario.userWithAllAtSpace.PASSWORD, + }, + tests: { + exists: { + statusCode: 403, + response: createExpectForbiddenResult(), + }, + reservedSpace: { + statusCode: 403, + response: createExpectForbiddenResult(), + }, + doesntExist: { + statusCode: 403, + response: createExpectForbiddenResult(), + }, + }, + }); + }); + }); +} diff --git a/x-pack/test/spaces_api_integration/security_and_spaces/apis/spaces/get.ts b/x-pack/test/spaces_api_integration/security_and_spaces/apis/spaces/get.ts new file mode 100644 index 0000000000000..001a7ab6379ee --- /dev/null +++ b/x-pack/test/spaces_api_integration/security_and_spaces/apis/spaces/get.ts @@ -0,0 +1,297 @@ +/* + * 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 { AUTHENTICATION } from '../../../common/lib/authentication'; +import { SPACES } from '../../../common/lib/spaces'; +import { TestInvoker } from '../../../common/lib/types'; +import { getTestSuiteFactory } from '../../../common/suites/spaces/get'; + +// tslint:disable:no-default-export +export default function getSpaceTestSuite({ getService }: TestInvoker) { + const supertestWithoutAuth = getService('supertestWithoutAuth'); + const esArchiver = getService('esArchiver'); + + const { + getTest, + createExpectResults, + createExpectNotFoundResult, + createExpectForbiddenResult, + nonExistantSpaceId, + } = getTestSuiteFactory(esArchiver, supertestWithoutAuth); + + describe('get', () => { + // valid spaces + [ + { + spaceId: SPACES.DEFAULT.spaceId, + otherSpaceId: SPACES.SPACE_1.spaceId, + userWithAllGlobally: AUTHENTICATION.KIBANA_RBAC_USER, + userWithReadGlobally: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER, + userWithAllAtSpace: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_ALL_USER, + userWithReadAtSpace: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_READ_USER, + userWithAllAtOtherSpace: AUTHENTICATION.KIBANA_RBAC_SPACE_1_ALL_USER, + userWithLegacyAll: AUTHENTICATION.KIBANA_LEGACY_USER, + userWithLegacyRead: AUTHENTICATION.KIBANA_LEGACY_DASHBOARD_ONLY_USER, + userWithDualAll: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_USER, + userwithDualRead: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_DASHBOARD_ONLY_USER, + }, + { + spaceId: SPACES.SPACE_1.spaceId, + otherSpaceId: SPACES.DEFAULT.spaceId, + userWithAllGlobally: AUTHENTICATION.KIBANA_RBAC_USER, + userWithReadGlobally: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER, + userWithAllAtSpace: AUTHENTICATION.KIBANA_RBAC_SPACE_1_ALL_USER, + userWithReadAtSpace: AUTHENTICATION.KIBANA_RBAC_SPACE_1_READ_USER, + userWithAllAtOtherSpace: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_ALL_USER, + userWithLegacyAll: AUTHENTICATION.KIBANA_LEGACY_USER, + userWithLegacyRead: AUTHENTICATION.KIBANA_LEGACY_DASHBOARD_ONLY_USER, + userWithDualAll: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_USER, + userwithDualRead: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_DASHBOARD_ONLY_USER, + }, + ].forEach(scenario => { + getTest(`${scenario.userWithAllGlobally.USERNAME}`, { + currentSpaceId: scenario.spaceId, + spaceId: scenario.spaceId, + auth: { + username: scenario.userWithAllGlobally.USERNAME, + password: scenario.userWithAllGlobally.PASSWORD, + }, + tests: { + default: { + statusCode: 200, + response: createExpectResults(scenario.spaceId), + }, + }, + }); + + getTest(`${scenario.userWithDualAll.USERNAME}`, { + currentSpaceId: scenario.spaceId, + spaceId: scenario.spaceId, + auth: { + username: scenario.userWithDualAll.USERNAME, + password: scenario.userWithDualAll.PASSWORD, + }, + tests: { + default: { + statusCode: 200, + response: createExpectResults(scenario.spaceId), + }, + }, + }); + + getTest(`${scenario.userWithLegacyAll.USERNAME}`, { + currentSpaceId: scenario.spaceId, + spaceId: scenario.spaceId, + auth: { + username: scenario.userWithLegacyAll.USERNAME, + password: scenario.userWithLegacyAll.PASSWORD, + }, + tests: { + default: { + statusCode: 200, + response: createExpectResults(scenario.spaceId), + }, + }, + }); + + getTest(`${scenario.userWithReadGlobally.USERNAME}`, { + currentSpaceId: scenario.spaceId, + spaceId: scenario.spaceId, + auth: { + username: scenario.userWithReadGlobally.USERNAME, + password: scenario.userWithReadGlobally.PASSWORD, + }, + tests: { + default: { + statusCode: 200, + response: createExpectResults(scenario.spaceId), + }, + }, + }); + + getTest(`${scenario.userwithDualRead.USERNAME}`, { + currentSpaceId: scenario.spaceId, + spaceId: scenario.spaceId, + auth: { + username: scenario.userwithDualRead.USERNAME, + password: scenario.userwithDualRead.PASSWORD, + }, + tests: { + default: { + statusCode: 200, + response: createExpectResults(scenario.spaceId), + }, + }, + }); + + getTest(`${scenario.userWithLegacyRead.USERNAME}`, { + currentSpaceId: scenario.spaceId, + spaceId: scenario.spaceId, + auth: { + username: scenario.userWithLegacyRead.USERNAME, + password: scenario.userWithLegacyRead.PASSWORD, + }, + tests: { + default: { + statusCode: 200, + response: createExpectResults(scenario.spaceId), + }, + }, + }); + + getTest(`${scenario.userWithReadAtSpace.USERNAME} at ${scenario.spaceId}`, { + currentSpaceId: scenario.spaceId, + spaceId: scenario.spaceId, + auth: { + username: scenario.userWithReadAtSpace.USERNAME, + password: scenario.userWithReadAtSpace.PASSWORD, + }, + tests: { + default: { + statusCode: 200, + response: createExpectResults(scenario.spaceId), + }, + }, + }); + + getTest(`${scenario.userWithAllAtOtherSpace.USERNAME} at a different space`, { + currentSpaceId: scenario.otherSpaceId, + spaceId: scenario.spaceId, + auth: { + username: scenario.userWithAllAtOtherSpace.USERNAME, + password: scenario.userWithAllAtOtherSpace.PASSWORD, + }, + tests: { + default: { + statusCode: 403, + response: createExpectForbiddenResult(scenario.spaceId), + }, + }, + }); + }); + + describe('non-existant space', () => { + [ + { + spaceId: SPACES.DEFAULT.spaceId, + otherSpaceId: nonExistantSpaceId, + userWithAllGlobally: AUTHENTICATION.KIBANA_RBAC_USER, + userWithReadGlobally: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER, + userWithAllAtSpace: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_ALL_USER, + userWithLegacyAll: AUTHENTICATION.KIBANA_LEGACY_USER, + userWithLegacyRead: AUTHENTICATION.KIBANA_LEGACY_DASHBOARD_ONLY_USER, + userWithDualAll: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_USER, + userwithDualRead: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_DASHBOARD_ONLY_USER, + }, + ].forEach(scenario => { + getTest(`${scenario.userWithAllGlobally.USERNAME}`, { + currentSpaceId: scenario.spaceId, + spaceId: scenario.otherSpaceId, + auth: { + username: scenario.userWithAllGlobally.USERNAME, + password: scenario.userWithAllGlobally.PASSWORD, + }, + tests: { + default: { + statusCode: 404, + response: createExpectNotFoundResult(scenario.otherSpaceId), + }, + }, + }); + + getTest(`${scenario.userWithDualAll.USERNAME}`, { + currentSpaceId: scenario.spaceId, + spaceId: scenario.otherSpaceId, + auth: { + username: scenario.userWithDualAll.USERNAME, + password: scenario.userWithDualAll.PASSWORD, + }, + tests: { + default: { + statusCode: 404, + response: createExpectNotFoundResult(scenario.otherSpaceId), + }, + }, + }); + + getTest(`${scenario.userWithLegacyAll.USERNAME}`, { + currentSpaceId: scenario.spaceId, + spaceId: scenario.otherSpaceId, + auth: { + username: scenario.userWithLegacyAll.USERNAME, + password: scenario.userWithLegacyAll.PASSWORD, + }, + tests: { + default: { + statusCode: 404, + response: createExpectNotFoundResult(scenario.otherSpaceId), + }, + }, + }); + + getTest(`${scenario.userWithReadGlobally.USERNAME}`, { + currentSpaceId: scenario.spaceId, + spaceId: scenario.otherSpaceId, + auth: { + username: scenario.userWithReadGlobally.USERNAME, + password: scenario.userWithReadGlobally.PASSWORD, + }, + tests: { + default: { + statusCode: 404, + response: createExpectNotFoundResult(scenario.otherSpaceId), + }, + }, + }); + + getTest(`${scenario.userwithDualRead.USERNAME}`, { + currentSpaceId: scenario.spaceId, + spaceId: scenario.otherSpaceId, + auth: { + username: scenario.userwithDualRead.USERNAME, + password: scenario.userwithDualRead.PASSWORD, + }, + tests: { + default: { + statusCode: 404, + response: createExpectNotFoundResult(scenario.otherSpaceId), + }, + }, + }); + + getTest(`${scenario.userWithLegacyRead.USERNAME}`, { + currentSpaceId: scenario.spaceId, + spaceId: scenario.otherSpaceId, + auth: { + username: scenario.userWithLegacyRead.USERNAME, + password: scenario.userWithLegacyRead.PASSWORD, + }, + tests: { + default: { + statusCode: 404, + response: createExpectNotFoundResult(scenario.otherSpaceId), + }, + }, + }); + + getTest(`${scenario.userWithAllAtSpace.USERNAME}`, { + currentSpaceId: scenario.spaceId, + spaceId: scenario.otherSpaceId, + auth: { + username: scenario.userWithAllAtSpace.USERNAME, + password: scenario.userWithAllAtSpace.PASSWORD, + }, + tests: { + default: { + statusCode: 403, + response: createExpectForbiddenResult(scenario.otherSpaceId), + }, + }, + }); + }); + }); + }); +} diff --git a/x-pack/test/spaces_api_integration/security_and_spaces/apis/spaces/get_all.ts b/x-pack/test/spaces_api_integration/security_and_spaces/apis/spaces/get_all.ts new file mode 100644 index 0000000000000..7c60296635b86 --- /dev/null +++ b/x-pack/test/spaces_api_integration/security_and_spaces/apis/spaces/get_all.ts @@ -0,0 +1,222 @@ +/* + * 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 { AUTHENTICATION } from '../../../common/lib/authentication'; +import { SPACES } from '../../../common/lib/spaces'; +import { TestInvoker } from '../../../common/lib/types'; +import { getAllTestSuiteFactory } from '../../../common/suites/spaces/get_all'; + +// tslint:disable:no-default-export +export default function getAllSpacesTestSuite({ getService }: TestInvoker) { + const supertestWithoutAuth = getService('supertestWithoutAuth'); + const esArchiver = getService('esArchiver'); + + const { getAllTest, createExpectResults } = getAllTestSuiteFactory( + esArchiver, + supertestWithoutAuth + ); + + describe('get all', () => { + [ + { + spaceId: SPACES.DEFAULT.spaceId, + userWithAllGlobally: AUTHENTICATION.KIBANA_RBAC_USER, + userWithReadGlobally: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER, + userWithAllAtSpace_1: AUTHENTICATION.KIBANA_RBAC_SPACE_1_ALL_USER, + userWithReadAtSpace_1: AUTHENTICATION.KIBANA_RBAC_SPACE_1_READ_USER, + userWithAllAtDefault: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_ALL_USER, + userWithReadAtDefault: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_READ_USER, + userWithLegacyAll: AUTHENTICATION.KIBANA_LEGACY_USER, + userWithLegacyRead: AUTHENTICATION.KIBANA_LEGACY_DASHBOARD_ONLY_USER, + userWithDualAll: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_USER, + userwithDualRead: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_DASHBOARD_ONLY_USER, + }, + { + spaceId: SPACES.SPACE_1.spaceId, + userWithAllGlobally: AUTHENTICATION.KIBANA_RBAC_USER, + userWithReadGlobally: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER, + userWithAllAtSpace_1: AUTHENTICATION.KIBANA_RBAC_SPACE_1_ALL_USER, + userWithReadAtSpace_1: AUTHENTICATION.KIBANA_RBAC_SPACE_1_READ_USER, + userWithAllAtDefault: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_ALL_USER, + userWithReadAtDefault: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_READ_USER, + userWithLegacyAll: AUTHENTICATION.KIBANA_LEGACY_USER, + userWithLegacyRead: AUTHENTICATION.KIBANA_LEGACY_DASHBOARD_ONLY_USER, + userWithDualAll: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_USER, + userwithDualRead: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_DASHBOARD_ONLY_USER, + }, + ].forEach(scenario => { + getAllTest( + `${scenario.userWithAllGlobally.USERNAME} can access all spaces from ${scenario.spaceId}`, + { + spaceId: scenario.spaceId, + auth: { + username: scenario.userWithAllGlobally.USERNAME, + password: scenario.userWithAllGlobally.PASSWORD, + }, + tests: { + exists: { + statusCode: 200, + response: createExpectResults('default', 'space_1', 'space_2'), + }, + }, + } + ); + + getAllTest( + `${scenario.userWithDualAll.USERNAME} can access all spaces from ${scenario.spaceId}`, + { + spaceId: scenario.spaceId, + auth: { + username: scenario.userWithDualAll.USERNAME, + password: scenario.userWithDualAll.PASSWORD, + }, + tests: { + exists: { + statusCode: 200, + response: createExpectResults('default', 'space_1', 'space_2'), + }, + }, + } + ); + + getAllTest( + `${scenario.userWithLegacyAll.USERNAME} can access all spaces from ${scenario.spaceId}`, + { + spaceId: scenario.spaceId, + auth: { + username: scenario.userWithLegacyAll.USERNAME, + password: scenario.userWithLegacyAll.PASSWORD, + }, + tests: { + exists: { + statusCode: 200, + response: createExpectResults('default', 'space_1', 'space_2'), + }, + }, + } + ); + + getAllTest( + `${scenario.userWithReadGlobally.USERNAME} can access all spaces from ${scenario.spaceId}`, + { + spaceId: scenario.spaceId, + auth: { + username: scenario.userWithReadGlobally.USERNAME, + password: scenario.userWithReadGlobally.PASSWORD, + }, + tests: { + exists: { + statusCode: 200, + response: createExpectResults('default', 'space_1', 'space_2'), + }, + }, + } + ); + + getAllTest( + `${scenario.userwithDualRead.USERNAME} can access all spaces from ${scenario.spaceId}`, + { + spaceId: scenario.spaceId, + auth: { + username: scenario.userwithDualRead.USERNAME, + password: scenario.userwithDualRead.PASSWORD, + }, + tests: { + exists: { + statusCode: 200, + response: createExpectResults('default', 'space_1', 'space_2'), + }, + }, + } + ); + + getAllTest( + `${scenario.userWithLegacyRead.USERNAME} can access all spaces from ${scenario.spaceId}`, + { + spaceId: scenario.spaceId, + auth: { + username: scenario.userWithLegacyRead.USERNAME, + password: scenario.userWithLegacyRead.PASSWORD, + }, + tests: { + exists: { + statusCode: 200, + response: createExpectResults('default', 'space_1', 'space_2'), + }, + }, + } + ); + + getAllTest( + `${scenario.userWithAllAtSpace_1.USERNAME} can access space_1 from ${scenario.spaceId}`, + { + spaceId: scenario.spaceId, + auth: { + username: scenario.userWithAllAtSpace_1.USERNAME, + password: scenario.userWithAllAtSpace_1.PASSWORD, + }, + tests: { + exists: { + statusCode: 200, + response: createExpectResults('space_1'), + }, + }, + } + ); + + getAllTest( + `${scenario.userWithReadAtSpace_1.USERNAME} can access space_1 from ${scenario.spaceId}`, + { + spaceId: scenario.spaceId, + auth: { + username: scenario.userWithReadAtSpace_1.USERNAME, + password: scenario.userWithReadAtSpace_1.PASSWORD, + }, + tests: { + exists: { + statusCode: 200, + response: createExpectResults('space_1'), + }, + }, + } + ); + + getAllTest( + `${scenario.userWithAllAtDefault.USERNAME} can access default from ${scenario.spaceId}`, + { + spaceId: scenario.spaceId, + auth: { + username: scenario.userWithAllAtDefault.USERNAME, + password: scenario.userWithAllAtDefault.PASSWORD, + }, + tests: { + exists: { + statusCode: 200, + response: createExpectResults('default'), + }, + }, + } + ); + + getAllTest( + `${scenario.userWithReadAtDefault.USERNAME} can access default from ${scenario.spaceId}`, + { + spaceId: scenario.spaceId, + auth: { + username: scenario.userWithReadAtDefault.USERNAME, + password: scenario.userWithReadAtDefault.PASSWORD, + }, + tests: { + exists: { + statusCode: 200, + response: createExpectResults('default'), + }, + }, + } + ); + }); + }); +} diff --git a/x-pack/test/spaces_api_integration/apis/saved_objects/index.js b/x-pack/test/spaces_api_integration/security_and_spaces/apis/spaces/index.ts similarity index 59% rename from x-pack/test/spaces_api_integration/apis/saved_objects/index.js rename to x-pack/test/spaces_api_integration/security_and_spaces/apis/spaces/index.ts index c74b03792ba03..3bf8127d39fb5 100644 --- a/x-pack/test/spaces_api_integration/apis/saved_objects/index.js +++ b/x-pack/test/spaces_api_integration/security_and_spaces/apis/spaces/index.ts @@ -4,15 +4,16 @@ * you may not use this file except in compliance with the Elastic License. */ +import { TestInvoker } from '../../../common/lib/types'; -export default function ({ loadTestFile }) { - - describe('saved_objects', () => { - loadTestFile(require.resolve('./bulk_get')); +// tslint:disable:no-default-export +export default function securityWithSpacesTestSuite({ loadTestFile }: TestInvoker) { + describe('spaces', () => { loadTestFile(require.resolve('./create')); loadTestFile(require.resolve('./delete')); - loadTestFile(require.resolve('./find')); + loadTestFile(require.resolve('./get_all')); loadTestFile(require.resolve('./get')); + loadTestFile(require.resolve('./select')); loadTestFile(require.resolve('./update')); }); } diff --git a/x-pack/test/spaces_api_integration/security_and_spaces/apis/spaces/select.ts b/x-pack/test/spaces_api_integration/security_and_spaces/apis/spaces/select.ts new file mode 100644 index 0000000000000..e211ea09f20c2 --- /dev/null +++ b/x-pack/test/spaces_api_integration/security_and_spaces/apis/spaces/select.ts @@ -0,0 +1,321 @@ +/* + * 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 { AUTHENTICATION } from '../../../common/lib/authentication'; +import { SPACES } from '../../../common/lib/spaces'; +import { TestInvoker } from '../../../common/lib/types'; +import { selectTestSuiteFactory } from '../../../common/suites/spaces/select'; + +// tslint:disable:no-default-export +export default function selectSpaceTestSuite({ getService }: TestInvoker) { + const supertestWithoutAuth = getService('supertestWithoutAuth'); + const esArchiver = getService('esArchiver'); + + const { + selectTest, + createExpectSpaceResponse, + createExpectForbiddenResult, + createExpectNotFoundResult, + nonExistantSpaceId, + } = selectTestSuiteFactory(esArchiver, supertestWithoutAuth); + + describe('select', () => { + // Global authorization tests + [ + { + spaceId: SPACES.DEFAULT.spaceId, + otherSpaceId: SPACES.SPACE_1.spaceId, + userWithAllGlobally: AUTHENTICATION.KIBANA_RBAC_USER, + userWithReadGlobally: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER, + userWithLegacyAll: AUTHENTICATION.KIBANA_LEGACY_USER, + userWithLegacyRead: AUTHENTICATION.KIBANA_LEGACY_DASHBOARD_ONLY_USER, + userWithDualAll: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_USER, + userWithDualRead: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_DASHBOARD_ONLY_USER, + }, + { + spaceId: SPACES.SPACE_1.spaceId, + otherSpaceId: SPACES.DEFAULT.spaceId, + userWithAllGlobally: AUTHENTICATION.KIBANA_RBAC_USER, + userWithReadGlobally: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER, + userWithLegacyAll: AUTHENTICATION.KIBANA_LEGACY_USER, + userWithLegacyRead: AUTHENTICATION.KIBANA_LEGACY_DASHBOARD_ONLY_USER, + userWithDualAll: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_USER, + userWithDualRead: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_DASHBOARD_ONLY_USER, + }, + ].forEach(scenario => { + selectTest(`${scenario.userWithAllGlobally.USERNAME} selects ${scenario.otherSpaceId}`, { + currentSpaceId: scenario.spaceId, + spaceId: scenario.otherSpaceId, + auth: { + username: scenario.userWithAllGlobally.USERNAME, + password: scenario.userWithAllGlobally.PASSWORD, + }, + tests: { + default: { + statusCode: 200, + response: createExpectSpaceResponse(scenario.otherSpaceId), + }, + }, + }); + + selectTest(`${scenario.userWithDualAll.USERNAME} selects ${scenario.otherSpaceId}`, { + currentSpaceId: scenario.spaceId, + spaceId: scenario.otherSpaceId, + auth: { + username: scenario.userWithDualAll.USERNAME, + password: scenario.userWithDualAll.PASSWORD, + }, + tests: { + default: { + statusCode: 200, + response: createExpectSpaceResponse(scenario.otherSpaceId), + }, + }, + }); + + selectTest(`${scenario.userWithLegacyAll.USERNAME} selects ${scenario.otherSpaceId}`, { + currentSpaceId: scenario.spaceId, + spaceId: scenario.otherSpaceId, + auth: { + username: scenario.userWithLegacyAll.USERNAME, + password: scenario.userWithLegacyAll.PASSWORD, + }, + tests: { + default: { + statusCode: 200, + response: createExpectSpaceResponse(scenario.otherSpaceId), + }, + }, + }); + + selectTest( + `${scenario.userWithReadGlobally.USERNAME} selects ${scenario.otherSpaceId} from + ${scenario.spaceId}`, + { + currentSpaceId: scenario.spaceId, + spaceId: scenario.otherSpaceId, + auth: { + username: scenario.userWithReadGlobally.USERNAME, + password: scenario.userWithReadGlobally.PASSWORD, + }, + tests: { + default: { + statusCode: 200, + response: createExpectSpaceResponse(scenario.otherSpaceId), + }, + }, + } + ); + + selectTest( + `${scenario.userWithDualRead.USERNAME} selects ${scenario.otherSpaceId} from + ${scenario.spaceId}`, + { + currentSpaceId: scenario.spaceId, + spaceId: scenario.otherSpaceId, + auth: { + username: scenario.userWithDualRead.USERNAME, + password: scenario.userWithDualRead.PASSWORD, + }, + tests: { + default: { + statusCode: 200, + response: createExpectSpaceResponse(scenario.otherSpaceId), + }, + }, + } + ); + + selectTest( + `${scenario.userWithLegacyRead.USERNAME} can select ${scenario.otherSpaceId} + from ${scenario.spaceId}`, + { + currentSpaceId: scenario.spaceId, + spaceId: scenario.otherSpaceId, + auth: { + username: scenario.userWithLegacyRead.USERNAME, + password: scenario.userWithLegacyRead.PASSWORD, + }, + tests: { + default: { + statusCode: 200, + response: createExpectSpaceResponse(scenario.otherSpaceId), + }, + }, + } + ); + }); + + // Same-Space authorization tests + [ + { + spaceId: SPACES.DEFAULT.spaceId, + userWithAllAtSpace: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_ALL_USER, + userWithReadAtSpace: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_READ_USER, + userWithAllAtOtherSpace: AUTHENTICATION.KIBANA_RBAC_SPACE_1_ALL_USER, + }, + { + spaceId: SPACES.SPACE_1.spaceId, + userWithAllAtSpace: AUTHENTICATION.KIBANA_RBAC_SPACE_1_ALL_USER, + userWithReadAtSpace: AUTHENTICATION.KIBANA_RBAC_SPACE_1_READ_USER, + userWithAllAtOtherSpace: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_ALL_USER, + }, + ].forEach(scenario => { + selectTest( + `${scenario.userWithAllAtSpace.USERNAME} can select ${scenario.spaceId} + from ${scenario.spaceId}`, + { + currentSpaceId: scenario.spaceId, + spaceId: scenario.spaceId, + auth: { + username: scenario.userWithAllAtSpace.USERNAME, + password: scenario.userWithAllAtSpace.PASSWORD, + }, + tests: { + default: { + statusCode: 200, + response: createExpectSpaceResponse(scenario.spaceId), + }, + }, + } + ); + + selectTest( + `${scenario.userWithReadAtSpace.USERNAME} can select ${scenario.spaceId} + from ${scenario.spaceId}`, + { + currentSpaceId: scenario.spaceId, + spaceId: scenario.spaceId, + auth: { + username: scenario.userWithReadAtSpace.USERNAME, + password: scenario.userWithReadAtSpace.PASSWORD, + }, + tests: { + default: { + statusCode: 200, + response: createExpectSpaceResponse(scenario.spaceId), + }, + }, + } + ); + + selectTest( + `${scenario.userWithAllAtOtherSpace.USERNAME} cannot select ${scenario.spaceId} + from ${scenario.spaceId}`, + { + currentSpaceId: scenario.spaceId, + spaceId: scenario.spaceId, + auth: { + username: scenario.userWithAllAtOtherSpace.USERNAME, + password: scenario.userWithAllAtOtherSpace.PASSWORD, + }, + tests: { + default: { + statusCode: 403, + response: createExpectForbiddenResult(scenario.spaceId), + }, + }, + } + ); + }); + + // Cross-Space authorization tests + [ + { + spaceId: SPACES.SPACE_1.spaceId, + otherSpaceId: SPACES.SPACE_2.spaceId, + userWithAllAtSpace: AUTHENTICATION.KIBANA_RBAC_SPACE_1_ALL_USER, + userWithAllAtOtherSpace: AUTHENTICATION.KIBANA_RBAC_SPACE_2_ALL_USER, + userWithAllAtBothSpaces: AUTHENTICATION.KIBANA_RBAC_SPACE_1_2_ALL_USER, + }, + ].forEach(scenario => { + selectTest( + `${scenario.userWithAllAtBothSpaces.USERNAME} can select ${scenario.spaceId} + from ${scenario.otherSpaceId}`, + { + currentSpaceId: scenario.otherSpaceId, + spaceId: scenario.spaceId, + auth: { + username: scenario.userWithAllAtBothSpaces.USERNAME, + password: scenario.userWithAllAtBothSpaces.PASSWORD, + }, + tests: { + default: { + statusCode: 200, + response: createExpectSpaceResponse(scenario.spaceId), + }, + }, + } + ); + + selectTest( + `${scenario.userWithAllAtOtherSpace.USERNAME} cannot select ${scenario.spaceId} + from ${scenario.otherSpaceId}`, + { + currentSpaceId: scenario.otherSpaceId, + spaceId: scenario.spaceId, + auth: { + username: scenario.userWithAllAtOtherSpace.USERNAME, + password: scenario.userWithAllAtOtherSpace.PASSWORD, + }, + tests: { + default: { + statusCode: 403, + response: createExpectForbiddenResult(scenario.spaceId), + }, + }, + } + ); + }); + + describe('non-existant space', () => { + [ + { + spaceId: SPACES.DEFAULT.spaceId, + otherSpaceId: nonExistantSpaceId, + userWithAllGlobally: AUTHENTICATION.KIBANA_RBAC_USER, + userWithAllAtSpace: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_ALL_USER, + }, + { + spaceId: SPACES.SPACE_1.spaceId, + otherSpaceId: nonExistantSpaceId, + userWithAllGlobally: AUTHENTICATION.KIBANA_RBAC_USER, + userWithAllAtSpace: AUTHENTICATION.KIBANA_RBAC_SPACE_1_ALL_USER, + }, + ].forEach(scenario => { + selectTest(`${scenario.userWithAllGlobally.USERNAME} cannot access non-existant space`, { + currentSpaceId: scenario.spaceId, + spaceId: scenario.otherSpaceId, + auth: { + username: scenario.userWithAllGlobally.USERNAME, + password: scenario.userWithAllGlobally.PASSWORD, + }, + tests: { + default: { + statusCode: 404, + response: createExpectNotFoundResult(nonExistantSpaceId), + }, + }, + }); + + selectTest(`${scenario.userWithAllAtSpace.USERNAME} cannot access non-existant space`, { + currentSpaceId: scenario.spaceId, + spaceId: scenario.otherSpaceId, + auth: { + username: scenario.userWithAllAtSpace.USERNAME, + password: scenario.userWithAllAtSpace.PASSWORD, + }, + tests: { + default: { + statusCode: 403, + response: createExpectForbiddenResult(nonExistantSpaceId), + }, + }, + }); + }); + }); + }); +} diff --git a/x-pack/test/spaces_api_integration/security_and_spaces/apis/spaces/update.ts b/x-pack/test/spaces_api_integration/security_and_spaces/apis/spaces/update.ts new file mode 100644 index 0000000000000..d6597f1fee1f2 --- /dev/null +++ b/x-pack/test/spaces_api_integration/security_and_spaces/apis/spaces/update.ts @@ -0,0 +1,338 @@ +/* + * 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 { AUTHENTICATION } from '../../../common/lib/authentication'; +import { SPACES } from '../../../common/lib/spaces'; +import { TestInvoker } from '../../../common/lib/types'; +import { updateTestSuiteFactory } from '../../../common/suites/spaces/update'; + +// tslint:disable:no-default-export +export default function updateSpaceTestSuite({ getService }: TestInvoker) { + const supertestWithoutAuth = getService('supertestWithoutAuth'); + const esArchiver = getService('esArchiver'); + + const { + updateTest, + createExpectResult, + createExpectNotFoundResult, + createExpectForbiddenResult, + createExpectLegacyForbiddenResult, + } = updateTestSuiteFactory(esArchiver, supertestWithoutAuth); + + describe('update', () => { + [ + { + spaceId: SPACES.DEFAULT.spaceId, + userWithAllGlobally: AUTHENTICATION.KIBANA_RBAC_USER, + userWithReadGlobally: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER, + userWithAllAtSpace: AUTHENTICATION.KIBANA_RBAC_SPACE_1_ALL_USER, + userWithReadAtSpace: AUTHENTICATION.KIBANA_RBAC_SPACE_1_READ_USER, + userWithLegacyAll: AUTHENTICATION.KIBANA_LEGACY_USER, + userWithLegacyRead: AUTHENTICATION.KIBANA_LEGACY_DASHBOARD_ONLY_USER, + userWithDualAll: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_USER, + userWithDualRead: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_DASHBOARD_ONLY_USER, + }, + { + spaceId: SPACES.SPACE_1.spaceId, + userWithAllGlobally: AUTHENTICATION.KIBANA_RBAC_USER, + userWithReadGlobally: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER, + userWithAllAtSpace: AUTHENTICATION.KIBANA_RBAC_SPACE_1_ALL_USER, + userWithReadAtSpace: AUTHENTICATION.KIBANA_RBAC_SPACE_1_READ_USER, + userWithLegacyAll: AUTHENTICATION.KIBANA_LEGACY_USER, + userWithLegacyRead: AUTHENTICATION.KIBANA_LEGACY_DASHBOARD_ONLY_USER, + userWithDualAll: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_USER, + userWithDualRead: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_DASHBOARD_ONLY_USER, + }, + ].forEach(scenario => { + updateTest( + `${scenario.userWithAllGlobally.USERNAME} can update space_1 from + the ${scenario.spaceId} space`, + { + spaceId: scenario.spaceId, + auth: { + username: scenario.userWithAllGlobally.USERNAME, + password: scenario.userWithAllGlobally.PASSWORD, + }, + tests: { + alreadyExists: { + space: { + name: 'space 1', + id: 'space_1', + description: 'a description', + color: '#5c5959', + _reserved: true, + }, + statusCode: 200, + response: createExpectResult({ + name: 'space 1', + id: 'space_1', + description: 'a description', + color: '#5c5959', + }), + }, + newSpace: { + space: { + name: 'marketing', + id: 'marketing', + description: 'a description', + color: '#5c5959', + }, + statusCode: 404, + response: createExpectNotFoundResult('marketing'), + }, + }, + } + ); + + updateTest( + `${scenario.userWithDualAll.USERNAME} can update space_1 from + the ${scenario.spaceId} space`, + { + spaceId: scenario.spaceId, + auth: { + username: scenario.userWithDualAll.USERNAME, + password: scenario.userWithDualAll.PASSWORD, + }, + tests: { + alreadyExists: { + space: { + name: 'space 1', + id: 'space_1', + description: 'a description', + color: '#5c5959', + _reserved: true, + }, + statusCode: 200, + response: createExpectResult({ + name: 'space 1', + id: 'space_1', + description: 'a description', + color: '#5c5959', + }), + }, + newSpace: { + space: { + name: 'marketing', + id: 'marketing', + description: 'a description', + color: '#5c5959', + }, + statusCode: 404, + response: createExpectNotFoundResult('marketing'), + }, + }, + } + ); + + updateTest( + `${scenario.userWithLegacyAll.USERNAME} can update space_1 from + the ${scenario.spaceId} space`, + { + spaceId: scenario.spaceId, + auth: { + username: scenario.userWithLegacyAll.USERNAME, + password: scenario.userWithLegacyAll.PASSWORD, + }, + tests: { + alreadyExists: { + space: { + name: 'space 1', + id: 'space_1', + description: 'a description', + color: '#5c5959', + _reserved: true, + }, + statusCode: 200, + response: createExpectResult({ + name: 'space 1', + id: 'space_1', + description: 'a description', + color: '#5c5959', + }), + }, + newSpace: { + space: { + name: 'marketing', + id: 'marketing', + description: 'a description', + color: '#5c5959', + }, + statusCode: 404, + response: createExpectNotFoundResult('marketing'), + }, + }, + } + ); + + updateTest( + `${scenario.userWithReadGlobally.USERNAME} cannot update space_1 + from the ${scenario.spaceId} space`, + { + spaceId: scenario.spaceId, + auth: { + username: scenario.userWithReadGlobally.USERNAME, + password: scenario.userWithReadGlobally.PASSWORD, + }, + tests: { + alreadyExists: { + space: { + name: 'space 1', + id: 'space_1', + description: 'a description', + color: '#5c5959', + _reserved: true, + }, + statusCode: 403, + response: createExpectForbiddenResult(), + }, + newSpace: { + space: { + name: 'marketing', + id: 'marketing', + description: 'a description', + color: '#5c5959', + }, + statusCode: 403, + response: createExpectForbiddenResult(), + }, + }, + } + ); + + updateTest( + `${scenario.userWithDualRead.USERNAME} cannot update space_1 + from the ${scenario.spaceId} space`, + { + spaceId: scenario.spaceId, + auth: { + username: scenario.userWithDualRead.USERNAME, + password: scenario.userWithDualRead.PASSWORD, + }, + tests: { + alreadyExists: { + space: { + name: 'space 1', + id: 'space_1', + description: 'a description', + color: '#5c5959', + _reserved: true, + }, + statusCode: 403, + response: createExpectForbiddenResult(), + }, + newSpace: { + space: { + name: 'marketing', + id: 'marketing', + description: 'a description', + color: '#5c5959', + }, + statusCode: 403, + response: createExpectForbiddenResult(), + }, + }, + } + ); + + updateTest( + `${scenario.userWithLegacyRead.USERNAME} cannot update space_1 + from the ${scenario.spaceId} space`, + { + spaceId: scenario.spaceId, + auth: { + username: scenario.userWithLegacyRead.USERNAME, + password: scenario.userWithLegacyRead.PASSWORD, + }, + tests: { + alreadyExists: { + space: { + name: 'space 1', + id: 'space_1', + description: 'a description', + color: '#5c5959', + _reserved: true, + }, + statusCode: 403, + response: createExpectLegacyForbiddenResult(), + }, + newSpace: { + space: { + name: 'marketing', + id: 'marketing', + description: 'a description', + color: '#5c5959', + }, + statusCode: 403, + response: createExpectLegacyForbiddenResult(), + }, + }, + } + ); + + updateTest(`${scenario.userWithAllAtSpace.USERNAME} cannot update space_1`, { + spaceId: scenario.spaceId, + auth: { + username: scenario.userWithAllAtSpace.USERNAME, + password: scenario.userWithAllAtSpace.PASSWORD, + }, + tests: { + alreadyExists: { + space: { + name: 'space 1', + id: 'space_1', + description: 'a description', + color: '#5c5959', + _reserved: true, + }, + statusCode: 403, + response: createExpectForbiddenResult(), + }, + newSpace: { + space: { + name: 'marketing', + id: 'marketing', + description: 'a description', + color: '#5c5959', + }, + statusCode: 403, + response: createExpectForbiddenResult(), + }, + }, + }); + + updateTest(`${scenario.userWithReadAtSpace.USERNAME} cannot update space_1`, { + spaceId: scenario.spaceId, + auth: { + username: scenario.userWithReadAtSpace.USERNAME, + password: scenario.userWithReadAtSpace.PASSWORD, + }, + tests: { + alreadyExists: { + space: { + name: 'space 1', + id: 'space_1', + description: 'a description', + color: '#5c5959', + _reserved: true, + }, + statusCode: 403, + response: createExpectForbiddenResult(), + }, + newSpace: { + space: { + name: 'marketing', + id: 'marketing', + description: 'a description', + color: '#5c5959', + }, + statusCode: 403, + response: createExpectForbiddenResult(), + }, + }, + }); + }); + }); +} diff --git a/x-pack/test/spaces_api_integration/security_and_spaces/config.js b/x-pack/test/spaces_api_integration/security_and_spaces/config.js new file mode 100644 index 0000000000000..5873a050577d7 --- /dev/null +++ b/x-pack/test/spaces_api_integration/security_and_spaces/config.js @@ -0,0 +1,9 @@ +/* + * 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'; + +export default createTestConfig('security_and_spaces', { license: 'trial' }); diff --git a/x-pack/test/spaces_api_integration/apis/index.js b/x-pack/test/spaces_api_integration/spaces_only/apis/index.js similarity index 79% rename from x-pack/test/spaces_api_integration/apis/index.js rename to x-pack/test/spaces_api_integration/spaces_only/apis/index.js index 309b845b6f3c2..21ff2b3ed5eae 100644 --- a/x-pack/test/spaces_api_integration/apis/index.js +++ b/x-pack/test/spaces_api_integration/spaces_only/apis/index.js @@ -5,8 +5,7 @@ */ export default function ({ loadTestFile }) { - describe('apis spaces', () => { - loadTestFile(require.resolve('./saved_objects')); + describe('apis spaces without security', () => { loadTestFile(require.resolve('./spaces')); }); } diff --git a/x-pack/test/spaces_api_integration/spaces_only/apis/spaces/create.ts b/x-pack/test/spaces_api_integration/spaces_only/apis/spaces/create.ts new file mode 100644 index 0000000000000..3deb0c9aa3892 --- /dev/null +++ b/x-pack/test/spaces_api_integration/spaces_only/apis/spaces/create.ts @@ -0,0 +1,72 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { SPACES } from '../../../common/lib/spaces'; +import { TestInvoker } from '../../../common/lib/types'; +import { createTestSuiteFactory } from '../../../common/suites/spaces/create'; + +// tslint:disable:no-default-export +export default function createSpacesOnlySuite({ getService }: TestInvoker) { + const supertestWithoutAuth = getService('supertestWithoutAuth'); + const esArchiver = getService('esArchiver'); + + const { createTest, createExpectResult, createExpectConflictResponse } = createTestSuiteFactory( + esArchiver, + supertestWithoutAuth + ); + + describe('create', () => { + [ + { + spaceId: SPACES.DEFAULT.spaceId, + }, + { + spaceId: SPACES.SPACE_1.spaceId, + }, + ].forEach(scenario => { + createTest(`from the ${scenario.spaceId} space`, { + spaceId: scenario.spaceId, + tests: { + newSpace: { + space: { + name: 'marketing', + id: 'marketing', + description: 'a description', + color: '#5c5959', + }, + statusCode: 200, + response: createExpectResult({ + name: 'marketing', + id: 'marketing', + description: 'a description', + color: '#5c5959', + }), + }, + alreadyExists: { + statusCode: 409, + response: createExpectConflictResponse(), + }, + reservedSpecified: { + space: { + name: 'reserved space', + id: 'reserved', + description: 'a description', + color: '#5c5959', + _reserved: true, + }, + statusCode: 200, + response: createExpectResult({ + name: 'reserved space', + id: 'reserved', + description: 'a description', + color: '#5c5959', + }), + }, + }, + }); + }); + }); +} diff --git a/x-pack/test/spaces_api_integration/spaces_only/apis/spaces/delete.ts b/x-pack/test/spaces_api_integration/spaces_only/apis/spaces/delete.ts new file mode 100644 index 0000000000000..333b23bd59e91 --- /dev/null +++ b/x-pack/test/spaces_api_integration/spaces_only/apis/spaces/delete.ts @@ -0,0 +1,50 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { SPACES } from '../../../common/lib/spaces'; +import { deleteTestSuiteFactory } from '../../../common/suites/spaces/delete'; + +// tslint:disable:no-default-export +export default function deleteSpaceTestSuite({ getService }) { + const supertestWithoutAuth = getService('supertestWithoutAuth'); + const esArchiver = getService('esArchiver'); + + const { + deleteTest, + createExpectEmptyResult, + createExpectReservedSpaceResult, + createExpectNotFoundResult, + } = deleteTestSuiteFactory(esArchiver, supertestWithoutAuth); + + describe('delete', () => { + [ + { + spaceId: SPACES.DEFAULT.spaceId, + }, + { + spaceId: SPACES.SPACE_1.spaceId, + }, + ].forEach(scenario => { + deleteTest(`from the ${scenario.spaceId} space`, { + spaceId: scenario.spaceId, + tests: { + exists: { + statusCode: 204, + response: createExpectEmptyResult(), + }, + reservedSpace: { + statusCode: 400, + response: createExpectReservedSpaceResult(), + }, + doesntExist: { + statusCode: 404, + response: createExpectNotFoundResult(), + }, + }, + }); + }); + }); +} diff --git a/x-pack/test/spaces_api_integration/spaces_only/apis/spaces/get.ts b/x-pack/test/spaces_api_integration/spaces_only/apis/spaces/get.ts new file mode 100644 index 0000000000000..4e547de15e247 --- /dev/null +++ b/x-pack/test/spaces_api_integration/spaces_only/apis/spaces/get.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 { SPACES } from '../../../common/lib/spaces'; +import { getTestSuiteFactory } from '../../../common/suites/spaces/get'; + +// tslint:disable:no-default-export +export default function getSpaceTestSuite({ getService }) { + const supertestWithoutAuth = getService('supertestWithoutAuth'); + const esArchiver = getService('esArchiver'); + + const { + getTest, + createExpectResults, + createExpectNotFoundResult, + nonExistantSpaceId, + } = getTestSuiteFactory(esArchiver, supertestWithoutAuth); + + describe('get', () => { + // valid spaces + [ + { + currentSpaceId: SPACES.DEFAULT.spaceId, + spaceId: SPACES.DEFAULT.spaceId, + }, + { + currentSpaceId: SPACES.DEFAULT.spaceId, + spaceId: SPACES.SPACE_1.spaceId, + }, + { + currentSpaceId: SPACES.SPACE_1.spaceId, + spaceId: SPACES.DEFAULT.spaceId, + }, + { + currentSpaceId: SPACES.SPACE_1.spaceId, + spaceId: SPACES.SPACE_1.spaceId, + }, + ].forEach(scenario => { + getTest(`can access ${scenario.spaceId} from within the ${scenario.currentSpaceId} space`, { + spaceId: scenario.spaceId, + currentSpaceId: scenario.currentSpaceId, + tests: { + default: { + statusCode: 200, + response: createExpectResults(scenario.spaceId), + }, + }, + }); + }); + + // invalid spaces + [ + { + currentSpaceId: SPACES.DEFAULT.spaceId, + spaceId: nonExistantSpaceId, + }, + ].forEach(scenario => { + getTest(`can't access ${scenario.spaceId} from within the ${scenario.currentSpaceId} space`, { + spaceId: scenario.spaceId, + currentSpaceId: scenario.currentSpaceId, + tests: { + default: { + statusCode: 404, + response: createExpectNotFoundResult(scenario.spaceId), + }, + }, + }); + }); + }); +} diff --git a/x-pack/test/spaces_api_integration/spaces_only/apis/spaces/get_all.ts b/x-pack/test/spaces_api_integration/spaces_only/apis/spaces/get_all.ts new file mode 100644 index 0000000000000..cd11b8045679d --- /dev/null +++ b/x-pack/test/spaces_api_integration/spaces_only/apis/spaces/get_all.ts @@ -0,0 +1,40 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { SPACES } from '../../../common/lib/spaces'; +import { getAllTestSuiteFactory } from '../../../common/suites/spaces/get_all'; + +// tslint:disable:no-default-export +export default function getAllSpacesTestSuite({ getService }) { + const supertestWithoutAuth = getService('supertestWithoutAuth'); + const esArchiver = getService('esArchiver'); + + const { getAllTest, createExpectResults } = getAllTestSuiteFactory( + esArchiver, + supertestWithoutAuth + ); + + describe('get all', () => { + [ + { + spaceId: SPACES.DEFAULT.spaceId, + }, + { + spaceId: SPACES.SPACE_1.spaceId, + }, + ].forEach(scenario => { + getAllTest(`can access all spaces from ${scenario.spaceId}`, { + spaceId: scenario.spaceId, + tests: { + exists: { + statusCode: 200, + response: createExpectResults('default', 'space_1', 'space_2'), + }, + }, + }); + }); + }); +} diff --git a/x-pack/test/spaces_api_integration/apis/spaces/index.js b/x-pack/test/spaces_api_integration/spaces_only/apis/spaces/index.ts similarity index 84% rename from x-pack/test/spaces_api_integration/apis/spaces/index.js rename to x-pack/test/spaces_api_integration/spaces_only/apis/spaces/index.ts index 3530bc0045eb9..08b2e389efd8d 100644 --- a/x-pack/test/spaces_api_integration/apis/spaces/index.js +++ b/x-pack/test/spaces_api_integration/spaces_only/apis/spaces/index.ts @@ -4,9 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ - -export default function ({ loadTestFile }) { - +// tslint:disable:no-default-export +export default function spacesOnlyTestSuite({ loadTestFile }) { describe('spaces', () => { loadTestFile(require.resolve('./create')); loadTestFile(require.resolve('./delete')); diff --git a/x-pack/test/spaces_api_integration/spaces_only/apis/spaces/select.ts b/x-pack/test/spaces_api_integration/spaces_only/apis/spaces/select.ts new file mode 100644 index 0000000000000..8de630fa9f7f8 --- /dev/null +++ b/x-pack/test/spaces_api_integration/spaces_only/apis/spaces/select.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 { SPACES } from '../../../common/lib/spaces'; +import { selectTestSuiteFactory } from '../../../common/suites/spaces/select'; + +// tslint:disable:no-default-export +export default function selectSpaceTestSuite({ getService }) { + const supertestWithoutAuth = getService('supertestWithoutAuth'); + const esArchiver = getService('esArchiver'); + + const { + selectTest, + createExpectSpaceResponse, + createExpectNotFoundResult, + nonExistantSpaceId, + } = selectTestSuiteFactory(esArchiver, supertestWithoutAuth); + + describe('select', () => { + [ + { + spaceId: SPACES.DEFAULT.spaceId, + otherSpaceId: SPACES.SPACE_1.spaceId, + }, + { + spaceId: SPACES.SPACE_1.spaceId, + otherSpaceId: SPACES.DEFAULT.spaceId, + }, + { + spaceId: SPACES.SPACE_1.spaceId, + otherSpaceId: SPACES.SPACE_2.spaceId, + }, + ].forEach(scenario => { + selectTest(`can select ${scenario.otherSpaceId} from ${scenario.spaceId}`, { + currentSpaceId: scenario.spaceId, + spaceId: scenario.otherSpaceId, + tests: { + default: { + statusCode: 200, + response: createExpectSpaceResponse(scenario.otherSpaceId), + }, + }, + }); + }); + + describe('non-existant space', () => { + [ + { + spaceId: SPACES.DEFAULT.spaceId, + otherSpaceId: nonExistantSpaceId, + }, + { + spaceId: SPACES.SPACE_1.spaceId, + otherSpaceId: nonExistantSpaceId, + }, + ].forEach(scenario => { + selectTest(`cannot select non-existant space from ${scenario.spaceId}`, { + currentSpaceId: scenario.spaceId, + spaceId: scenario.otherSpaceId, + tests: { + default: { + statusCode: 404, + response: createExpectNotFoundResult(scenario.otherSpaceId), + }, + }, + }); + }); + }); + }); +} diff --git a/x-pack/test/spaces_api_integration/spaces_only/apis/spaces/update.ts b/x-pack/test/spaces_api_integration/spaces_only/apis/spaces/update.ts new file mode 100644 index 0000000000000..d3426a0a816fa --- /dev/null +++ b/x-pack/test/spaces_api_integration/spaces_only/apis/spaces/update.ts @@ -0,0 +1,62 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { SPACES } from '../../../common/lib/spaces'; +import { updateTestSuiteFactory } from '../../../common/suites/spaces/update'; + +// tslint:disable:no-default-export +export default function updateSpaceTestSuite({ getService }) { + const supertestWithoutAuth = getService('supertestWithoutAuth'); + const esArchiver = getService('esArchiver'); + + const { updateTest, createExpectResult, createExpectNotFoundResult } = updateTestSuiteFactory( + esArchiver, + supertestWithoutAuth + ); + + describe('update', () => { + [ + { + spaceId: SPACES.DEFAULT.spaceId, + }, + { + spaceId: SPACES.SPACE_1.spaceId, + }, + ].forEach(scenario => { + updateTest(`can update space_1 from the ${scenario.spaceId} space`, { + spaceId: scenario.spaceId, + tests: { + alreadyExists: { + space: { + name: 'space 1', + id: 'space_1', + description: 'a description', + color: '#5c5959', + _reserved: true, + }, + statusCode: 200, + response: createExpectResult({ + name: 'space 1', + id: 'space_1', + description: 'a description', + color: '#5c5959', + }), + }, + newSpace: { + space: { + name: 'marketing', + id: 'marketing', + description: 'a description', + color: '#5c5959', + }, + statusCode: 404, + response: createExpectNotFoundResult('marketing'), + }, + }, + }); + }); + }); +} diff --git a/x-pack/test/spaces_api_integration/spaces_only/config.js b/x-pack/test/spaces_api_integration/spaces_only/config.js new file mode 100644 index 0000000000000..4b80c979ffdf0 --- /dev/null +++ b/x-pack/test/spaces_api_integration/spaces_only/config.js @@ -0,0 +1,8 @@ +/* + * 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'; + +export default createTestConfig('spaces_only', { license: 'basic', securityEnabled: false }); diff --git a/x-pack/tsconfig.json b/x-pack/tsconfig.json index 62bb8cb1d6b07..a5ae5cdd134bf 100644 --- a/x-pack/tsconfig.json +++ b/x-pack/tsconfig.json @@ -1,9 +1,9 @@ { - "extends": "../tsconfig.json", - "include": [ - "common/**/*", - "server/**/*", - "plugins/**/*", - "test/**/*", - ] -} + "extends": "../tsconfig.json", + "include": [ + "common/**/*", + "server/**/*", + "plugins/**/*", + "test/**/*", + ] +} \ No newline at end of file