diff --git a/x-pack/package.json b/x-pack/package.json index e3bb76db43ce2..85cc4a7cc8523 100644 --- a/x-pack/package.json +++ b/x-pack/package.json @@ -72,6 +72,7 @@ "tmp": "0.0.31", "tree-kill": "^1.1.0", "typescript": "^2.9.2", + "uuid": "3.0.1", "vinyl-fs": "^3.0.2", "xml-crypto": "^0.10.1", "xml2js": "^0.4.19", diff --git a/x-pack/plugins/spaces/server/lib/saved_objects_client/__snapshots__/spaces_saved_objects_client.test.js.snap b/x-pack/plugins/spaces/server/lib/saved_objects_client/__snapshots__/spaces_saved_objects_client.test.js.snap index 861b170685f99..9bd6165f8d057 100644 --- a/x-pack/plugins/spaces/server/lib/saved_objects_client/__snapshots__/spaces_saved_objects_client.test.js.snap +++ b/x-pack/plugins/spaces/server/lib/saved_objects_client/__snapshots__/spaces_saved_objects_client.test.js.snap @@ -1,13 +1,37 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`current space (space_1) #create #delete does not allow an object to be deleted via a different space 1`] = `"not found"`; +exports[`current space (space_1) #bulk_create throws when the base client returns a malformed document id 1`] = `"Saved object [foo/mock-id] is missing its expected space identifier."`; -exports[`current space (space_1) #create #update does not allow an object to be updated via a different space 1`] = `"not found"`; +exports[`current space (space_1) #bulk_get throws when base client returns documents with malformed ids 1`] = `"Saved object [foo/object_1] is missing its expected space identifier."`; -exports[`current space (space_1) #get returns error when the object belongs to a different space 1`] = `"not found"`; +exports[`current space (space_1) #create throws when the base client returns a malformed document id 1`] = `"Saved object [foo/mock-id] is missing its expected space identifier."`; -exports[`default space #delete does not allow an object to be deleted via a different space 1`] = `"not found"`; +exports[`current space (space_1) #delete does not allow an object to be deleted via a different space 1`] = `"not found: foo space_1:object_2"`; -exports[`default space #get returns error when the object belongs to a different space 1`] = `"not found"`; +exports[`current space (space_1) #find throws when base client returns documents with malformed ids 1`] = `"Saved object [foo/object_1] is missing its expected space identifier."`; -exports[`default space #update does not allow an object to be updated via a different space 1`] = `"not found"`; +exports[`current space (space_1) #get returns error when the object belongs to a different space 1`] = `"not found: foo space_1:object_2"`; + +exports[`current space (space_1) #get returns error when the object has a malformed identifier 1`] = `"Saved object [foo/object_1] is missing its expected space identifier."`; + +exports[`current space (space_1) #update does not allow an object to be updated via a different space 1`] = `"not found: foo space_1:object_2"`; + +exports[`current space (space_1) #update throws when the base client returns a malformed document id 1`] = `"Saved object [foo/object_1] is missing its expected space identifier."`; + +exports[`default space #bulk_create throws when the base client returns a malformed document id 1`] = `"Saved object [foo/default:default] has an unexpected space identifier [default]."`; + +exports[`default space #bulk_get throws when the base client returns a malformed document id 1`] = `"Saved object [foo/default:default] has an unexpected space identifier [default]."`; + +exports[`default space #create throws when the base client returns a malformed document id 1`] = `"Saved object [foo/default:default] has an unexpected space identifier [default]."`; + +exports[`default space #delete does not allow an object to be deleted via a different space 1`] = `"not found: foo object_2"`; + +exports[`default space #find throws when the base client returns a malformed document id 1`] = `"Saved object [foo/default:default] has an unexpected space identifier [default]."`; + +exports[`default space #get returns error when the object belongs to a different space 1`] = `"not found: foo object_2"`; + +exports[`default space #get throws when the base client returns a malformed document id 1`] = `"Saved object [foo/default:default] has an unexpected space identifier [default]."`; + +exports[`default space #update does not allow an object to be updated via a different space 1`] = `"not found: foo object_2"`; + +exports[`default space #update throws when the base client returns a malformed document id 1`] = `"Saved object [space/default:default] has an unexpected space identifier [default]."`; diff --git a/x-pack/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.js b/x-pack/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.js index 9fc4064723184..c9fd34a60b6d8 100644 --- a/x-pack/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.js +++ b/x-pack/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.js @@ -8,6 +8,7 @@ import { DEFAULT_SPACE_ID } from '../../../common/constants'; import { isTypeSpaceAware } from './lib/is_type_space_aware'; import { getSpacesQueryFilters } from './lib/query_filters'; import uniq from 'lodash'; +import uuid from 'uuid'; export class SpacesSavedObjectsClient { constructor(options) { @@ -45,7 +46,8 @@ export class SpacesSavedObjectsClient { ...options, extraDocumentProperties: { ...options.extraDocumentProperties - } + }, + id: this._prependSpaceId(type, options.id) }; if (this._shouldAssignSpaceId(type, spaceId)) { @@ -54,7 +56,8 @@ export class SpacesSavedObjectsClient { delete createOptions.extraDocumentProperties.spaceId; } - return await this._client.create(type, attributes, createOptions); + const result = await this._client.create(type, attributes, createOptions); + return this._trimSpaceId(result); } /** @@ -73,7 +76,8 @@ export class SpacesSavedObjectsClient { ...object, extraDocumentProperties: { ...object.extraDocumentProperties - } + }, + id: this._prependSpaceId(object.type, object.id) }; if (this._shouldAssignSpaceId(object.type, spaceId)) { @@ -85,7 +89,10 @@ export class SpacesSavedObjectsClient { return objectToCreate; }); - return await this._client.bulkCreate(objectsToCreate, options); + const result = await this._client.bulkCreate(objectsToCreate, options); + result.saved_objects.forEach(this._trimSpaceId.bind(this)); + + return result; } /** @@ -96,11 +103,13 @@ export class SpacesSavedObjectsClient { * @returns {promise} */ async delete(type, id) { + const objectId = this._prependSpaceId(type, id); + // attempt to retrieve document before deleting. // this ensures that the document belongs to the current space. await this.get(type, id); - return await this._client.delete(type, id); + return await this._client.delete(type, objectId); } /** @@ -131,7 +140,9 @@ export class SpacesSavedObjectsClient { spaceOptions.filters = [...filters, ...getSpacesQueryFilters(spaceId, types)]; - return await this._client.find({ ...options, ...spaceOptions }); + const result = await this._client.find({ ...options, ...spaceOptions }); + result.saved_objects.forEach(this._trimSpaceId.bind(this)); + return result; } /** @@ -154,13 +165,18 @@ export class SpacesSavedObjectsClient { const extraDocumentProperties = this._collectExtraDocumentProperties(['spaceId', 'type'], options.extraDocumentProperties); - const result = await this._client.bulkGet(objects, { + const objectsToRetrieve = objects.map(object => ({ + ...object, + id: this._prependSpaceId(object.type, object.id) + })); + + const result = await this._client.bulkGet(objectsToRetrieve, { ...options, extraDocumentProperties }); result.saved_objects = result.saved_objects.map(savedObject => { - const { id, type, spaceId = DEFAULT_SPACE_ID } = savedObject; + const { id, type, spaceId = DEFAULT_SPACE_ID } = this._trimSpaceId(savedObject); if (isTypeSpaceAware(type)) { if (spaceId !== thisSpaceId) { @@ -190,9 +206,11 @@ export class SpacesSavedObjectsClient { async get(type, id, options = {}) { // ES 'get' does not support queries, so we have to filter results after the fact. + const objectId = this._prependSpaceId(type, id); + const extraDocumentProperties = this._collectExtraDocumentProperties(['spaceId'], options.extraDocumentProperties); - const response = await this._client.get(type, id, { + const response = await this._client.get(type, objectId, { ...options, extraDocumentProperties }); @@ -206,7 +224,7 @@ export class SpacesSavedObjectsClient { } } - return response; + return this._trimSpaceId(response); } /** @@ -227,6 +245,8 @@ export class SpacesSavedObjectsClient { } }; + const objectId = this._prependSpaceId(type, id); + // attempt to retrieve document before updating. // this ensures that the document belongs to the current space. if (isTypeSpaceAware(type)) { @@ -241,7 +261,8 @@ export class SpacesSavedObjectsClient { } } - return await this._client.update(type, id, attributes, updateOptions); + const result = await this._client.update(type, objectId, attributes, updateOptions); + return this._trimSpaceId(result); } _collectExtraDocumentProperties(thisClientProperties, optionalProperties = []) { @@ -251,4 +272,29 @@ export class SpacesSavedObjectsClient { _shouldAssignSpaceId(type, spaceId) { return spaceId !== DEFAULT_SPACE_ID && isTypeSpaceAware(type); } + + _prependSpaceId(type, id = uuid.v1()) { + if (this._spaceId === DEFAULT_SPACE_ID || !isTypeSpaceAware(type)) { + return id; + } + return `${this._spaceId}:${id}`; + } + + _trimSpaceId(savedObject) { + const prefix = `${this._spaceId}:`; + + const idHasPrefix = savedObject.id.startsWith(prefix); + + if (this._shouldAssignSpaceId(savedObject.type, this._spaceId)) { + if (idHasPrefix) { + savedObject.id = savedObject.id.slice(prefix.length); + } else { + throw new Error(`Saved object [${savedObject.type}/${savedObject.id}] is missing its expected space identifier.`); + } + } else if (idHasPrefix) { + throw new Error(`Saved object [${savedObject.type}/${savedObject.id}] has an unexpected space identifier [${this._spaceId}].`); + } + + return savedObject; + } } diff --git a/x-pack/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.test.js b/x-pack/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.test.js index 7e9fab3116d70..e7dbffa413c9e 100644 --- a/x-pack/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.test.js +++ b/x-pack/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.test.js @@ -6,7 +6,12 @@ import { SpacesSavedObjectsClient } from './spaces_saved_objects_client'; import { createSpacesService } from '../create_spaces_service'; + +jest.mock('uuid', () => ({ + v1: jest.fn(() => `mock-id`) +})); import { DEFAULT_SPACE_ID } from '../../../common/constants'; +import { cloneDeep } from 'lodash'; const createObjectEntry = (type, id, spaceId) => ({ [id]: { @@ -18,11 +23,13 @@ const createObjectEntry = (type, id, spaceId) => ({ const SAVED_OBJECTS = { ...createObjectEntry('foo', 'object_0'), - ...createObjectEntry('foo', 'object_1', 'space_1'), - ...createObjectEntry('foo', 'object_2', 'space_2'), + ...createObjectEntry('foo', 'space_1:object_1', 'space_1'), + ...createObjectEntry('foo', 'space_2:object_2', 'space_2'), ...createObjectEntry('space', 'space_1'), }; +const createSavedObjects = () => cloneDeep(SAVED_OBJECTS); + const config = { 'server.basePath': '/' }; @@ -39,14 +46,48 @@ const createMockRequest = (space) => ({ getBasePath: () => space.id !== DEFAULT_SPACE_ID ? `/s/${space.id}` : '', }); -const createMockClient = (space) => { +const createMockClient = (space, { mangleSpaceIdentifier = false } = {}) => { + const errors = { + createGenericNotFoundError: jest.fn((type, id) => { + return new Error(`not found: ${type} ${id}`); + }) + }; + + const maybeTransformSavedObject = (savedObject) => { + if (!mangleSpaceIdentifier) { + return savedObject; + } + if (space.id === DEFAULT_SPACE_ID) { + savedObject.id = `default:${space.id}`; + } else { + savedObject.id = savedObject.id.split(':')[1]; + } + + return savedObject; + }; + return { get: jest.fn((type, id) => { - return SAVED_OBJECTS[id]; + const result = createSavedObjects()[id]; + if (!result) { + throw errors.createGenericNotFoundError(type, id); + } + + return maybeTransformSavedObject(result); }), bulkGet: jest.fn((objects) => { return { - saved_objects: objects.map(object => SAVED_OBJECTS[object.id]) + saved_objects: objects.map(object => { + const result = createSavedObjects()[object.id]; + if (!result) { + return { + id: object.id, + type: object.type, + error: { statusCode: 404, message: 'Not found' } + }; + } + return maybeTransformSavedObject(result); + }) }; }), find: jest.fn(({ type }) => { @@ -56,19 +97,36 @@ const createMockClient = (space) => { saved_objects: [space] }; } + const objects = createSavedObjects(); + const result = Object.keys(objects) + .filter(key => objects[key].spaceId === space.id || (space.id === DEFAULT_SPACE_ID && !objects[key].spaceId)) + .map(key => maybeTransformSavedObject(objects[key])); + + return { + saved_objects: result + }; + }), + create: jest.fn((type, attributes, options) => { + return maybeTransformSavedObject({ + id: options.id || 'foo-id', + type, + attributes + }); + }), + bulkCreate: jest.fn((objects) => { return { - saved_objects: [] + saved_objects: cloneDeep(objects).map(maybeTransformSavedObject) }; }), - create: jest.fn(), - bulkCreate: jest.fn(), - update: jest.fn(), + update: jest.fn((type, id, attributes) => { + return maybeTransformSavedObject({ + id, + type, + attributes + }); + }), delete: jest.fn(), - errors: { - createGenericNotFoundError: jest.fn(() => { - return new Error('not found'); - }) - } + errors, }; }; @@ -97,7 +155,28 @@ describe('default space', () => { const result = await client.get(type, id, options); - expect(result).toBe(SAVED_OBJECTS[id]); + expect(result).toEqual(SAVED_OBJECTS[id]); + }); + + test(`does not append the space id to the document id`, async () => { + const request = createMockRequest(currentSpace); + const baseClient = createMockClient(currentSpace); + const spacesService = createSpacesService(server); + + const client = new SpacesSavedObjectsClient({ + request, + baseClient, + spacesService, + types: [], + }); + + const type = 'foo'; + const id = 'object_0'; + const options = {}; + + await client.get(type, id, options); + + expect(baseClient.get).toHaveBeenCalledWith(type, id, { extraDocumentProperties: ['spaceId'] }); }); test(`returns global objects that don't belong to a specific space`, async () => { @@ -118,7 +197,7 @@ describe('default space', () => { const result = await client.get(type, id, options); - expect(result).toBe(SAVED_OBJECTS[id]); + expect(result).toEqual(SAVED_OBJECTS[id]); }); test(`merges options.extraDocumentProperties`, async () => { @@ -166,6 +245,25 @@ describe('default space', () => { await expect(client.get(type, id, options)).rejects.toThrowErrorMatchingSnapshot(); }); + + test(`throws when the base client returns a malformed document id`, async () => { + const request = createMockRequest(currentSpace); + const baseClient = createMockClient(currentSpace, { mangleSpaceIdentifier: true }); + const spacesService = createSpacesService(server); + + const client = new SpacesSavedObjectsClient({ + request, + baseClient, + spacesService, + types: [], + }); + + const type = 'foo'; + const id = 'object_0'; + const options = {}; + + await expect(client.get(type, id, options)).rejects.toThrowErrorMatchingSnapshot(); + }); }); describe('#bulk_get', () => { @@ -208,6 +306,34 @@ describe('default space', () => { }); }); + test(`does not append the space id to the document id`, async () => { + const request = createMockRequest(currentSpace); + const baseClient = createMockClient(currentSpace); + const spacesService = createSpacesService(server); + + const client = new SpacesSavedObjectsClient({ + request, + baseClient, + spacesService, + types: [], + }); + + const type = 'foo'; + const options = {}; + + const objects = [{ + type, + id: 'object_0' + }, { + type, + id: 'object_2' + }]; + + await client.bulkGet(objects, options); + + expect(baseClient.bulkGet).toHaveBeenCalledWith(objects, { ...options, extraDocumentProperties: ["spaceId", "type"] }); + }); + test(`returns global objects that don't belong to a specific space`, async () => { const request = createMockRequest(currentSpace); const baseClient = createMockClient(currentSpace); @@ -274,6 +400,25 @@ describe('default space', () => { extraDocumentProperties: ['spaceId', 'type', 'otherSourceProp'] }); }); + + test(`throws when the base client returns a malformed document id`, async () => { + const request = createMockRequest(currentSpace); + const baseClient = createMockClient(currentSpace, { mangleSpaceIdentifier: true }); + const spacesService = createSpacesService(server); + + const client = new SpacesSavedObjectsClient({ + request, + baseClient, + spacesService, + types: [], + }); + + const type = 'foo'; + const id = 'object_0'; + const options = {}; + + await expect(client.bulkGet([{ type, id }], options)).rejects.toThrowErrorMatchingSnapshot(); + }); }); describe('#find', () => { @@ -382,6 +527,24 @@ describe('default space', () => { }] }); }); + + test(`throws when the base client returns a malformed document id`, async () => { + const request = createMockRequest(currentSpace); + const baseClient = createMockClient(currentSpace, { mangleSpaceIdentifier: true }); + const spacesService = createSpacesService(server); + + const client = new SpacesSavedObjectsClient({ + request, + baseClient, + spacesService, + types: [], + }); + + const type = 'foo'; + const options = { type }; + + await expect(client.find(options)).rejects.toThrowErrorMatchingSnapshot(); + }); }); describe('#create', () => { @@ -407,7 +570,7 @@ describe('default space', () => { await client.create(type, attributes); - expect(baseClient.create).toHaveBeenCalledWith(type, attributes, { extraDocumentProperties: {} }); + expect(baseClient.create).toHaveBeenCalledWith(type, attributes, { extraDocumentProperties: {}, id: 'mock-id' }); }); test('does not assign a spaceId to space-aware objects belonging to the default space', async () => { @@ -432,7 +595,28 @@ describe('default space', () => { await client.create(type, attributes); // called without extraDocumentProperties - expect(baseClient.create).toHaveBeenCalledWith(type, attributes, { extraDocumentProperties: {} }); + expect(baseClient.create).toHaveBeenCalledWith(type, attributes, { extraDocumentProperties: {}, id: 'mock-id' }); + }); + + test(`throws when the base client returns a malformed document id`, async () => { + const request = createMockRequest(currentSpace); + const baseClient = createMockClient(currentSpace, { mangleSpaceIdentifier: true }); + const spacesService = createSpacesService(server); + + const client = new SpacesSavedObjectsClient({ + request, + baseClient, + spacesService, + types: [], + }); + + const type = 'foo'; + const attributes = { + prop1: 'value 1', + prop2: 'value 2' + }; + + await expect(client.create(type, attributes)).rejects.toThrowErrorMatchingSnapshot(); }); }); @@ -467,7 +651,8 @@ describe('default space', () => { const expectedCalledWithObjects = objects.map(object => ({ ...object, - extraDocumentProperties: {} + extraDocumentProperties: {}, + id: 'mock-id' })); expect(baseClient.bulkCreate).toHaveBeenCalledWith(expectedCalledWithObjects, {}); @@ -502,7 +687,7 @@ describe('default space', () => { await client.bulkCreate(objects, {}); expect(baseClient.bulkCreate).toHaveBeenCalledWith(objects.map(o => { - return { ...o, extraDocumentProperties: {} }; + return { ...o, extraDocumentProperties: {}, id: 'mock-id' }; }), {}); }); @@ -537,11 +722,13 @@ describe('default space', () => { const expectedCalledWithObjects = [...objects]; expectedCalledWithObjects[0] = { ...expectedCalledWithObjects[0], - extraDocumentProperties: {} + extraDocumentProperties: {}, + id: 'mock-id' }; expectedCalledWithObjects[1] = { ...expectedCalledWithObjects[1], - extraDocumentProperties: {} + extraDocumentProperties: {}, + id: 'mock-id' }; expect(baseClient.bulkCreate).toHaveBeenCalledWith(expectedCalledWithObjects, {}); @@ -578,9 +765,37 @@ describe('default space', () => { // called with empty extraDocumentProperties expect(baseClient.bulkCreate).toHaveBeenCalledWith(objects.map(o => ({ ...o, - extraDocumentProperties: {} + extraDocumentProperties: {}, + id: 'mock-id' })), {}); }); + + test(`throws when the base client returns a malformed document id`, async () => { + const request = createMockRequest(currentSpace); + const baseClient = createMockClient(currentSpace, { mangleSpaceIdentifier: true }); + const spacesService = createSpacesService(server); + + const client = new SpacesSavedObjectsClient({ + request, + baseClient, + spacesService, + types: [], + }); + + const attributes = { + prop1: 'value 1', + prop2: 'value 2' + }; + const objects = [{ + type: 'foo', + attributes + }, { + type: 'bar', + attributes + }]; + + await expect(client.bulkCreate(objects, {})).rejects.toThrowErrorMatchingSnapshot(); + }); }); describe('#update', () => { @@ -655,6 +870,28 @@ describe('default space', () => { await expect(client.update(type, id, attributes)).rejects.toThrowErrorMatchingSnapshot(); }); + + test(`throws when the base client returns a malformed document id`, async () => { + const request = createMockRequest(currentSpace); + const baseClient = createMockClient(currentSpace, { mangleSpaceIdentifier: true }); + const spacesService = createSpacesService(server); + + const client = new SpacesSavedObjectsClient({ + request, + baseClient, + spacesService, + types: [], + }); + + const id = 'space_1'; + const type = 'space'; + const attributes = { + prop1: 'value 1', + prop2: 'value 2' + }; + + await expect(client.update(type, id, attributes)).rejects.toThrowErrorMatchingSnapshot(); + }); }); describe('#delete', () => { @@ -745,7 +982,32 @@ describe('current space (space_1)', () => { const result = await client.get(type, id, options); - expect(result).toBe(SAVED_OBJECTS[id]); + expect(result).toEqual({ + id, + type, + spaceId: currentSpace.id + }); + }); + + test('appends the space id to the document id', async () => { + const request = createMockRequest(currentSpace); + const baseClient = createMockClient(currentSpace); + const spacesService = createSpacesService(server); + + const client = new SpacesSavedObjectsClient({ + request, + baseClient, + spacesService, + types: [], + }); + + const type = 'foo'; + const id = 'object_1'; + const options = {}; + + await client.get(type, id, options); + + expect(baseClient.get).toHaveBeenCalledWith(type, `${currentSpace.id}:${id}`, { ...options, extraDocumentProperties: ['spaceId'] }); }); test(`returns global objects that don't belong to a specific space`, async () => { @@ -766,7 +1028,7 @@ describe('current space (space_1)', () => { const result = await client.get(type, id, options); - expect(result).toBe(SAVED_OBJECTS[id]); + expect(result).toEqual(SAVED_OBJECTS[id]); }); test(`merges options.extraDocumentProperties`, async () => { @@ -790,7 +1052,7 @@ describe('current space (space_1)', () => { await client.get(type, id, options); - expect(baseClient.get).toHaveBeenCalledWith(type, id, { + expect(baseClient.get).toHaveBeenCalledWith(type, `${currentSpace.id}:${id}`, { extraDocumentProperties: ['spaceId', 'otherSourceProp'] }); }); @@ -814,6 +1076,25 @@ describe('current space (space_1)', () => { await expect(client.get(type, id, options)).rejects.toThrowErrorMatchingSnapshot(); }); + + test(`returns error when the object has a malformed identifier`, async () => { + const request = createMockRequest(currentSpace); + const baseClient = createMockClient(currentSpace, { mangleSpaceIdentifier: true }); + const spacesService = createSpacesService(server); + + const client = new SpacesSavedObjectsClient({ + request, + baseClient, + spacesService, + types: [], + }); + + const type = 'foo'; + const id = 'object_1'; + const options = {}; + + await expect(client.get(type, id, options)).rejects.toThrowErrorMatchingSnapshot(); + }); }); describe('#bulk_get', () => { @@ -857,6 +1138,35 @@ describe('current space (space_1)', () => { }); }); + test('appends the space id to the document id', async () => { + const request = createMockRequest(currentSpace); + const baseClient = createMockClient(currentSpace); + const spacesService = createSpacesService(server); + + const client = new SpacesSavedObjectsClient({ + request, + baseClient, + spacesService, + types: [], + }); + + const type = 'foo'; + const options = {}; + const objects = [{ + type, + id: 'object_1' + }, { + type, + id: 'object_2' + }]; + + await client.bulkGet(objects, options); + + const expectedObjects = objects.map(o => ({ ...o, id: `${currentSpace.id}:${o.id}` })); + expect(baseClient.bulkGet) + .toHaveBeenCalledWith(expectedObjects, { ...options, extraDocumentProperties: ["spaceId", "type"] }); + }); + test(`returns global objects that don't belong to a specific space`, async () => { const request = createMockRequest(currentSpace); const baseClient = createMockClient(currentSpace); @@ -876,7 +1186,7 @@ describe('current space (space_1)', () => { type, id: 'object_1' }, { - type, + type: 'space', id: 'space_1' }], options); @@ -920,14 +1230,44 @@ describe('current space (space_1)', () => { await client.bulkGet(objects, options); - expect(baseClient.bulkGet).toHaveBeenCalledWith(objects, { + const expectedCalledWithObjects = objects.map(object => { + const id = `${currentSpace.id}:${object.id}`; + return { + ...object, + id + }; + }); + + expect(baseClient.bulkGet).toHaveBeenCalledWith(expectedCalledWithObjects, { extraDocumentProperties: ['spaceId', 'type', 'otherSourceProp'] }); }); - }); - - describe('#find', () => { - test(`creates ES query filters restricting objects to the current space`, async () => { + + test(`throws when base client returns documents with malformed ids`, async () => { + const request = createMockRequest(currentSpace); + const baseClient = createMockClient(currentSpace, { mangleSpaceIdentifier: true }); + const spacesService = createSpacesService(server); + + const client = new SpacesSavedObjectsClient({ + request, + baseClient, + spacesService, + types: [], + }); + + const type = 'foo'; + const objects = [{ + type, + id: 'object_1' + }]; + const options = {}; + + await expect(client.bulkGet(objects, options)).rejects.toThrowErrorMatchingSnapshot(); + }); + }); + + describe('#find', () => { + test(`creates ES query filters restricting objects to the current space`, async () => { const request = createMockRequest(currentSpace); const baseClient = createMockClient(currentSpace); @@ -1030,6 +1370,26 @@ describe('current space (space_1)', () => { }] }); }); + + test(`throws when base client returns documents with malformed ids`, async () => { + const request = createMockRequest(currentSpace); + const baseClient = createMockClient(currentSpace, { mangleSpaceIdentifier: true }); + const spacesService = createSpacesService(server); + + const client = new SpacesSavedObjectsClient({ + request, + baseClient, + spacesService, + types: [], + }); + + const type = 'foo'; + const options = { + type, + }; + + await expect(client.find(options)).rejects.toThrowErrorMatchingSnapshot(); + }); }); describe('#create', () => { @@ -1055,6 +1415,7 @@ describe('current space (space_1)', () => { await client.create(type, attributes); expect(baseClient.create).toHaveBeenCalledWith(type, attributes, { + id: `${currentSpace.id}:mock-id`, extraDocumentProperties: { spaceId: 'space_1' } @@ -1082,258 +1443,326 @@ describe('current space (space_1)', () => { await client.create(type, attributes); - expect(baseClient.create).toHaveBeenCalledWith(type, attributes, { extraDocumentProperties: {} }); + expect(baseClient.create).toHaveBeenCalledWith(type, attributes, { extraDocumentProperties: {}, id: 'mock-id' }); }); - describe('#bulk_create', () => { - test('allows for bulk creation when all types are space-aware', async () => { - - const request = createMockRequest(currentSpace); - const baseClient = createMockClient(currentSpace); - const spacesService = createSpacesService(server); + test('throws when the base client returns a malformed document id', async () => { + const request = createMockRequest(currentSpace); + const baseClient = createMockClient(currentSpace, { mangleSpaceIdentifier: true }); + const spacesService = createSpacesService(server); - const client = new SpacesSavedObjectsClient({ - request, - baseClient, - spacesService, - types: [], - }); + const client = new SpacesSavedObjectsClient({ + request, + baseClient, + spacesService, + types: [], + }); + const type = 'foo'; + const attributes = { + prop1: 'value 1', + prop2: 'value 2' + }; - const attributes = { - prop1: 'value 1', - prop2: 'value 2' - }; - const objects = [{ - type: 'foo', - attributes - }, { - type: 'bar', - attributes - }]; + await expect(client.create(type, attributes)).rejects.toThrowErrorMatchingSnapshot(); + }); + }); - await client.bulkCreate(objects, {}); + describe('#bulk_create', () => { + test('allows for bulk creation when all types are space-aware', async () => { - const expectedCalledWithObjects = objects.map(object => ({ - ...object, - extraDocumentProperties: { - spaceId: 'space_1' - } - })); + const request = createMockRequest(currentSpace); + const baseClient = createMockClient(currentSpace); + const spacesService = createSpacesService(server); - expect(baseClient.bulkCreate).toHaveBeenCalledWith(expectedCalledWithObjects, {}); + const client = new SpacesSavedObjectsClient({ + request, + baseClient, + spacesService, + types: [], }); - test('allows for bulk creation when all types are not space-aware', async () => { - const request = createMockRequest(currentSpace); - const baseClient = createMockClient(currentSpace); - const spacesService = createSpacesService(server); + const attributes = { + prop1: 'value 1', + prop2: 'value 2' + }; + const objects = [{ + type: 'foo', + attributes + }, { + type: 'bar', + attributes + }]; - const client = new SpacesSavedObjectsClient({ - request, - baseClient, - spacesService, - types: [], - }); + await client.bulkCreate(objects, {}); - const attributes = { - prop1: 'value 1', - prop2: 'value 2' - }; + const expectedCalledWithObjects = objects.map(object => ({ + ...object, + extraDocumentProperties: { + spaceId: 'space_1' + }, + id: `${currentSpace.id}:mock-id` + })); - const objects = [{ - type: 'space', - attributes - }, { - type: 'space', - attributes - }]; + expect(baseClient.bulkCreate).toHaveBeenCalledWith(expectedCalledWithObjects, {}); + }); - await client.bulkCreate(objects, {}); + test('allows for bulk creation when all types are not space-aware', async () => { - expect(baseClient.bulkCreate).toHaveBeenCalledWith(objects.map(o => { - return { ...o, extraDocumentProperties: {} }; - }), {}); + const request = createMockRequest(currentSpace); + const baseClient = createMockClient(currentSpace); + const spacesService = createSpacesService(server); + + const client = new SpacesSavedObjectsClient({ + request, + baseClient, + spacesService, + types: [], }); - test('allows space-aware and non-space-aware (global) objects to be created at the same time', async () => { + const attributes = { + prop1: 'value 1', + prop2: 'value 2' + }; + + const objects = [{ + type: 'space', + attributes + }, { + type: 'space', + attributes + }]; + + await client.bulkCreate(objects, {}); - const request = createMockRequest(currentSpace); - const baseClient = createMockClient(currentSpace); - const spacesService = createSpacesService(server); + expect(baseClient.bulkCreate).toHaveBeenCalledWith(objects.map(o => { + return { ...o, extraDocumentProperties: {}, id: 'mock-id' }; + }), {}); + }); - const client = new SpacesSavedObjectsClient({ - request, - baseClient, - spacesService, - types: [], - }); + test('allows space-aware and non-space-aware (global) objects to be created at the same time', async () => { - const attributes = { - prop1: 'value 1', - prop2: 'value 2' - }; + const request = createMockRequest(currentSpace); + const baseClient = createMockClient(currentSpace); + const spacesService = createSpacesService(server); - const objects = [{ - type: 'space', - attributes - }, { - type: 'foo', - attributes - }]; + const client = new SpacesSavedObjectsClient({ + request, + baseClient, + spacesService, + types: [], + }); - await client.bulkCreate(objects, {}); + const attributes = { + prop1: 'value 1', + prop2: 'value 2' + }; - const expectedCalledWithObjects = [...objects]; - expectedCalledWithObjects[0] = { - ...expectedCalledWithObjects[0], - extraDocumentProperties: {} - }; - expectedCalledWithObjects[1] = { - ...expectedCalledWithObjects[1], - extraDocumentProperties: { - spaceId: 'space_1' - } - }; + const objects = [{ + type: 'space', + attributes + }, { + type: 'foo', + attributes + }]; - expect(baseClient.bulkCreate).toHaveBeenCalledWith(expectedCalledWithObjects, {}); + await client.bulkCreate(objects, {}); + + const expectedCalledWithObjects = [...objects]; + expectedCalledWithObjects[0] = { + ...expectedCalledWithObjects[0], + extraDocumentProperties: {}, + id: 'mock-id' + }; + expectedCalledWithObjects[1] = { + ...expectedCalledWithObjects[1], + extraDocumentProperties: { + spaceId: 'space_1' + }, + id: `${currentSpace.id}:mock-id` + }; + + expect(baseClient.bulkCreate).toHaveBeenCalledWith(expectedCalledWithObjects, {}); + }); + + test('throws when the base client returns a malformed document id', async () => { + const request = createMockRequest(currentSpace); + const baseClient = createMockClient(currentSpace, { mangleSpaceIdentifier: true }); + const spacesService = createSpacesService(server); + + const client = new SpacesSavedObjectsClient({ + request, + baseClient, + spacesService, + types: [], }); + + const type = 'foo'; + const attributes = { + prop1: 'value 1', + prop2: 'value 2' + }; + + await expect(client.bulkCreate([{ type, attributes }])).rejects.toThrowErrorMatchingSnapshot(); }); + }); - describe('#update', () => { - test('allows an object to be updated if it exists in the same space', async () => { - - const request = createMockRequest(currentSpace); - const baseClient = createMockClient(currentSpace); - const spacesService = createSpacesService(server); - - const client = new SpacesSavedObjectsClient({ - request, - baseClient, - spacesService, - types: [], - }); - - const id = 'object_1'; - const type = 'foo'; - const attributes = { - prop1: 'value 1', - prop2: 'value 2' - }; + describe('#update', () => { + test('allows an object to be updated if it exists in the same space', async () => { - await client.update(type, id, attributes); + const request = createMockRequest(currentSpace); + const baseClient = createMockClient(currentSpace); + const spacesService = createSpacesService(server); - expect(baseClient.update).toHaveBeenCalledWith(type, id, attributes, { extraDocumentProperties: { spaceId: 'space_1' } }); + const client = new SpacesSavedObjectsClient({ + request, + baseClient, + spacesService, + types: [], }); - test('allows a global object to be updated', async () => { - const request = createMockRequest(currentSpace); - const baseClient = createMockClient(currentSpace); - const spacesService = createSpacesService(server); + const id = 'object_1'; + const type = 'foo'; + const attributes = { + prop1: 'value 1', + prop2: 'value 2' + }; - const client = new SpacesSavedObjectsClient({ - request, - baseClient, - spacesService, - types: [], - }); + await client.update(type, id, attributes); - const id = 'space_1'; - const type = 'space'; - const attributes = { - prop1: 'value 1', - prop2: 'value 2' - }; + expect(baseClient.update) + .toHaveBeenCalledWith(type, `${currentSpace.id}:${id}`, attributes, { extraDocumentProperties: { spaceId: 'space_1' } }); + }); - await client.update(type, id, attributes); + test('allows a global object to be updated', async () => { + const request = createMockRequest(currentSpace); + const baseClient = createMockClient(currentSpace); + const spacesService = createSpacesService(server); - expect(baseClient.update).toHaveBeenCalledWith(type, id, attributes, { extraDocumentProperties: {} }); + const client = new SpacesSavedObjectsClient({ + request, + baseClient, + spacesService, + types: [], }); - test('does not allow an object to be updated via a different space', async () => { + const id = 'space_1'; + const type = 'space'; + const attributes = { + prop1: 'value 1', + prop2: 'value 2' + }; + + await client.update(type, id, attributes); - const request = createMockRequest(currentSpace); - const baseClient = createMockClient(currentSpace); - const spacesService = createSpacesService(server); + expect(baseClient.update).toHaveBeenCalledWith(type, id, attributes, { extraDocumentProperties: {} }); + }); - const client = new SpacesSavedObjectsClient({ - request, - baseClient, - spacesService, - types: [], - }); + test('does not allow an object to be updated via a different space', async () => { - const id = 'object_2'; - const type = 'foo'; - const attributes = { - prop1: 'value 1', - prop2: 'value 2' - }; + const request = createMockRequest(currentSpace); + const baseClient = createMockClient(currentSpace); + const spacesService = createSpacesService(server); - await expect(client.update(type, id, attributes)).rejects.toThrowErrorMatchingSnapshot(); + const client = new SpacesSavedObjectsClient({ + request, + baseClient, + spacesService, + types: [], }); + + const id = 'object_2'; + const type = 'foo'; + const attributes = { + prop1: 'value 1', + prop2: 'value 2' + }; + + await expect(client.update(type, id, attributes)).rejects.toThrowErrorMatchingSnapshot(); }); - describe('#delete', () => { - test('allows an object to be deleted if it exists in the same space', async () => { - const request = createMockRequest(currentSpace); - const baseClient = createMockClient(currentSpace); - const spacesService = createSpacesService(server); + test('throws when the base client returns a malformed document id', async () => { + const request = createMockRequest(currentSpace); + const baseClient = createMockClient(currentSpace, { mangleSpaceIdentifier: true }); + const spacesService = createSpacesService(server); - const client = new SpacesSavedObjectsClient({ - request, - baseClient, - spacesService, - types: [], - }); + const client = new SpacesSavedObjectsClient({ + request, + baseClient, + spacesService, + types: [], + }); + + const id = 'object_1'; + const type = 'foo'; + const attributes = { + prop1: 'value 1', + prop2: 'value 2' + }; - const id = 'object_1'; - const type = 'foo'; + await expect(client.update(type, id, attributes)).rejects.toThrowErrorMatchingSnapshot(); + }); + }); - await client.delete(type, id); + describe('#delete', () => { + test('allows an object to be deleted if it exists in the same space', async () => { + const request = createMockRequest(currentSpace); + const baseClient = createMockClient(currentSpace); + const spacesService = createSpacesService(server); - expect(baseClient.delete).toHaveBeenCalledWith(type, id); + const client = new SpacesSavedObjectsClient({ + request, + baseClient, + spacesService, + types: [], }); - test('allows a global object to be deleted', async () => { - const request = createMockRequest(currentSpace); - const baseClient = createMockClient(currentSpace); - const spacesService = createSpacesService(server); + const id = 'object_1'; + const type = 'foo'; - const client = new SpacesSavedObjectsClient({ - request, - baseClient, - spacesService, - types: [], - }); + await client.delete(type, id); - const id = 'space_1'; - const type = 'space'; + expect(baseClient.delete).toHaveBeenCalledWith(type, `${currentSpace.id}:${id}`); + }); - await client.delete(type, id); + test('allows a global object to be deleted', async () => { + const request = createMockRequest(currentSpace); + const baseClient = createMockClient(currentSpace); + const spacesService = createSpacesService(server); - expect(baseClient.delete).toHaveBeenCalledWith(type, id); + const client = new SpacesSavedObjectsClient({ + request, + baseClient, + spacesService, + types: [], }); - test('does not allow an object to be deleted via a different space', async () => { + const id = 'space_1'; + const type = 'space'; - const request = createMockRequest(currentSpace); - const baseClient = createMockClient(currentSpace); - const spacesService = createSpacesService(server); + await client.delete(type, id); - const client = new SpacesSavedObjectsClient({ - request, - baseClient, - spacesService, - types: [], - }); + expect(baseClient.delete).toHaveBeenCalledWith(type, id); + }); - const id = 'object_2'; - const type = 'foo'; + test('does not allow an object to be deleted via a different space', async () => { - await expect(client.delete(type, id)).rejects.toThrowErrorMatchingSnapshot(); + const request = createMockRequest(currentSpace); + const baseClient = createMockClient(currentSpace); + const spacesService = createSpacesService(server); + + const client = new SpacesSavedObjectsClient({ + request, + baseClient, + spacesService, + types: [], }); + + const id = 'object_2'; + const type = 'foo'; + + await expect(client.delete(type, id)).rejects.toThrowErrorMatchingSnapshot(); }); }); }); 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 index 59f18c131b1ec..14d6ba54de2e8 100644 --- a/x-pack/test/spaces_api_integration/apis/saved_objects/create.js +++ b/x-pack/test/spaces_api_integration/apis/saved_objects/create.js @@ -31,9 +31,11 @@ export default function ({ getService }) { } }); + const expectedDocumentId = spaceId === DEFAULT_SPACE_ID ? resp.body.id : `${spaceId}:${resp.body.id}`; + // query ES directory to assert on space id const { _source } = await es.get({ - id: `visualization:${resp.body.id}`, + id: `visualization:${expectedDocumentId}`, type: 'doc', index: '.kibana' }); 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 index 0e7b72a5553f2..fe3cb7bb2be06 100644 --- a/x-pack/test/spaces_api_integration/apis/saved_objects/delete.js +++ b/x-pack/test/spaces_api_integration/apis/saved_objects/delete.js @@ -7,6 +7,7 @@ import expect from 'expect.js'; import { SPACES } from './lib/spaces'; import { getUrlPrefix, getIdPrefix } from './lib/space_test_utils'; +import { DEFAULT_SPACE_ID } from '../../../../plugins/spaces/common/constants'; export default function ({ getService }) { const supertest = getService('supertest'); @@ -14,15 +15,15 @@ export default function ({ getService }) { describe('delete', () => { - const expectEmpty = (resp) => { + const expectEmpty = () => (resp) => { expect(resp.body).to.eql({}); }; - const expectNotFound = (resp) => { + const expectNotFound = (type, id) => (resp) => { expect(resp.body).to.eql({ statusCode: 404, error: 'Not Found', - message: 'Not Found' + message: `Saved object [${type}/${id}] not found` }); }; @@ -35,21 +36,29 @@ export default function ({ getService }) { await supertest .delete(`${getUrlPrefix(spaceId)}/api/saved_objects/dashboard/${getIdPrefix(spaceId)}be3733a0-9efe-11e7-acb3-3dab96693fab`) .expect(tests.spaceAware.statusCode) - .then(tests.spaceAware.response) + .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) + .then(tests.notSpaceAware.response()) )); it(`should return ${tests.inOtherSpace.statusCode} when deleting a doc belonging to another space`, async () => { + const documentId = `${getIdPrefix('space_2')}be3733a0-9efe-11e7-acb3-3dab96693fab`; + + let expectedObjectId = documentId; + + if (spaceId !== DEFAULT_SPACE_ID) { + expectedObjectId = `${spaceId}:${expectedObjectId}`; + } + await supertest - .delete(`${getUrlPrefix(spaceId)}/api/saved_objects/dashboard/${getIdPrefix('space_2')}be3733a0-9efe-11e7-acb3-3dab96693fab`) + .delete(`${getUrlPrefix(spaceId)}/api/saved_objects/dashboard/${documentId}`) .expect(tests.inOtherSpace.statusCode) - .then(tests.inOtherSpace.response); + .then(tests.inOtherSpace.response('dashboard', expectedObjectId)); }); }); }; 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 index 092b9ae499b5c..6a8e21e9b5c99 100644 --- a/x-pack/test/spaces_api_integration/apis/saved_objects/get.js +++ b/x-pack/test/spaces_api_integration/apis/saved_objects/get.js @@ -7,6 +7,7 @@ import expect from 'expect.js'; import { getIdPrefix, 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'); @@ -14,7 +15,7 @@ export default function ({ getService }) { describe('get', () => { - const expectResults = (spaceId) => (resp) => { + const expectResults = (spaceId) => () => (resp) => { // The default space does not assign a space id. const expectedSpaceId = spaceId === 'default' ? undefined : spaceId; @@ -43,10 +44,10 @@ export default function ({ getService }) { expect(resp.body).to.eql(expectedBody); }; - const expectNotFound = (resp) => { + const expectNotFound = (type, id) => (resp) => { expect(resp.body).to.eql({ error: 'Not Found', - message: 'Not Found', + message: `Saved object [${type}/${id}] not found`, statusCode: 404, }); }; @@ -58,10 +59,18 @@ export default function ({ getService }) { it(`should return ${tests.exists.statusCode}`, async () => { const objectId = `${getIdPrefix(otherSpaceId)}dd7caf20-9efd-11e7-acb3-3dab96693fab`; + + let expectedObjectId = objectId; + const testingMismatchedSpaces = spaceId !== otherSpaceId; + + if (testingMismatchedSpaces && spaceId !== DEFAULT_SPACE_ID) { + expectedObjectId = `${spaceId}:${expectedObjectId}`; + } + return supertest .get(`${getUrlPrefix(spaceId)}/api/saved_objects/visualization/${objectId}`) .expect(tests.exists.statusCode) - .then(tests.exists.response); + .then(tests.exists.response('visualization', expectedObjectId)); }); }); }; diff --git a/x-pack/test/spaces_api_integration/apis/saved_objects/lib/space_test_utils.js b/x-pack/test/spaces_api_integration/apis/saved_objects/lib/space_test_utils.js index 73df273c6e6e9..fab201a5b3c00 100644 --- a/x-pack/test/spaces_api_integration/apis/saved_objects/lib/space_test_utils.js +++ b/x-pack/test/spaces_api_integration/apis/saved_objects/lib/space_test_utils.js @@ -10,7 +10,6 @@ export function getUrlPrefix(spaceId) { return spaceId && spaceId !== DEFAULT_SPACE_ID ? `/s/${spaceId}` : ``; } -// Spaces do not actually prefix the ID, but this simplifies testing positive and negative flows. export function getIdPrefix(spaceId) { return spaceId === DEFAULT_SPACE_ID ? '' : `${spaceId}-`; } 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 index 409e4b9db549e..3aea0aadde82e 100644 --- a/x-pack/test/spaces_api_integration/apis/saved_objects/update.js +++ b/x-pack/test/spaces_api_integration/apis/saved_objects/update.js @@ -7,13 +7,14 @@ import expect from 'expect.js'; import { SPACES } from './lib/spaces'; import { getUrlPrefix, getIdPrefix } from './lib/space_test_utils'; +import { DEFAULT_SPACE_ID } from '../../../../plugins/spaces/common/constants'; export default function ({ getService }) { const supertest = getService('supertest'); const esArchiver = getService('esArchiver'); describe('update', () => { - const expectSpaceAwareResults = resp => { + 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$/); @@ -29,7 +30,7 @@ export default function ({ getService }) { }); }; - const expectNonSpaceAwareResults = resp => { + 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$/); @@ -45,11 +46,11 @@ export default function ({ getService }) { }); }; - const expectNotFound = resp => { + const expectNotFound = (type, id) => resp => { expect(resp.body).eql({ statusCode: 404, error: 'Not Found', - message: 'Not Found' + message: `Saved object [${type}/${id}] not found` }); }; @@ -66,7 +67,7 @@ export default function ({ getService }) { } }) .expect(tests.spaceAware.statusCode) - .then(tests.spaceAware.response); + .then(tests.spaceAware.response()); }); it(`should return ${tests.notSpaceAware.statusCode} for a non space-aware doc`, async () => { @@ -78,7 +79,7 @@ export default function ({ getService }) { } }) .expect(tests.notSpaceAware.statusCode) - .then(tests.notSpaceAware.response); + .then(tests.notSpaceAware.response()); }); it(`should return ${tests.inOtherSpace.statusCode} for a doc in another space`, async () => { @@ -91,7 +92,7 @@ export default function ({ getService }) { } }) .expect(tests.inOtherSpace.statusCode) - .then(tests.inOtherSpace.response); + .then(tests.inOtherSpace.response(`visualization`, `${spaceId === DEFAULT_SPACE_ID ? '' : (spaceId + ':')}${id}`)); }); describe('unknown id', () => { @@ -104,7 +105,7 @@ export default function ({ getService }) { } }) .expect(tests.doesntExist.statusCode) - .then(tests.doesntExist.response); + .then(tests.doesntExist.response(`visualization`, `${spaceId === DEFAULT_SPACE_ID ? '' : (spaceId + ':')}not an id`)); }); }); }); diff --git a/x-pack/test/spaces_api_integration/fixtures/es_archiver/saved_objects/spaces/data.json.gz b/x-pack/test/spaces_api_integration/fixtures/es_archiver/saved_objects/spaces/data.json.gz index 4c2d63913ebe0..0be0d4c12010a 100644 Binary files a/x-pack/test/spaces_api_integration/fixtures/es_archiver/saved_objects/spaces/data.json.gz and b/x-pack/test/spaces_api_integration/fixtures/es_archiver/saved_objects/spaces/data.json.gz differ diff --git a/x-pack/test/spaces_api_integration/fixtures/es_archiver/saved_objects/spaces/mappings.json b/x-pack/test/spaces_api_integration/fixtures/es_archiver/saved_objects/spaces/mappings.json index 9cca6b52a1caa..bb9b0c33b7394 100644 --- a/x-pack/test/spaces_api_integration/fixtures/es_archiver/saved_objects/spaces/mappings.json +++ b/x-pack/test/spaces_api_integration/fixtures/es_archiver/saved_objects/spaces/mappings.json @@ -308,4 +308,4 @@ }, "aliases": {} } -} +} \ No newline at end of file