diff --git a/src/core/server/saved_objects/service/lib/repository.test.js b/src/core/server/saved_objects/service/lib/repository.test.js index 40c3fdb7d0857f4..6d6d6c0a32d8ce6 100644 --- a/src/core/server/saved_objects/service/lib/repository.test.js +++ b/src/core/server/saved_objects/service/lib/repository.test.js @@ -20,6 +20,7 @@ import { SavedObjectsRepository } from './repository'; import * as getSearchDslNS from './search_dsl/search_dsl'; import { SavedObjectsErrorHelpers } from './errors'; +import { ALL_NAMESPACES_STRING } from './utils'; import { SavedObjectsSerializer } from '../../serialization'; import { encodeHitVersion } from '../../version'; import { SavedObjectTypeRegistry } from '../../saved_objects_type_registry'; @@ -725,6 +726,12 @@ describe('SavedObjectsRepository', () => { }); }; + it(`throws when options.namespace is '*'`, async () => { + await expect( + savedObjectsRepository.bulkCreate([obj3], { namespace: ALL_NAMESPACES_STRING }) + ).rejects.toThrowError(createBadRequestError('"options.namespace" cannot be "*"')); + }); + it(`returns error when type is invalid`, async () => { const obj = { ...obj3, type: 'unknownType' }; await bulkCreateError(obj, undefined, expectErrorInvalidType(obj)); @@ -1042,6 +1049,13 @@ describe('SavedObjectsRepository', () => { }); }; + it(`throws when options.namespace is '*'`, async () => { + const obj = { type: 'dashboard', id: 'three' }; + await expect( + savedObjectsRepository.bulkGet([obj], { namespace: ALL_NAMESPACES_STRING }) + ).rejects.toThrowError(createBadRequestError('"options.namespace" cannot be "*"')); + }); + it(`returns error when type is invalid`, async () => { const obj = { type: 'unknownType', id: 'three' }; await bulkGetErrorInvalidType([obj1, obj, obj2]); @@ -1467,6 +1481,12 @@ describe('SavedObjectsRepository', () => { }); }; + it(`throws when options.namespace is '*'`, async () => { + await expect( + savedObjectsRepository.bulkUpdate([obj], { namespace: ALL_NAMESPACES_STRING }) + ).rejects.toThrowError(createBadRequestError('"options.namespace" cannot be "*"')); + }); + it(`returns error when type is invalid`, async () => { const _obj = { ...obj, type: 'unknownType' }; await bulkUpdateError(_obj, undefined, expectErrorNotFound(_obj)); @@ -1477,6 +1497,15 @@ describe('SavedObjectsRepository', () => { await bulkUpdateError(_obj, undefined, expectErrorNotFound(_obj)); }); + it(`returns error when object namespace is '*'`, async () => { + const _obj = { ...obj, namespace: '*' }; + await bulkUpdateError( + _obj, + undefined, + expectErrorResult(obj, createBadRequestError('"namespace" cannot be "*"')) + ); + }); + it(`returns error when ES is unable to find the document (mget)`, async () => { const _obj = { ...obj, type: MULTI_NAMESPACE_TYPE, found: false }; const mgetResponse = getMockMgetResponse([_obj]); @@ -1630,7 +1659,7 @@ describe('SavedObjectsRepository', () => { ); }; - describe('cluster calls', () => { + describe('client calls', () => { it(`doesn't make a cluster call if the objects array is empty`, async () => { await checkConflicts([]); expect(client.mget).not.toHaveBeenCalled(); @@ -1662,6 +1691,14 @@ describe('SavedObjectsRepository', () => { }); }); + describe('errors', () => { + it(`throws when options.namespace is '*'`, async () => { + await expect( + savedObjectsRepository.checkConflicts([obj1], { namespace: ALL_NAMESPACES_STRING }) + ).rejects.toThrowError(createBadRequestError('"options.namespace" cannot be "*"')); + }); + }); + describe('returns', () => { it(`expected results`, async () => { const unknownTypeObj = { type: 'unknownType', id: 'three' }; @@ -1909,6 +1946,12 @@ describe('SavedObjectsRepository', () => { }); describe('errors', () => { + it(`throws when options.namespace is '*'`, async () => { + await expect( + savedObjectsRepository.create(type, attributes, { namespace: ALL_NAMESPACES_STRING }) + ).rejects.toThrowError(createBadRequestError('"options.namespace" cannot be "*"')); + }); + it(`throws when type is invalid`, async () => { await expect(savedObjectsRepository.create('unknownType', attributes)).rejects.toThrowError( createUnsupportedTypeError('unknownType') @@ -2120,6 +2163,12 @@ describe('SavedObjectsRepository', () => { ); }; + it(`throws when options.namespace is '*'`, async () => { + await expect( + savedObjectsRepository.delete(type, id, { namespace: ALL_NAMESPACES_STRING }) + ).rejects.toThrowError(createBadRequestError('"options.namespace" cannot be "*"')); + }); + it(`throws when type is invalid`, async () => { await expectNotFoundError('unknownType', id); expect(client.delete).not.toHaveBeenCalled(); @@ -2169,6 +2218,20 @@ describe('SavedObjectsRepository', () => { expect(client.get).toHaveBeenCalledTimes(1); }); + it(`throws when the type is multi-namespace and the document has all namespaces and the force option is not enabled`, async () => { + const response = getMockGetResponse({ type: MULTI_NAMESPACE_TYPE, id, namespace }); + response._source.namespaces = ['*']; + client.get.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise(response) + ); + await expect( + savedObjectsRepository.delete(MULTI_NAMESPACE_TYPE, id, { namespace }) + ).rejects.toThrowError( + 'Unable to delete saved object that exists in multiple namespaces, use `force` option to delete it anyway' + ); + expect(client.get).toHaveBeenCalledTimes(1); + }); + it(`throws when ES is unable to find the document during delete`, async () => { client.delete.mockResolvedValueOnce( elasticsearchClientMock.createSuccessTransportRequestPromise({ result: 'not_found' }) @@ -2252,7 +2315,7 @@ describe('SavedObjectsRepository', () => { }); describe('errors', () => { - it(`throws when namespace is not a string`, async () => { + it(`throws when namespace is not a string or is '*'`, async () => { const test = async (namespace) => { await expect(savedObjectsRepository.deleteByNamespace(namespace)).rejects.toThrowError( `namespace is required, and must be a string` @@ -2263,6 +2326,7 @@ describe('SavedObjectsRepository', () => { await test(['namespace']); await test(123); await test(true); + await test(ALL_NAMESPACES_STRING); }); }); @@ -2802,6 +2866,12 @@ describe('SavedObjectsRepository', () => { ); }; + it(`throws when options.namespace is '*'`, async () => { + await expect( + savedObjectsRepository.get(type, id, { namespace: ALL_NAMESPACES_STRING }) + ).rejects.toThrowError(createBadRequestError('"options.namespace" cannot be "*"')); + }); + it(`throws when type is invalid`, async () => { await expectNotFoundError('unknownType', id); expect(client.get).not.toHaveBeenCalled(); @@ -2993,6 +3063,14 @@ describe('SavedObjectsRepository', () => { ); }; + it(`throws when options.namespace is '*'`, async () => { + await expect( + savedObjectsRepository.incrementCounter(type, id, field, { + namespace: ALL_NAMESPACES_STRING, + }) + ).rejects.toThrowError(createBadRequestError('"options.namespace" cannot be "*"')); + }); + it(`throws when type is not a string`, async () => { const test = async (type) => { await expect( @@ -3649,6 +3727,12 @@ describe('SavedObjectsRepository', () => { ); }; + it(`throws when options.namespace is '*'`, async () => { + await expect( + savedObjectsRepository.update(type, id, attributes, { namespace: ALL_NAMESPACES_STRING }) + ).rejects.toThrowError(createBadRequestError('"options.namespace" cannot be "*"')); + }); + it(`throws when type is invalid`, async () => { await expectNotFoundError('unknownType', id); expect(client.update).not.toHaveBeenCalled(); diff --git a/src/core/server/saved_objects/service/lib/repository.ts b/src/core/server/saved_objects/service/lib/repository.ts index abeb2c2a7e577f2..0d69a00d8ae1c75 100644 --- a/src/core/server/saved_objects/service/lib/repository.ts +++ b/src/core/server/saved_objects/service/lib/repository.ts @@ -67,7 +67,7 @@ import { } from '../../types'; import { SavedObjectTypeRegistry } from '../../saved_objects_type_registry'; import { validateConvertFilterToKueryNode } from './filter_utils'; -import { SavedObjectsUtils } from './utils'; +import { ALL_NAMESPACES_STRING, SavedObjectsUtils } from './utils'; // BEWARE: The SavedObjectClient depends on the implementation details of the SavedObjectsRepository // so any breaking changes to this repository are considered breaking changes to the SavedObjectsClient. @@ -562,7 +562,10 @@ export class SavedObjectsRepository { if (this._registry.isMultiNamespace(type)) { preflightResult = await this.preflightCheckIncludesNamespace(type, id, namespace); const existingNamespaces = getSavedObjectNamespaces(undefined, preflightResult) ?? []; - if (!force && existingNamespaces.length > 1) { + if ( + !force && + (existingNamespaces.length > 1 || existingNamespaces.includes(ALL_NAMESPACES_STRING)) + ) { throw SavedObjectsErrorHelpers.createBadRequestError( 'Unable to delete saved object that exists in multiple namespaces, use `force` option to delete it anyway' ); @@ -610,8 +613,8 @@ export class SavedObjectsRepository { namespace: string, options: SavedObjectsDeleteByNamespaceOptions = {} ): Promise { - if (!namespace || typeof namespace !== 'string') { - throw new TypeError(`namespace is required, and must be a string`); + if (!namespace || typeof namespace !== 'string' || namespace === '*') { + throw new TypeError(`namespace is required, and must be a string that is not equal to '*'`); } const allTypes = Object.keys(getRootPropertiesObjects(this._mappings)); @@ -1211,6 +1214,19 @@ export class SavedObjectsRepository { } const { attributes, references, version, namespace: objectNamespace } = object; + + if (objectNamespace === ALL_NAMESPACES_STRING) { + return { + tag: 'Left' as 'Left', + error: { + id, + type, + error: errorContent( + SavedObjectsErrorHelpers.createBadRequestError('"namespace" cannot be "*"') + ), + }, + }; + } // `objectNamespace` is a namespace string, while `namespace` is a namespace ID. // The object namespace string, if defined, will supersede the operation's namespace ID. @@ -1526,7 +1542,10 @@ export class SavedObjectsRepository { } const namespaces = raw._source.namespaces; - return namespaces?.includes(SavedObjectsUtils.namespaceIdToString(namespace)) ?? false; + const existsInNamespace = + namespaces?.includes(SavedObjectsUtils.namespaceIdToString(namespace)) || + namespaces?.includes('*'); + return existsInNamespace ?? false; } /** @@ -1653,8 +1672,15 @@ function getSavedObjectNamespaces( * Ensure that a namespace is always in its namespace ID representation. * This allows `'default'` to be used interchangeably with `undefined`. */ -const normalizeNamespace = (namespace?: string) => - namespace === undefined ? namespace : SavedObjectsUtils.namespaceStringToId(namespace); +const normalizeNamespace = (namespace?: string) => { + if (namespace === ALL_NAMESPACES_STRING) { + throw SavedObjectsErrorHelpers.createBadRequestError('"options.namespace" cannot be "*"'); + } else if (namespace === undefined) { + return namespace; + } else { + return SavedObjectsUtils.namespaceStringToId(namespace); + } +}; /** * Extracts the contents of a decorated error to return the attributes for bulk operations. diff --git a/src/core/server/saved_objects/service/lib/search_dsl/query_params.test.ts b/src/core/server/saved_objects/service/lib/search_dsl/query_params.test.ts index 85c47029e36d580..5a048e8f894b428 100644 --- a/src/core/server/saved_objects/service/lib/search_dsl/query_params.test.ts +++ b/src/core/server/saved_objects/service/lib/search_dsl/query_params.test.ts @@ -21,6 +21,7 @@ import { esKuery, KueryNode } from '../../../../../../plugins/data/server'; import { typeRegistryMock } from '../../../saved_objects_type_registry.mock'; +import { ALL_NAMESPACES_STRING } from '../utils'; import { getQueryParams } from './query_params'; const registry = typeRegistryMock.create(); @@ -199,9 +200,10 @@ describe('#getQueryParams', () => { describe('`namespaces` parameter', () => { const createTypeClause = (type: string, namespaces?: string[]) => { if (registry.isMultiNamespace(type)) { + const array = [...(namespaces ?? ['default']), ALL_NAMESPACES_STRING]; return { bool: { - must: expect.arrayContaining([{ terms: { namespaces: namespaces ?? ['default'] } }]), + must: expect.arrayContaining([{ terms: { namespaces: array } }]), must_not: [{ exists: { field: 'namespace' } }], }, }; diff --git a/src/core/server/saved_objects/service/lib/search_dsl/query_params.ts b/src/core/server/saved_objects/service/lib/search_dsl/query_params.ts index 3ff72a86c2f8947..dc33db59258c0a3 100644 --- a/src/core/server/saved_objects/service/lib/search_dsl/query_params.ts +++ b/src/core/server/saved_objects/service/lib/search_dsl/query_params.ts @@ -21,7 +21,7 @@ import { esKuery, KueryNode } from '../../../../../../plugins/data/server'; import { getRootPropertiesObjects, IndexMapping } from '../../../mappings'; import { ISavedObjectTypeRegistry } from '../../../saved_objects_type_registry'; -import { DEFAULT_NAMESPACE_STRING } from '../utils'; +import { ALL_NAMESPACES_STRING, DEFAULT_NAMESPACE_STRING } from '../utils'; /** * Gets the types based on the type. Uses mappings to support @@ -83,7 +83,10 @@ function getClauseForType( if (registry.isMultiNamespace(type)) { return { bool: { - must: [{ term: { type } }, { terms: { namespaces } }], + must: [ + { term: { type } }, + { terms: { namespaces: [...namespaces, ALL_NAMESPACES_STRING] } }, + ], must_not: [{ exists: { field: 'namespace' } }], }, }; diff --git a/src/core/server/saved_objects/service/lib/utils.ts b/src/core/server/saved_objects/service/lib/utils.ts index 6101ad57cc40107..0df0b3a5fd85da9 100644 --- a/src/core/server/saved_objects/service/lib/utils.ts +++ b/src/core/server/saved_objects/service/lib/utils.ts @@ -18,6 +18,7 @@ */ export const DEFAULT_NAMESPACE_STRING = 'default'; +export const ALL_NAMESPACES_STRING = '*'; /** * @public diff --git a/x-pack/plugins/spaces/server/lib/utils/namespace.ts b/x-pack/plugins/spaces/server/lib/utils/namespace.ts index 344da18846f3b74..a34796d3720ae65 100644 --- a/x-pack/plugins/spaces/server/lib/utils/namespace.ts +++ b/x-pack/plugins/spaces/server/lib/utils/namespace.ts @@ -6,6 +6,8 @@ import { SavedObjectsUtils } from '../../../../../../src/core/server'; +export const ALL_SPACES_STRING = '*'; + /** * Converts a Space ID string to its namespace ID representation. Note that a Space ID string is equivalent to a namespace string. * diff --git a/x-pack/plugins/spaces/server/routes/api/external/share_add_spaces.ts b/x-pack/plugins/spaces/server/routes/api/external/share_add_spaces.ts index ee61ccd2d5e4103..3f4e439a8d683e5 100644 --- a/x-pack/plugins/spaces/server/routes/api/external/share_add_spaces.ts +++ b/x-pack/plugins/spaces/server/routes/api/external/share_add_spaces.ts @@ -9,6 +9,7 @@ import { wrapError } from '../../../lib/errors'; import { ExternalRouteDeps } from '.'; import { SPACE_ID_REGEX } from '../../../lib/space_schema'; import { createLicensedRouteHandler } from '../../lib'; +import { ALL_SPACES_STRING } from '../../../lib/utils/namespace'; const uniq = (arr: T[]): T[] => Array.from(new Set(arr)); export function initShareAddSpacesApi(deps: ExternalRouteDeps) { @@ -22,8 +23,8 @@ export function initShareAddSpacesApi(deps: ExternalRouteDeps) { spaces: schema.arrayOf( schema.string({ validate: (value) => { - if (!SPACE_ID_REGEX.test(value)) { - return `lower case, a-z, 0-9, "_", and "-" are allowed`; + if (value !== ALL_SPACES_STRING && !SPACE_ID_REGEX.test(value)) { + return `lower case, a-z, 0-9, "_", and "-" are allowed, OR "*"`; } }, }), diff --git a/x-pack/plugins/spaces/server/routes/api/external/share_remove_spaces.ts b/x-pack/plugins/spaces/server/routes/api/external/share_remove_spaces.ts index d03185ea7aa0954..e2e261ef5b8279a 100644 --- a/x-pack/plugins/spaces/server/routes/api/external/share_remove_spaces.ts +++ b/x-pack/plugins/spaces/server/routes/api/external/share_remove_spaces.ts @@ -9,6 +9,7 @@ import { wrapError } from '../../../lib/errors'; import { ExternalRouteDeps } from '.'; import { SPACE_ID_REGEX } from '../../../lib/space_schema'; import { createLicensedRouteHandler } from '../../lib'; +import { ALL_SPACES_STRING } from '../../../lib/utils/namespace'; const uniq = (arr: T[]): T[] => Array.from(new Set(arr)); export function initShareRemoveSpacesApi(deps: ExternalRouteDeps) { @@ -22,8 +23,8 @@ export function initShareRemoveSpacesApi(deps: ExternalRouteDeps) { spaces: schema.arrayOf( schema.string({ validate: (value) => { - if (!SPACE_ID_REGEX.test(value)) { - return `lower case, a-z, 0-9, "_", and "-" are allowed`; + if (value !== ALL_SPACES_STRING && !SPACE_ID_REGEX.test(value)) { + return `lower case, a-z, 0-9, "_", and "-" are allowed, OR "*"`; } }, }), diff --git a/x-pack/plugins/spaces/server/saved_objects/spaces_saved_objects_client.ts b/x-pack/plugins/spaces/server/saved_objects/spaces_saved_objects_client.ts index 4e830d6149537c7..dfd1f5f0eafca20 100644 --- a/x-pack/plugins/spaces/server/saved_objects/spaces_saved_objects_client.ts +++ b/x-pack/plugins/spaces/server/saved_objects/spaces_saved_objects_client.ts @@ -19,7 +19,7 @@ import { ISavedObjectTypeRegistry, } from 'src/core/server'; import { SpacesServiceSetup } from '../spaces_service/spaces_service'; -import { spaceIdToNamespace } from '../lib/utils/namespace'; +import { ALL_SPACES_STRING, spaceIdToNamespace } from '../lib/utils/namespace'; import { SpacesClient } from '../lib/spaces_client'; interface SpacesSavedObjectsClientOptions { @@ -165,7 +165,7 @@ export class SpacesSavedObjectsClient implements SavedObjectsClientContract { if (namespaces) { const spacesClient = await this.getSpacesClient; const availableSpaces = await spacesClient.getAll('findSavedObjects'); - if (namespaces.includes('*')) { + if (namespaces.includes(ALL_SPACES_STRING)) { namespaces = availableSpaces.map((space) => space.id); } else { namespaces = namespaces.filter((namespace) => diff --git a/x-pack/test/saved_object_api_integration/common/fixtures/es_archiver/saved_objects/spaces/data.json b/x-pack/test/saved_object_api_integration/common/fixtures/es_archiver/saved_objects/spaces/data.json index 4c0447c29c8f9c1..d9d5c6f9c58081f 100644 --- a/x-pack/test/saved_object_api_integration/common/fixtures/es_archiver/saved_objects/spaces/data.json +++ b/x-pack/test/saved_object_api_integration/common/fixtures/es_archiver/saved_objects/spaces/data.json @@ -347,6 +347,23 @@ } } +{ + "type": "doc", + "value": { + "id": "sharedtype:all_spaces", + "index": ".kibana", + "source": { + "sharedtype": { + "title": "A shared saved-object in all spaces" + }, + "type": "sharedtype", + "namespaces": ["*"], + "updated_at": "2017-09-21T18:59:16.270Z" + }, + "type": "doc" + } +} + { "type": "doc", "value": { diff --git a/x-pack/test/saved_object_api_integration/common/lib/saved_object_test_cases.ts b/x-pack/test/saved_object_api_integration/common/lib/saved_object_test_cases.ts index b32950538f8e531..2e747c7bcb20164 100644 --- a/x-pack/test/saved_object_api_integration/common/lib/saved_object_test_cases.ts +++ b/x-pack/test/saved_object_api_integration/common/lib/saved_object_test_cases.ts @@ -17,6 +17,10 @@ export const SAVED_OBJECT_TEST_CASES = Object.freeze({ type: 'isolatedtype', id: 'space2-isolatedtype-id', }), + MULTI_NAMESPACE_ALL_SPACES: Object.freeze({ + type: 'sharedtype', + id: 'all_spaces', + }), MULTI_NAMESPACE_DEFAULT_AND_SPACE_1: Object.freeze({ type: 'sharedtype', id: 'default_and_space_1', diff --git a/x-pack/test/saved_object_api_integration/common/lib/saved_object_test_utils.ts b/x-pack/test/saved_object_api_integration/common/lib/saved_object_test_utils.ts index 595986c08efc1d3..61bac3d314c1b01 100644 --- a/x-pack/test/saved_object_api_integration/common/lib/saved_object_test_utils.ts +++ b/x-pack/test/saved_object_api_integration/common/lib/saved_object_test_utils.ts @@ -16,6 +16,7 @@ const { SPACE_1: { spaceId: SPACE_1_ID }, SPACE_2: { spaceId: SPACE_2_ID }, } = SPACES; +const ALL_SPACES = '*'; const { NOT_A_KIBANA_USER, SUPERUSER, @@ -170,6 +171,8 @@ export const expectResponses = { if (isMultiNamespace(type)) { if (['conflict_1', 'conflict_2a', 'conflict_2b', 'conflict_3', 'conflict_4a'].includes(id)) { expect(actualNamespaces).to.eql([DEFAULT_SPACE_ID, SPACE_1_ID, SPACE_2_ID]); + } else if (id === CASES.MULTI_NAMESPACE_ALL_SPACES.id) { + expect(actualNamespaces).to.eql([ALL_SPACES]); } else if (id === CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1.id) { expect(actualNamespaces).to.eql([DEFAULT_SPACE_ID, SPACE_1_ID]); } else if (id === CASES.MULTI_NAMESPACE_ONLY_SPACE_1.id) { diff --git a/x-pack/test/saved_object_api_integration/common/suites/export.ts b/x-pack/test/saved_object_api_integration/common/suites/export.ts index 4a8eff1fb380c07..eeaa78ef1878340 100644 --- a/x-pack/test/saved_object_api_integration/common/suites/export.ts +++ b/x-pack/test/saved_object_api_integration/common/suites/export.ts @@ -72,14 +72,17 @@ export const getTestCases = (spaceId?: string): { [key: string]: ExportTestCase multiNamespaceType: { title: 'multi-namespace type', type: 'sharedtype', - successResult: (spaceId === SPACE_1_ID - ? [CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1, CASES.MULTI_NAMESPACE_ONLY_SPACE_1] - : spaceId === SPACE_2_ID - ? [CASES.MULTI_NAMESPACE_ONLY_SPACE_2] - : [CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1] - ) - .concat([CONFLICT_1_OBJ, CONFLICT_2A_OBJ, CONFLICT_2B_OBJ, CONFLICT_3_OBJ, CONFLICT_4A_OBJ]) - .flat(), + successResult: [ + CASES.MULTI_NAMESPACE_ALL_SPACES, + ...(spaceId === SPACE_1_ID + ? [CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1, CASES.MULTI_NAMESPACE_ONLY_SPACE_1] + : spaceId === SPACE_2_ID + ? [CASES.MULTI_NAMESPACE_ONLY_SPACE_2] + : [CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1] + ) + .concat([CONFLICT_1_OBJ, CONFLICT_2A_OBJ, CONFLICT_2B_OBJ, CONFLICT_3_OBJ, CONFLICT_4A_OBJ]) + .flat(), + ], }, namespaceAgnosticObject: { title: 'namespace-agnostic object', diff --git a/x-pack/test/saved_object_api_integration/common/suites/find.ts b/x-pack/test/saved_object_api_integration/common/suites/find.ts index bab4a4d88534a8a..42381b50a4dd936 100644 --- a/x-pack/test/saved_object_api_integration/common/suites/find.ts +++ b/x-pack/test/saved_object_api_integration/common/suites/find.ts @@ -16,6 +16,7 @@ import { ExpectResponseBody, TestCase, TestDefinition, TestSuite, TestUser } fro const { DEFAULT: { spaceId: DEFAULT_SPACE_ID }, } = SPACES; +const ALL_SPACES = '*'; export interface FindTestDefinition extends TestDefinition { request: { query: string }; @@ -74,6 +75,7 @@ const CONFLICT_4A_OBJ = Object.freeze({ }); const TEST_CASES = [ + { ...CASES.MULTI_NAMESPACE_ALL_SPACES, namespaces: ['*'] }, { ...CASES.SINGLE_NAMESPACE_DEFAULT_SPACE, namespaces: ['default'] }, { ...CASES.SINGLE_NAMESPACE_SPACE_1, namespaces: ['space_1'] }, { ...CASES.SINGLE_NAMESPACE_SPACE_2, namespaces: ['space_2'] }, @@ -118,12 +120,16 @@ export const getTestCases = ( return TEST_CASES.filter((t) => { const hasOtherNamespaces = Array.isArray(t.namespaces) && - t.namespaces!.some((ns) => ns !== (currentSpace ?? 'default')); + t.namespaces!.some((ns) => ns === ALL_SPACES || ns !== (currentSpace ?? 'default')); return hasOtherNamespaces && predicate(t); }); } return TEST_CASES.filter( - (t) => (!t.namespaces || t.namespaces.includes(currentSpace ?? 'default')) && predicate(t) + (t) => + (!t.namespaces || + t.namespaces.includes(ALL_SPACES) || + t.namespaces.includes(currentSpace ?? 'default')) && + predicate(t) ); }; @@ -254,7 +260,10 @@ export function findTestSuiteFactory(esArchiver: any, supertest: SuperTest) !user || !so.namespaces || so.namespaces.some( - (ns) => user.authorizedAtSpaces.includes(ns) || user.authorizedAtSpaces.includes('*') + (ns) => + ns === ALL_SPACES || + user.authorizedAtSpaces.includes(ns) || + user.authorizedAtSpaces.includes('*') ) ); expect(response.body.page).to.eql(page); diff --git a/x-pack/test/saved_object_api_integration/security_and_spaces/apis/bulk_create.ts b/x-pack/test/saved_object_api_integration/security_and_spaces/apis/bulk_create.ts index 0cc5969e2b7ab03..d16fe5ab68e3455 100644 --- a/x-pack/test/saved_object_api_integration/security_and_spaces/apis/bulk_create.ts +++ b/x-pack/test/saved_object_api_integration/security_and_spaces/apis/bulk_create.ts @@ -33,6 +33,7 @@ const createTestCases = (overwrite: boolean, spaceId: string) => { }, { ...CASES.SINGLE_NAMESPACE_SPACE_1, ...fail409(!overwrite && spaceId === SPACE_1_ID) }, { ...CASES.SINGLE_NAMESPACE_SPACE_2, ...fail409(!overwrite && spaceId === SPACE_2_ID) }, + { ...CASES.MULTI_NAMESPACE_ALL_SPACES, ...fail409(!overwrite) }, { ...CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1, ...fail409(!overwrite || (spaceId !== DEFAULT_SPACE_ID && spaceId !== SPACE_1_ID)), diff --git a/x-pack/test/saved_object_api_integration/security_and_spaces/apis/bulk_get.ts b/x-pack/test/saved_object_api_integration/security_and_spaces/apis/bulk_get.ts index 4a35bdd03e4dd5d..4878d9d81dbf693 100644 --- a/x-pack/test/saved_object_api_integration/security_and_spaces/apis/bulk_get.ts +++ b/x-pack/test/saved_object_api_integration/security_and_spaces/apis/bulk_get.ts @@ -28,6 +28,7 @@ const createTestCases = (spaceId: string) => { { ...CASES.SINGLE_NAMESPACE_DEFAULT_SPACE, ...fail404(spaceId !== DEFAULT_SPACE_ID) }, { ...CASES.SINGLE_NAMESPACE_SPACE_1, ...fail404(spaceId !== SPACE_1_ID) }, { ...CASES.SINGLE_NAMESPACE_SPACE_2, ...fail404(spaceId !== SPACE_2_ID) }, + CASES.MULTI_NAMESPACE_ALL_SPACES, { ...CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1, ...fail404(spaceId !== DEFAULT_SPACE_ID && spaceId !== SPACE_1_ID), diff --git a/x-pack/test/saved_object_api_integration/security_and_spaces/apis/bulk_update.ts b/x-pack/test/saved_object_api_integration/security_and_spaces/apis/bulk_update.ts index 1e11d1fc61110f4..3f4341de6cfc56f 100644 --- a/x-pack/test/saved_object_api_integration/security_and_spaces/apis/bulk_update.ts +++ b/x-pack/test/saved_object_api_integration/security_and_spaces/apis/bulk_update.ts @@ -28,6 +28,7 @@ const createTestCases = (spaceId: string) => { { ...CASES.SINGLE_NAMESPACE_DEFAULT_SPACE, ...fail404(spaceId !== DEFAULT_SPACE_ID) }, { ...CASES.SINGLE_NAMESPACE_SPACE_1, ...fail404(spaceId !== SPACE_1_ID) }, { ...CASES.SINGLE_NAMESPACE_SPACE_2, ...fail404(spaceId !== SPACE_2_ID) }, + CASES.MULTI_NAMESPACE_ALL_SPACES, { ...CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1, ...fail404(spaceId !== DEFAULT_SPACE_ID && spaceId !== SPACE_1_ID), @@ -44,6 +45,7 @@ const createTestCases = (spaceId: string) => { { ...CASES.SINGLE_NAMESPACE_DEFAULT_SPACE, namespace: DEFAULT_SPACE_ID }, { ...CASES.SINGLE_NAMESPACE_SPACE_1, namespace: SPACE_1_ID }, { ...CASES.SINGLE_NAMESPACE_SPACE_2, namespace: SPACE_1_ID, ...fail404() }, // intentional 404 test case + { ...CASES.MULTI_NAMESPACE_ALL_SPACES, namespace: DEFAULT_SPACE_ID }, // any spaceId will work (not '*') { ...CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1, namespace: DEFAULT_SPACE_ID }, // SPACE_1_ID would also work { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_1, namespace: SPACE_2_ID, ...fail404() }, // intentional 404 test case { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_2, namespace: SPACE_2_ID }, diff --git a/x-pack/test/saved_object_api_integration/security_and_spaces/apis/create.ts b/x-pack/test/saved_object_api_integration/security_and_spaces/apis/create.ts index f81488603dc83e3..9ced649e5a12334 100644 --- a/x-pack/test/saved_object_api_integration/security_and_spaces/apis/create.ts +++ b/x-pack/test/saved_object_api_integration/security_and_spaces/apis/create.ts @@ -31,6 +31,7 @@ const createTestCases = (overwrite: boolean, spaceId: string) => { }, { ...CASES.SINGLE_NAMESPACE_SPACE_1, ...fail409(!overwrite && spaceId === SPACE_1_ID) }, { ...CASES.SINGLE_NAMESPACE_SPACE_2, ...fail409(!overwrite && spaceId === SPACE_2_ID) }, + { ...CASES.MULTI_NAMESPACE_ALL_SPACES, ...fail409(!overwrite) }, { ...CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1, ...fail409(!overwrite || (spaceId !== DEFAULT_SPACE_ID && spaceId !== SPACE_1_ID)), diff --git a/x-pack/test/saved_object_api_integration/security_and_spaces/apis/delete.ts b/x-pack/test/saved_object_api_integration/security_and_spaces/apis/delete.ts index eed67b6779679ba..436f09e8d2ee010 100644 --- a/x-pack/test/saved_object_api_integration/security_and_spaces/apis/delete.ts +++ b/x-pack/test/saved_object_api_integration/security_and_spaces/apis/delete.ts @@ -28,6 +28,9 @@ const createTestCases = (spaceId: string) => { { ...CASES.SINGLE_NAMESPACE_DEFAULT_SPACE, ...fail404(spaceId !== DEFAULT_SPACE_ID) }, { ...CASES.SINGLE_NAMESPACE_SPACE_1, ...fail404(spaceId !== SPACE_1_ID) }, { ...CASES.SINGLE_NAMESPACE_SPACE_2, ...fail404(spaceId !== SPACE_2_ID) }, + { ...CASES.MULTI_NAMESPACE_ALL_SPACES, ...fail400() }, + // try to delete this object again, this time using the `force` option + { ...CASES.MULTI_NAMESPACE_ALL_SPACES, force: true }, { ...CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1, ...fail400(spaceId === DEFAULT_SPACE_ID || spaceId === SPACE_1_ID), diff --git a/x-pack/test/saved_object_api_integration/security_and_spaces/apis/get.ts b/x-pack/test/saved_object_api_integration/security_and_spaces/apis/get.ts index dabe174af4d4be6..b554eb55b0adb1b 100644 --- a/x-pack/test/saved_object_api_integration/security_and_spaces/apis/get.ts +++ b/x-pack/test/saved_object_api_integration/security_and_spaces/apis/get.ts @@ -28,6 +28,7 @@ const createTestCases = (spaceId: string) => { { ...CASES.SINGLE_NAMESPACE_DEFAULT_SPACE, ...fail404(spaceId !== DEFAULT_SPACE_ID) }, { ...CASES.SINGLE_NAMESPACE_SPACE_1, ...fail404(spaceId !== SPACE_1_ID) }, { ...CASES.SINGLE_NAMESPACE_SPACE_2, ...fail404(spaceId !== SPACE_2_ID) }, + CASES.MULTI_NAMESPACE_ALL_SPACES, { ...CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1, ...fail404(spaceId !== DEFAULT_SPACE_ID && spaceId !== SPACE_1_ID), diff --git a/x-pack/test/saved_object_api_integration/security_and_spaces/apis/import.ts b/x-pack/test/saved_object_api_integration/security_and_spaces/apis/import.ts index 0b531a3dccc1abd..a319a73c6a98ab4 100644 --- a/x-pack/test/saved_object_api_integration/security_and_spaces/apis/import.ts +++ b/x-pack/test/saved_object_api_integration/security_and_spaces/apis/import.ts @@ -58,6 +58,7 @@ const createTestCases = (overwrite: boolean, spaceId: string) => { const group2 = [ // when overwrite=true, all of the objects in this group are created successfully, so we can check the created object attributes CASES.NEW_MULTI_NAMESPACE_OBJ, + { ...CASES.MULTI_NAMESPACE_ALL_SPACES, ...fail409(!overwrite) }, { ...CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1, ...fail409(!overwrite && (spaceId === DEFAULT_SPACE_ID || spaceId === SPACE_1_ID)), diff --git a/x-pack/test/saved_object_api_integration/security_and_spaces/apis/resolve_import_errors.ts b/x-pack/test/saved_object_api_integration/security_and_spaces/apis/resolve_import_errors.ts index 792fe63e5932d7d..b0f4f13f268c9e6 100644 --- a/x-pack/test/saved_object_api_integration/security_and_spaces/apis/resolve_import_errors.ts +++ b/x-pack/test/saved_object_api_integration/security_and_spaces/apis/resolve_import_errors.ts @@ -55,6 +55,7 @@ const createTestCases = (overwrite: boolean, spaceId: string) => { const group1NonImportable = [{ ...CASES.HIDDEN, ...fail400() }]; const group1All = [...group1Importable, ...group1NonImportable]; const group2 = [ + { ...CASES.MULTI_NAMESPACE_ALL_SPACES, ...fail409(!overwrite) }, { ...CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1, ...fail409(!overwrite && (spaceId === DEFAULT_SPACE_ID || spaceId === SPACE_1_ID)), diff --git a/x-pack/test/saved_object_api_integration/security_and_spaces/apis/update.ts b/x-pack/test/saved_object_api_integration/security_and_spaces/apis/update.ts index fec6f2b7de71545..a976ce08adb1f25 100644 --- a/x-pack/test/saved_object_api_integration/security_and_spaces/apis/update.ts +++ b/x-pack/test/saved_object_api_integration/security_and_spaces/apis/update.ts @@ -28,6 +28,7 @@ const createTestCases = (spaceId: string) => { { ...CASES.SINGLE_NAMESPACE_DEFAULT_SPACE, ...fail404(spaceId !== DEFAULT_SPACE_ID) }, { ...CASES.SINGLE_NAMESPACE_SPACE_1, ...fail404(spaceId !== SPACE_1_ID) }, { ...CASES.SINGLE_NAMESPACE_SPACE_2, ...fail404(spaceId !== SPACE_2_ID) }, + CASES.MULTI_NAMESPACE_ALL_SPACES, { ...CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1, ...fail404(spaceId !== DEFAULT_SPACE_ID && spaceId !== SPACE_1_ID), diff --git a/x-pack/test/saved_object_api_integration/security_only/apis/bulk_create.ts b/x-pack/test/saved_object_api_integration/security_only/apis/bulk_create.ts index 725120687c2313e..26a53fc50f92155 100644 --- a/x-pack/test/saved_object_api_integration/security_only/apis/bulk_create.ts +++ b/x-pack/test/saved_object_api_integration/security_only/apis/bulk_create.ts @@ -23,6 +23,7 @@ const createTestCases = (overwrite: boolean) => { { ...CASES.SINGLE_NAMESPACE_DEFAULT_SPACE, ...fail409(!overwrite) }, CASES.SINGLE_NAMESPACE_SPACE_1, CASES.SINGLE_NAMESPACE_SPACE_2, + { ...CASES.MULTI_NAMESPACE_ALL_SPACES, ...fail409(!overwrite) }, { ...CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1, ...fail409(!overwrite) }, { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_1, ...fail409(), ...unresolvableConflict() }, { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_2, ...fail409(), ...unresolvableConflict() }, diff --git a/x-pack/test/saved_object_api_integration/security_only/apis/bulk_get.ts b/x-pack/test/saved_object_api_integration/security_only/apis/bulk_get.ts index d305e08da1b3270..96eddf1f8bd3cc6 100644 --- a/x-pack/test/saved_object_api_integration/security_only/apis/bulk_get.ts +++ b/x-pack/test/saved_object_api_integration/security_only/apis/bulk_get.ts @@ -22,6 +22,7 @@ const createTestCases = () => { CASES.SINGLE_NAMESPACE_DEFAULT_SPACE, { ...CASES.SINGLE_NAMESPACE_SPACE_1, ...fail404() }, { ...CASES.SINGLE_NAMESPACE_SPACE_2, ...fail404() }, + CASES.MULTI_NAMESPACE_ALL_SPACES, CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1, { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_1, ...fail404() }, { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_2, ...fail404() }, diff --git a/x-pack/test/saved_object_api_integration/security_only/apis/bulk_update.ts b/x-pack/test/saved_object_api_integration/security_only/apis/bulk_update.ts index 39ceb5a70d1b230..2a19c56f80ce6f0 100644 --- a/x-pack/test/saved_object_api_integration/security_only/apis/bulk_update.ts +++ b/x-pack/test/saved_object_api_integration/security_only/apis/bulk_update.ts @@ -28,6 +28,7 @@ const createTestCases = () => { CASES.SINGLE_NAMESPACE_DEFAULT_SPACE, { ...CASES.SINGLE_NAMESPACE_SPACE_1, ...fail404() }, { ...CASES.SINGLE_NAMESPACE_SPACE_2, ...fail404() }, + CASES.MULTI_NAMESPACE_ALL_SPACES, CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1, { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_1, ...fail404() }, { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_2, ...fail404() }, @@ -42,6 +43,7 @@ const createTestCases = () => { { ...CASES.SINGLE_NAMESPACE_DEFAULT_SPACE, namespace: DEFAULT_SPACE_ID }, { ...CASES.SINGLE_NAMESPACE_SPACE_1, namespace: SPACE_1_ID }, { ...CASES.SINGLE_NAMESPACE_SPACE_2, namespace: SPACE_1_ID, ...fail404() }, // intentional 404 test case + { ...CASES.MULTI_NAMESPACE_ALL_SPACES, namespace: DEFAULT_SPACE_ID }, // any spaceId will work (not '*') { ...CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1, namespace: DEFAULT_SPACE_ID }, // SPACE_1_ID would also work { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_1, namespace: SPACE_2_ID, ...fail404() }, // intentional 404 test case { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_2, namespace: SPACE_2_ID }, diff --git a/x-pack/test/saved_object_api_integration/security_only/apis/create.ts b/x-pack/test/saved_object_api_integration/security_only/apis/create.ts index 88d096f05d84661..be867d03aa51da2 100644 --- a/x-pack/test/saved_object_api_integration/security_only/apis/create.ts +++ b/x-pack/test/saved_object_api_integration/security_only/apis/create.ts @@ -22,6 +22,7 @@ const createTestCases = (overwrite: boolean) => { { ...CASES.SINGLE_NAMESPACE_DEFAULT_SPACE, ...fail409(!overwrite) }, CASES.SINGLE_NAMESPACE_SPACE_1, CASES.SINGLE_NAMESPACE_SPACE_2, + { ...CASES.MULTI_NAMESPACE_ALL_SPACES, ...fail409(!overwrite) }, { ...CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1, ...fail409(!overwrite) }, { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_1, ...fail409() }, { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_2, ...fail409() }, diff --git a/x-pack/test/saved_object_api_integration/security_only/apis/delete.ts b/x-pack/test/saved_object_api_integration/security_only/apis/delete.ts index f1aee480c106173..4caf112a59b272b 100644 --- a/x-pack/test/saved_object_api_integration/security_only/apis/delete.ts +++ b/x-pack/test/saved_object_api_integration/security_only/apis/delete.ts @@ -22,6 +22,9 @@ const createTestCases = () => { CASES.SINGLE_NAMESPACE_DEFAULT_SPACE, { ...CASES.SINGLE_NAMESPACE_SPACE_1, ...fail404() }, { ...CASES.SINGLE_NAMESPACE_SPACE_2, ...fail404() }, + { ...CASES.MULTI_NAMESPACE_ALL_SPACES, ...fail400() }, + // try to delete this object again, this time using the `force` option + { ...CASES.MULTI_NAMESPACE_ALL_SPACES, force: true }, { ...CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1, ...fail400() }, // try to delete this object again, this time using the `force` option { ...CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1, force: true }, diff --git a/x-pack/test/saved_object_api_integration/security_only/apis/get.ts b/x-pack/test/saved_object_api_integration/security_only/apis/get.ts index 0f105b939960f27..5eed2839b61722c 100644 --- a/x-pack/test/saved_object_api_integration/security_only/apis/get.ts +++ b/x-pack/test/saved_object_api_integration/security_only/apis/get.ts @@ -22,6 +22,7 @@ const createTestCases = () => { CASES.SINGLE_NAMESPACE_DEFAULT_SPACE, { ...CASES.SINGLE_NAMESPACE_SPACE_1, ...fail404() }, { ...CASES.SINGLE_NAMESPACE_SPACE_2, ...fail404() }, + CASES.MULTI_NAMESPACE_ALL_SPACES, CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1, { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_1, ...fail404() }, { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_2, ...fail404() }, diff --git a/x-pack/test/saved_object_api_integration/security_only/apis/import.ts b/x-pack/test/saved_object_api_integration/security_only/apis/import.ts index 34be3b7408432a4..df763dba6d18abd 100644 --- a/x-pack/test/saved_object_api_integration/security_only/apis/import.ts +++ b/x-pack/test/saved_object_api_integration/security_only/apis/import.ts @@ -49,6 +49,7 @@ const createTestCases = (overwrite: boolean) => { const group2 = [ // when overwrite=true, all of the objects in this group are created successfully, so we can check the created object attributes CASES.NEW_MULTI_NAMESPACE_OBJ, + { ...CASES.MULTI_NAMESPACE_ALL_SPACES, ...fail409(!overwrite) }, { ...CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1, ...fail409(!overwrite) }, { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_1, ...destinationId() }, { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_2, ...destinationId() }, diff --git a/x-pack/test/saved_object_api_integration/security_only/apis/resolve_import_errors.ts b/x-pack/test/saved_object_api_integration/security_only/apis/resolve_import_errors.ts index 91134dd14bd8a30..22734e95da0b590 100644 --- a/x-pack/test/saved_object_api_integration/security_only/apis/resolve_import_errors.ts +++ b/x-pack/test/saved_object_api_integration/security_only/apis/resolve_import_errors.ts @@ -43,6 +43,7 @@ const createTestCases = (overwrite: boolean) => { const group1NonImportable = [{ ...CASES.HIDDEN, ...fail400() }]; const group1All = [...group1Importable, ...group1NonImportable]; const group2 = [ + { ...CASES.MULTI_NAMESPACE_ALL_SPACES, ...fail409(!overwrite) }, { ...CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1, ...fail409(!overwrite) }, { ...CASES.CONFLICT_1A_OBJ, ...newCopy() }, // "ambiguous source" conflict which results in a new destination ID and empty origin ID { ...CASES.CONFLICT_1B_OBJ, ...newCopy() }, // "ambiguous source" conflict which results in a new destination ID and empty origin ID diff --git a/x-pack/test/saved_object_api_integration/security_only/apis/update.ts b/x-pack/test/saved_object_api_integration/security_only/apis/update.ts index c1fd350101fd4e8..d6e22abf4af246c 100644 --- a/x-pack/test/saved_object_api_integration/security_only/apis/update.ts +++ b/x-pack/test/saved_object_api_integration/security_only/apis/update.ts @@ -22,6 +22,7 @@ const createTestCases = () => { CASES.SINGLE_NAMESPACE_DEFAULT_SPACE, { ...CASES.SINGLE_NAMESPACE_SPACE_1, ...fail404() }, { ...CASES.SINGLE_NAMESPACE_SPACE_2, ...fail404() }, + CASES.MULTI_NAMESPACE_ALL_SPACES, CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1, { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_1, ...fail404() }, { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_2, ...fail404() }, diff --git a/x-pack/test/saved_object_api_integration/spaces_only/apis/bulk_create.ts b/x-pack/test/saved_object_api_integration/spaces_only/apis/bulk_create.ts index 74fade39bf7a580..457c3863d056000 100644 --- a/x-pack/test/saved_object_api_integration/spaces_only/apis/bulk_create.ts +++ b/x-pack/test/saved_object_api_integration/spaces_only/apis/bulk_create.ts @@ -28,6 +28,7 @@ const createTestCases = (overwrite: boolean, spaceId: string) => [ }, { ...CASES.SINGLE_NAMESPACE_SPACE_1, ...fail409(!overwrite && spaceId === SPACE_1_ID) }, { ...CASES.SINGLE_NAMESPACE_SPACE_2, ...fail409(!overwrite && spaceId === SPACE_2_ID) }, + { ...CASES.MULTI_NAMESPACE_ALL_SPACES, ...fail409(!overwrite) }, { ...CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1, ...fail409(!overwrite || (spaceId !== DEFAULT_SPACE_ID && spaceId !== SPACE_1_ID)), diff --git a/x-pack/test/saved_object_api_integration/spaces_only/apis/bulk_get.ts b/x-pack/test/saved_object_api_integration/spaces_only/apis/bulk_get.ts index 37bb2ec920c1e62..7eef9a95f523854 100644 --- a/x-pack/test/saved_object_api_integration/spaces_only/apis/bulk_get.ts +++ b/x-pack/test/saved_object_api_integration/spaces_only/apis/bulk_get.ts @@ -22,6 +22,7 @@ const createTestCases = (spaceId: string) => [ { ...CASES.SINGLE_NAMESPACE_DEFAULT_SPACE, ...fail404(spaceId !== DEFAULT_SPACE_ID) }, { ...CASES.SINGLE_NAMESPACE_SPACE_1, ...fail404(spaceId !== SPACE_1_ID) }, { ...CASES.SINGLE_NAMESPACE_SPACE_2, ...fail404(spaceId !== SPACE_2_ID) }, + CASES.MULTI_NAMESPACE_ALL_SPACES, { ...CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1, ...fail404(spaceId !== DEFAULT_SPACE_ID && spaceId !== SPACE_1_ID), diff --git a/x-pack/test/saved_object_api_integration/spaces_only/apis/bulk_update.ts b/x-pack/test/saved_object_api_integration/spaces_only/apis/bulk_update.ts index b51ec303fadf3f8..e789377b93fe161 100644 --- a/x-pack/test/saved_object_api_integration/spaces_only/apis/bulk_update.ts +++ b/x-pack/test/saved_object_api_integration/spaces_only/apis/bulk_update.ts @@ -23,6 +23,7 @@ const createTestCases = (spaceId: string) => { { ...CASES.SINGLE_NAMESPACE_DEFAULT_SPACE, ...fail404(spaceId !== DEFAULT_SPACE_ID) }, { ...CASES.SINGLE_NAMESPACE_SPACE_1, ...fail404(spaceId !== SPACE_1_ID) }, { ...CASES.SINGLE_NAMESPACE_SPACE_2, ...fail404(spaceId !== SPACE_2_ID) }, + CASES.MULTI_NAMESPACE_ALL_SPACES, { ...CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1, ...fail404(spaceId !== DEFAULT_SPACE_ID && spaceId !== SPACE_1_ID), @@ -39,6 +40,7 @@ const createTestCases = (spaceId: string) => { { ...CASES.SINGLE_NAMESPACE_DEFAULT_SPACE, namespace: DEFAULT_SPACE_ID }, { ...CASES.SINGLE_NAMESPACE_SPACE_1, namespace: SPACE_1_ID }, { ...CASES.SINGLE_NAMESPACE_SPACE_2, namespace: SPACE_1_ID, ...fail404() }, // intentional 404 test case + { ...CASES.MULTI_NAMESPACE_ALL_SPACES, namespace: spaceId }, // any spaceId will work (not '*') { ...CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1, namespace: DEFAULT_SPACE_ID }, // SPACE_1_ID would also work { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_1, namespace: SPACE_2_ID, ...fail404() }, // intentional 404 test case { ...CASES.MULTI_NAMESPACE_ONLY_SPACE_2, namespace: SPACE_2_ID }, diff --git a/x-pack/test/saved_object_api_integration/spaces_only/apis/create.ts b/x-pack/test/saved_object_api_integration/spaces_only/apis/create.ts index 1040f7fd81ddee0..145630eb501ba05 100644 --- a/x-pack/test/saved_object_api_integration/spaces_only/apis/create.ts +++ b/x-pack/test/saved_object_api_integration/spaces_only/apis/create.ts @@ -25,6 +25,7 @@ const createTestCases = (overwrite: boolean, spaceId: string) => [ }, { ...CASES.SINGLE_NAMESPACE_SPACE_1, ...fail409(!overwrite && spaceId === SPACE_1_ID) }, { ...CASES.SINGLE_NAMESPACE_SPACE_2, ...fail409(!overwrite && spaceId === SPACE_2_ID) }, + { ...CASES.MULTI_NAMESPACE_ALL_SPACES, ...fail409(!overwrite) }, { ...CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1, ...fail409(!overwrite || (spaceId !== DEFAULT_SPACE_ID && spaceId !== SPACE_1_ID)), diff --git a/x-pack/test/saved_object_api_integration/spaces_only/apis/delete.ts b/x-pack/test/saved_object_api_integration/spaces_only/apis/delete.ts index eab089084ca9401..66309a4be446085 100644 --- a/x-pack/test/saved_object_api_integration/spaces_only/apis/delete.ts +++ b/x-pack/test/saved_object_api_integration/spaces_only/apis/delete.ts @@ -22,6 +22,9 @@ const createTestCases = (spaceId: string) => [ { ...CASES.SINGLE_NAMESPACE_DEFAULT_SPACE, ...fail404(spaceId !== DEFAULT_SPACE_ID) }, { ...CASES.SINGLE_NAMESPACE_SPACE_1, ...fail404(spaceId !== SPACE_1_ID) }, { ...CASES.SINGLE_NAMESPACE_SPACE_2, ...fail404(spaceId !== SPACE_2_ID) }, + { ...CASES.MULTI_NAMESPACE_ALL_SPACES, ...fail400() }, + // try to delete this object again, this time using the `force` option + { ...CASES.MULTI_NAMESPACE_ALL_SPACES, force: true }, { ...CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1, ...fail400(spaceId === DEFAULT_SPACE_ID || spaceId === SPACE_1_ID), diff --git a/x-pack/test/saved_object_api_integration/spaces_only/apis/get.ts b/x-pack/test/saved_object_api_integration/spaces_only/apis/get.ts index b0fed3e13b9af83..a56216537a365f6 100644 --- a/x-pack/test/saved_object_api_integration/spaces_only/apis/get.ts +++ b/x-pack/test/saved_object_api_integration/spaces_only/apis/get.ts @@ -22,6 +22,7 @@ const createTestCases = (spaceId: string) => [ { ...CASES.SINGLE_NAMESPACE_DEFAULT_SPACE, ...fail404(spaceId !== DEFAULT_SPACE_ID) }, { ...CASES.SINGLE_NAMESPACE_SPACE_1, ...fail404(spaceId !== SPACE_1_ID) }, { ...CASES.SINGLE_NAMESPACE_SPACE_2, ...fail404(spaceId !== SPACE_2_ID) }, + CASES.MULTI_NAMESPACE_ALL_SPACES, { ...CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1, ...fail404(spaceId !== DEFAULT_SPACE_ID && spaceId !== SPACE_1_ID), diff --git a/x-pack/test/saved_object_api_integration/spaces_only/apis/import.ts b/x-pack/test/saved_object_api_integration/spaces_only/apis/import.ts index a36249528540b86..3009fa0bd75a4d5 100644 --- a/x-pack/test/saved_object_api_integration/spaces_only/apis/import.ts +++ b/x-pack/test/saved_object_api_integration/spaces_only/apis/import.ts @@ -44,6 +44,7 @@ const createTestCases = (overwrite: boolean, spaceId: string) => { }, { ...CASES.SINGLE_NAMESPACE_SPACE_1, ...fail409(!overwrite && spaceId === SPACE_1_ID) }, { ...CASES.SINGLE_NAMESPACE_SPACE_2, ...fail409(!overwrite && spaceId === SPACE_2_ID) }, + { ...CASES.MULTI_NAMESPACE_ALL_SPACES, ...fail409(!overwrite) }, { ...CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1, ...fail409(!overwrite && (spaceId === DEFAULT_SPACE_ID || spaceId === SPACE_1_ID)), diff --git a/x-pack/test/saved_object_api_integration/spaces_only/apis/resolve_import_errors.ts b/x-pack/test/saved_object_api_integration/spaces_only/apis/resolve_import_errors.ts index 1431a61b1cbe072..721a6b2bf710805 100644 --- a/x-pack/test/saved_object_api_integration/spaces_only/apis/resolve_import_errors.ts +++ b/x-pack/test/saved_object_api_integration/spaces_only/apis/resolve_import_errors.ts @@ -48,6 +48,7 @@ const createTestCases = (overwrite: boolean, spaceId: string) => { : CASES.SINGLE_NAMESPACE_SPACE_2; return [ { ...singleNamespaceObject, ...fail409(!overwrite) }, + { ...CASES.MULTI_NAMESPACE_ALL_SPACES, ...fail409(!overwrite) }, { ...CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1, ...fail409(!overwrite && (spaceId === DEFAULT_SPACE_ID || spaceId === SPACE_1_ID)), diff --git a/x-pack/test/saved_object_api_integration/spaces_only/apis/update.ts b/x-pack/test/saved_object_api_integration/spaces_only/apis/update.ts index 31ef6fb25b2f213..7a004290249ca63 100644 --- a/x-pack/test/saved_object_api_integration/spaces_only/apis/update.ts +++ b/x-pack/test/saved_object_api_integration/spaces_only/apis/update.ts @@ -22,6 +22,7 @@ const createTestCases = (spaceId: string) => [ { ...CASES.SINGLE_NAMESPACE_DEFAULT_SPACE, ...fail404(spaceId !== DEFAULT_SPACE_ID) }, { ...CASES.SINGLE_NAMESPACE_SPACE_1, ...fail404(spaceId !== SPACE_1_ID) }, { ...CASES.SINGLE_NAMESPACE_SPACE_2, ...fail404(spaceId !== SPACE_2_ID) }, + CASES.MULTI_NAMESPACE_ALL_SPACES, { ...CASES.MULTI_NAMESPACE_DEFAULT_AND_SPACE_1, ...fail404(spaceId !== DEFAULT_SPACE_ID && spaceId !== SPACE_1_ID), diff --git a/x-pack/test/spaces_api_integration/common/fixtures/es_archiver/saved_objects/spaces/data.json b/x-pack/test/spaces_api_integration/common/fixtures/es_archiver/saved_objects/spaces/data.json index 7e528c23c20a05b..5ce6c0ce6b7c5b1 100644 --- a/x-pack/test/spaces_api_integration/common/fixtures/es_archiver/saved_objects/spaces/data.json +++ b/x-pack/test/spaces_api_integration/common/fixtures/es_archiver/saved_objects/spaces/data.json @@ -482,7 +482,7 @@ { "type": "doc", "value": { - "id": "sharedtype:all_spaces", + "id": "sharedtype:each_space", "index": ".kibana", "source": { "sharedtype": { @@ -496,6 +496,23 @@ } } +{ + "type": "doc", + "value": { + "id": "sharedtype:all_spaces", + "index": ".kibana", + "source": { + "sharedtype": { + "title": "A shared saved-object in all spaces" + }, + "type": "sharedtype", + "namespaces": ["*"], + "updated_at": "2017-09-21T18:59:16.270Z" + }, + "type": "doc" + } +} + { "type": "doc", "value": { diff --git a/x-pack/test/spaces_api_integration/common/lib/saved_object_test_cases.ts b/x-pack/test/spaces_api_integration/common/lib/saved_object_test_cases.ts index 3b0f5f8570aa323..9b8baa7f22a2bb6 100644 --- a/x-pack/test/spaces_api_integration/common/lib/saved_object_test_cases.ts +++ b/x-pack/test/spaces_api_integration/common/lib/saved_object_test_cases.ts @@ -29,9 +29,13 @@ export const MULTI_NAMESPACE_SAVED_OBJECT_TEST_CASES = Object.freeze({ id: 'space_1_and_space_2', existingNamespaces: ['space_1', 'space_2'], }), + EACH_SPACE: Object.freeze({ + id: 'each_space', + existingNamespaces: ['default', 'space_1', 'space_2'], // each individual space + }), ALL_SPACES: Object.freeze({ id: 'all_spaces', - existingNamespaces: ['default', 'space_1', 'space_2'], + existingNamespaces: ['*'], // all current and future spaces }), DOES_NOT_EXIST: Object.freeze({ id: 'does_not_exist', diff --git a/x-pack/test/spaces_api_integration/common/suites/copy_to_space.ts b/x-pack/test/spaces_api_integration/common/suites/copy_to_space.ts index 26c736034501f75..ee7a2fb7316571c 100644 --- a/x-pack/test/spaces_api_integration/common/suites/copy_to_space.ts +++ b/x-pack/test/spaces_api_integration/common/suites/copy_to_space.ts @@ -423,7 +423,7 @@ export function copyToSpaceTestSuiteFactory( const type = 'sharedtype'; const v4 = new RegExp(/^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i); const noConflictId = `${spaceId}_only`; - const exactMatchId = 'all_spaces'; + const exactMatchId = 'each_space'; const inexactMatchId = `conflict_1_${spaceId}`; const ambiguousConflictId = `conflict_2_${spaceId}`; diff --git a/x-pack/test/spaces_api_integration/common/suites/resolve_copy_to_space_conflicts.ts b/x-pack/test/spaces_api_integration/common/suites/resolve_copy_to_space_conflicts.ts index cb9219b1ba2ed83..eba7e2033eadf23 100644 --- a/x-pack/test/spaces_api_integration/common/suites/resolve_copy_to_space_conflicts.ts +++ b/x-pack/test/spaces_api_integration/common/suites/resolve_copy_to_space_conflicts.ts @@ -310,7 +310,7 @@ export function resolveCopyToSpaceConflictsSuite( // a 403 error actually comes back as an HTTP 200 response const statusCode = outcome === 'noAccess' ? 404 : 200; const type = 'sharedtype'; - const exactMatchId = 'all_spaces'; + const exactMatchId = 'each_space'; const inexactMatchId = `conflict_1_${spaceId}`; const ambiguousConflictId = `conflict_2_${spaceId}`; diff --git a/x-pack/test/spaces_api_integration/common/suites/share_add.ts b/x-pack/test/spaces_api_integration/common/suites/share_add.ts index 219190cb2800296..54d636c938b580a 100644 --- a/x-pack/test/spaces_api_integration/common/suites/share_add.ts +++ b/x-pack/test/spaces_api_integration/common/suites/share_add.ts @@ -26,7 +26,6 @@ export interface ShareAddTestCase { id: string; namespaces: string[]; failure?: 400 | 403 | 404; - fail400Param?: string; fail403Param?: string; } @@ -42,19 +41,12 @@ export function shareAddTestSuiteFactory(esArchiver: any, supertest: SuperTest async ( response: Record ) => { - const { id, failure, fail400Param, fail403Param } = testCase; + const { id, failure, fail403Param } = testCase; const object = response.body; if (failure === 403) { await expectResponses.forbiddenTypes(fail403Param!)(TYPE)(response); - } else if (failure) { - let error: any; - if (failure === 400) { - error = SavedObjectsErrorHelpers.createBadRequestError( - `${id} already exists in the following namespace(s): ${fail400Param}` - ); - } else if (failure === 404) { - error = SavedObjectsErrorHelpers.createGenericNotFoundError(TYPE, id); - } + } else if (failure === 404) { + const error = SavedObjectsErrorHelpers.createGenericNotFoundError(TYPE, id); expect(object.error).to.eql(error.output.payload.error); expect(object.statusCode).to.eql(error.output.payload.statusCode); } else { diff --git a/x-pack/test/spaces_api_integration/common/suites/share_remove.ts b/x-pack/test/spaces_api_integration/common/suites/share_remove.ts index 0748aa797264cb9..0169d4eb4c64bc9 100644 --- a/x-pack/test/spaces_api_integration/common/suites/share_remove.ts +++ b/x-pack/test/spaces_api_integration/common/suites/share_remove.ts @@ -27,7 +27,6 @@ export interface ShareRemoveTestCase { id: string; namespaces: string[]; failure?: 400 | 403 | 404; - fail400Param?: string; } const TYPE = 'sharedtype'; @@ -41,19 +40,12 @@ export function shareRemoveTestSuiteFactory(esArchiver: any, supertest: SuperTes const expectResponseBody = (testCase: ShareRemoveTestCase): ExpectResponseBody => async ( response: Record ) => { - const { id, failure, fail400Param } = testCase; + const { id, failure } = testCase; const object = response.body; if (failure === 403) { await expectForbidden(TYPE)(response); - } else if (failure) { - let error: any; - if (failure === 400) { - error = SavedObjectsErrorHelpers.createBadRequestError( - `${id} doesn't exist in the following namespace(s): ${fail400Param}` - ); - } else if (failure === 404) { - error = SavedObjectsErrorHelpers.createGenericNotFoundError(TYPE, id); - } + } else if (failure === 404) { + const error = SavedObjectsErrorHelpers.createGenericNotFoundError(TYPE, id); expect(object.error).to.eql(error.output.payload.error); expect(object.statusCode).to.eql(error.output.payload.statusCode); } else { diff --git a/x-pack/test/spaces_api_integration/security_and_spaces/apis/share_add.ts b/x-pack/test/spaces_api_integration/security_and_spaces/apis/share_add.ts index ddd029c8d7d687e..937aaff05958016 100644 --- a/x-pack/test/spaces_api_integration/security_and_spaces/apis/share_add.ts +++ b/x-pack/test/spaces_api_integration/security_and_spaces/apis/share_add.ts @@ -12,7 +12,11 @@ import { import { TestUser } from '../../../saved_object_api_integration/common/lib/types'; import { MULTI_NAMESPACE_SAVED_OBJECT_TEST_CASES as CASES } from '../../common/lib/saved_object_test_cases'; import { TestInvoker } from '../../common/lib/types'; -import { shareAddTestSuiteFactory, ShareAddTestDefinition } from '../../common/suites/share_add'; +import { + shareAddTestSuiteFactory, + ShareAddTestDefinition, + ShareAddTestCase, +} from '../../common/suites/share_add'; const { DEFAULT: { spaceId: DEFAULT_SPACE_ID }, @@ -33,6 +37,8 @@ const createTestCases = (spaceId: string) => { { ...CASES.SPACE_1_AND_SPACE_2, namespaces, ...fail404(spaceId === DEFAULT_SPACE_ID) }, { ...CASES.ALL_SPACES, namespaces }, { ...CASES.DOES_NOT_EXIST, namespaces, ...fail404() }, + // Test case to check adding all spaces ("*") to a saved object + { ...CASES.EACH_SPACE, namespaces: ['*'] }, // Test cases to check adding multiple namespaces to different saved objects that exist in one space // These are non-exhaustive, they only check cases for adding two additional namespaces to a saved object // More permutations are covered in the corresponding spaces_only test suite @@ -57,13 +63,24 @@ const calculateSingleSpaceAuthZ = ( testCases: ReturnType, spaceId: string ) => { - const targetsOtherSpace = testCases.filter( - (x) => !x.namespaces.includes(spaceId) || x.namespaces.length > 1 - ); - const tmp = testCases.filter((x) => !targetsOtherSpace.includes(x)); // doesn't target other space - const doesntExistInThisSpace = tmp.filter((x) => !x.existingNamespaces.includes(spaceId)); - const existsInThisSpace = tmp.filter((x) => x.existingNamespaces.includes(spaceId)); - return { targetsOtherSpace, doesntExistInThisSpace, existsInThisSpace }; + const targetsAllSpaces: ShareAddTestCase[] = []; + const targetsOtherSpace: ShareAddTestCase[] = []; + const doesntExistInThisSpace: ShareAddTestCase[] = []; + const existsInThisSpace: ShareAddTestCase[] = []; + + for (const testCase of testCases) { + const { namespaces, existingNamespaces } = testCase; + if (namespaces.includes('*')) { + targetsAllSpaces.push(testCase); + } else if (!namespaces.includes(spaceId) || namespaces.length > 1) { + targetsOtherSpace.push(testCase); + } else if (!existingNamespaces.includes(spaceId)) { + doesntExistInThisSpace.push(testCase); + } else { + existsInThisSpace.push(testCase); + } + } + return { targetsAllSpaces, targetsOtherSpace, doesntExistInThisSpace, existsInThisSpace }; }; // eslint-disable-next-line import/no-default-export export default function ({ getService }: TestInvoker) { @@ -79,11 +96,13 @@ export default function ({ getService }: TestInvoker) { return { unauthorized: createTestDefinitions(testCases, true, { fail403Param: 'create' }), authorizedInSpace: [ + createTestDefinitions(thisSpace.targetsAllSpaces, true, { fail403Param: 'create' }), createTestDefinitions(thisSpace.targetsOtherSpace, true, { fail403Param: 'create' }), createTestDefinitions(thisSpace.doesntExistInThisSpace, false), createTestDefinitions(thisSpace.existsInThisSpace, false), ].flat(), authorizedInOtherSpace: [ + createTestDefinitions(thisSpace.targetsAllSpaces, true, { fail403Param: 'create' }), createTestDefinitions(otherSpace.targetsOtherSpace, true, { fail403Param: 'create' }), // If the preflight GET request fails, it will return a 404 error; users who are authorized to create saved objects in the target // space(s) but are not authorized to update saved objects in this space will see a 403 error instead of 404. This is a safeguard to diff --git a/x-pack/test/spaces_api_integration/security_and_spaces/apis/share_remove.ts b/x-pack/test/spaces_api_integration/security_and_spaces/apis/share_remove.ts index 4b120a71213b756..34406d3258aa415 100644 --- a/x-pack/test/spaces_api_integration/security_and_spaces/apis/share_remove.ts +++ b/x-pack/test/spaces_api_integration/security_and_spaces/apis/share_remove.ts @@ -35,16 +35,20 @@ const createTestCases = (spaceId: string) => { { id: CASES.DEFAULT_AND_SPACE_1.id, namespaces, ...fail404(spaceId === SPACE_2_ID) }, { id: CASES.DEFAULT_AND_SPACE_2.id, namespaces, ...fail404(spaceId === SPACE_1_ID) }, { id: CASES.SPACE_1_AND_SPACE_2.id, namespaces, ...fail404(spaceId === DEFAULT_SPACE_ID) }, - { id: CASES.ALL_SPACES.id, namespaces }, + { id: CASES.EACH_SPACE.id, namespaces }, { id: CASES.DOES_NOT_EXIST.id, namespaces, ...fail404() }, ] as ShareRemoveTestCase[]; - // Test cases to check removing all three namespaces from different saved objects that exist in two spaces - // These are non-exhaustive, they only check some cases -- each object will result in a 404, either because - // it never existed in the target namespace, or it was removed in one of the test cases above - // More permutations are covered in the corresponding spaces_only test suite namespaces = [DEFAULT_SPACE_ID, SPACE_1_ID, SPACE_2_ID]; const multipleSpaces = [ + // Test case to check removing all spaces from a saved object that exists in all spaces; + // It fails the second time because the object no longer exists + { ...CASES.ALL_SPACES, namespaces: ['*'] }, + { ...CASES.ALL_SPACES, namespaces: ['*'], ...fail404() }, + // Test cases to check removing all three namespaces from different saved objects that exist in two spaces + // These are non-exhaustive, they only check some cases -- each object will result in a 404, either because + // it never existed in the target namespace, or it was removed in one of the test cases above + // More permutations are covered in the corresponding spaces_only test suite { id: CASES.DEFAULT_AND_SPACE_1.id, namespaces, ...fail404() }, { id: CASES.DEFAULT_AND_SPACE_2.id, namespaces, ...fail404() }, { id: CASES.SPACE_1_AND_SPACE_2.id, namespaces, ...fail404() }, diff --git a/x-pack/test/spaces_api_integration/spaces_only/apis/share_add.ts b/x-pack/test/spaces_api_integration/spaces_only/apis/share_add.ts index 25ba986a12fd887..8b8e449b3c323a5 100644 --- a/x-pack/test/spaces_api_integration/spaces_only/apis/share_add.ts +++ b/x-pack/test/spaces_api_integration/spaces_only/apis/share_add.ts @@ -33,6 +33,7 @@ const createSingleTestCases = (spaceId: string) => { { ...CASES.DEFAULT_AND_SPACE_1, namespaces, ...fail404(spaceId === SPACE_2_ID) }, { ...CASES.DEFAULT_AND_SPACE_2, namespaces, ...fail404(spaceId === SPACE_1_ID) }, { ...CASES.SPACE_1_AND_SPACE_2, namespaces, ...fail404(spaceId === DEFAULT_SPACE_ID) }, + { ...CASES.EACH_SPACE, namespaces }, { ...CASES.ALL_SPACES, namespaces }, { ...CASES.DOES_NOT_EXIST, namespaces, ...fail404() }, ]; @@ -42,14 +43,26 @@ const createSingleTestCases = (spaceId: string) => { * These are non-exhaustive, but they check different permutations of saved objects and spaces to add */ const createMultiTestCases = () => { - const allSpaces = [DEFAULT_SPACE_ID, SPACE_1_ID, SPACE_2_ID]; - let id = CASES.DEFAULT_ONLY.id; - const one = [{ id, namespaces: allSpaces }]; - id = CASES.DEFAULT_AND_SPACE_1.id; - const two = [{ id, namespaces: allSpaces }]; - id = CASES.ALL_SPACES.id; - const three = [{ id, namespaces: allSpaces }]; - return { one, two, three }; + const eachSpace = [DEFAULT_SPACE_ID, SPACE_1_ID, SPACE_2_ID]; + const allSpaces = ['*']; + // for each of the cases below, test adding each space and all spaces to the object + const one = [ + { id: CASES.DEFAULT_ONLY.id, namespaces: eachSpace }, + { id: CASES.DEFAULT_ONLY.id, namespaces: allSpaces }, + ]; + const two = [ + { id: CASES.DEFAULT_AND_SPACE_1.id, namespaces: eachSpace }, + { id: CASES.DEFAULT_AND_SPACE_1.id, namespaces: allSpaces }, + ]; + const three = [ + { id: CASES.EACH_SPACE.id, namespaces: eachSpace }, + { id: CASES.EACH_SPACE.id, namespaces: allSpaces }, + ]; + const four = [ + { id: CASES.ALL_SPACES.id, namespaces: eachSpace }, + { id: CASES.ALL_SPACES.id, namespaces: allSpaces }, + ]; + return { one, two, three, four }; }; // eslint-disable-next-line import/no-default-export @@ -68,6 +81,7 @@ export default function ({ getService }: TestInvoker) { one: createTestDefinitions(testCases.one, false), two: createTestDefinitions(testCases.two, false), three: createTestDefinitions(testCases.three, false), + four: createTestDefinitions(testCases.four, false), }; }; @@ -76,9 +90,10 @@ export default function ({ getService }: TestInvoker) { const tests = createSingleTests(spaceId); addTests(`targeting the ${spaceId} space`, { spaceId, tests }); }); - const { one, two, three } = createMultiTests(); + const { one, two, three, four } = createMultiTests(); addTests('for a saved object in the default space', { tests: one }); addTests('for a saved object in the default and space_1 spaces', { tests: two }); addTests('for a saved object in the default, space_1, and space_2 spaces', { tests: three }); + addTests('for a saved object in all spaces', { tests: four }); }); } diff --git a/x-pack/test/spaces_api_integration/spaces_only/apis/share_remove.ts b/x-pack/test/spaces_api_integration/spaces_only/apis/share_remove.ts index 2c4506b7235339e..bb0e6f858cbab75 100644 --- a/x-pack/test/spaces_api_integration/spaces_only/apis/share_remove.ts +++ b/x-pack/test/spaces_api_integration/spaces_only/apis/share_remove.ts @@ -33,7 +33,7 @@ const createSingleTestCases = (spaceId: string) => { { ...CASES.DEFAULT_AND_SPACE_1, namespaces, ...fail404(spaceId === SPACE_2_ID) }, { ...CASES.DEFAULT_AND_SPACE_2, namespaces, ...fail404(spaceId === SPACE_1_ID) }, { ...CASES.SPACE_1_AND_SPACE_2, namespaces, ...fail404(spaceId === DEFAULT_SPACE_ID) }, - { ...CASES.ALL_SPACES, namespaces }, + { ...CASES.EACH_SPACE, namespaces }, { ...CASES.DOES_NOT_EXIST, namespaces, ...fail404() }, ]; }; @@ -56,7 +56,7 @@ const createMultiTestCases = () => { { id, namespaces: [DEFAULT_SPACE_ID], ...fail404() }, // this object's namespaces no longer contains DEFAULT_SPACE_ID { id, namespaces: [SPACE_1_ID], ...fail404() }, // this object's namespaces does contain SPACE_1_ID ]; - id = CASES.ALL_SPACES.id; + id = CASES.EACH_SPACE.id; const three = [ { id, namespaces: [DEFAULT_SPACE_ID, SPACE_1_ID, nonExistentSpaceId] }, // this saved object will not be found in the context of the current namespace ('default') @@ -64,7 +64,15 @@ const createMultiTestCases = () => { { id, namespaces: [SPACE_1_ID], ...fail404() }, // this object's namespaces no longer contains SPACE_1_ID { id, namespaces: [SPACE_2_ID], ...fail404() }, // this object's namespaces does contain SPACE_2_ID ]; - return { one, two, three }; + id = CASES.ALL_SPACES.id; + const four = [ + { id, namespaces: [DEFAULT_SPACE_ID, SPACE_1_ID, nonExistentSpaceId] }, + // this saved object will still be found in the context of the current namespace ('default') + { id, namespaces: ['*'] }, + // this object no longer exists + { id, namespaces: ['*'], ...fail404() }, + ]; + return { one, two, three, four }; }; // eslint-disable-next-line import/no-default-export @@ -83,6 +91,7 @@ export default function ({ getService }: TestInvoker) { one: createTestDefinitions(testCases.one, false), two: createTestDefinitions(testCases.two, false), three: createTestDefinitions(testCases.three, false), + four: createTestDefinitions(testCases.four, false), }; }; @@ -91,9 +100,10 @@ export default function ({ getService }: TestInvoker) { const tests = createSingleTests(spaceId); addTests(`targeting the ${spaceId} space`, { spaceId, tests }); }); - const { one, two, three } = createMultiTests(); + const { one, two, three, four } = createMultiTests(); addTests('for a saved object in the default space', { tests: one }); addTests('for a saved object in the default and space_1 spaces', { tests: two }); addTests('for a saved object in the default, space_1, and space_2 spaces', { tests: three }); + addTests('for a saved object in all spaces', { tests: four }); }); }