Skip to content

Commit

Permalink
Add integration test for _get_shareable_references
Browse files Browse the repository at this point in the history
  • Loading branch information
jportner committed May 6, 2021
1 parent 4296e5e commit c99e438
Show file tree
Hide file tree
Showing 7 changed files with 474 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,7 @@
"type": "legacy-url-alias",
"updated_at": "2017-09-21T18:51:23.794Z",
"legacy-url-alias": {
"sourceId": "alias-match",
"targetNamespace": "space_1",
"targetType": "resolvetype",
"targetId": "alias-match-newid"
Expand All @@ -561,6 +562,7 @@
"type": "legacy-url-alias",
"updated_at": "2017-09-21T18:51:23.794Z",
"legacy-url-alias": {
"sourceId": "disabled",
"targetNamespace": "space_1",
"targetType": "resolvetype",
"targetId": "alias-match-newid",
Expand Down Expand Up @@ -611,6 +613,7 @@
"type": "legacy-url-alias",
"updated_at": "2017-09-21T18:51:23.794Z",
"legacy-url-alias": {
"sourceId": "conflict",
"targetNamespace": "space_1",
"targetType": "resolvetype",
"targetId": "conflict-newid"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,9 @@
},
"type": "sharedtype",
"namespaces": ["default"],
"references": [
{ "type": "sharedtype", "id": "each_space", "name": "refname" }
],
"updated_at": "2017-09-21T18:59:16.270Z"
},
"type": "doc"
Expand All @@ -405,12 +408,33 @@
},
"type": "sharedtype",
"namespaces": ["space_1"],
"references": [
{ "type": "sharedtype", "id": "each_space", "name": "refname" }
],
"updated_at": "2017-09-21T18:59:16.270Z"
},
"type": "doc"
}
}

{
"type": "doc",
"value": {
"id": "legacy-url-alias:space_1:sharedtype:default_only",
"index": ".kibana",
"source": {
"type": "legacy-url-alias",
"updated_at": "2017-09-21T18:51:23.794Z",
"legacy-url-alias": {
"sourceId": "default_only",
"targetNamespace": "space_1",
"targetType": "sharedtype",
"targetId": "space_1_only"
}
}
}
}

{
"type": "doc",
"value": {
Expand All @@ -422,12 +446,33 @@
},
"type": "sharedtype",
"namespaces": ["space_2"],
"references": [
{ "type": "sharedtype", "id": "each_space", "name": "refname" }
],
"updated_at": "2017-09-21T18:59:16.270Z"
},
"type": "doc"
}
}

{
"type": "doc",
"value": {
"id": "legacy-url-alias:space_2:sharedtype:default_only",
"index": ".kibana",
"source": {
"type": "legacy-url-alias",
"updated_at": "2017-09-21T18:51:23.794Z",
"legacy-url-alias": {
"sourceId": "default_only",
"targetNamespace": "space_2",
"targetType": "sharedtype",
"targetId": "space_2_only"
}
}
}
}

{
"type": "doc",
"value": {
Expand Down Expand Up @@ -490,6 +535,12 @@
},
"type": "sharedtype",
"namespaces": ["default", "space_1", "space_2"],
"references": [
{ "type": "sharedtype", "id": "default_only", "name": "refname" },
{ "type": "sharedtype", "id": "space_1_only", "name": "refname" },
{ "type": "sharedtype", "id": "space_2_only", "name": "refname" },
{ "type": "sharedtype", "id": "all_spaces", "name": "refname" }
],
"updated_at": "2017-09-21T18:59:16.270Z"
},
"type": "doc"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,270 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import expect from '@kbn/expect';
import { deepFreeze } from '@kbn/std';
import { SuperTest } from 'supertest';
import {
SavedObjectsCollectMultiNamespaceReferencesResponse,
SavedObjectReferenceWithContext,
} from '../../../../../src/core/server';
import { MULTI_NAMESPACE_SAVED_OBJECT_TEST_CASES as CASES } from '../lib/saved_object_test_cases';
import { SPACES } from '../lib/spaces';
import {
expectResponses,
getUrlPrefix,
} from '../../../saved_object_api_integration/common/lib/saved_object_test_utils';
import {
ExpectResponseBody,
TestDefinition,
TestSuite,
} from '../../../saved_object_api_integration/common/lib/types';

export interface GetShareableReferencesTestDefinition extends TestDefinition {
request: {
objects: Array<{ type: string; id: string }>;
};
}
export type GetShareableReferencesTestSuite = TestSuite<GetShareableReferencesTestDefinition>;
export interface GetShareableReferencesTestCase {
objects: Array<{ type: string; id: string }>;
expectedResults: SavedObjectReferenceWithContext[];
}

const {
DEFAULT: { spaceId: DEFAULT_SPACE_ID },
SPACE_1: { spaceId: SPACE_1_ID },
SPACE_2: { spaceId: SPACE_2_ID },
} = SPACES;
export const TEST_CASE_OBJECTS: Record<string, { type: string; id: string }> = deepFreeze({
SHAREABLE_TYPE: { type: 'sharedtype', id: CASES.EACH_SPACE.id }, // contains references to four other objects
SHAREABLE_TYPE_DOES_NOT_EXIST: { type: 'sharedtype', id: 'does-not-exist' },
NON_SHAREABLE_TYPE: { type: 'dashboard', id: 'my_dashboard' }, // one of these exists in each space
});
// Expected results for each space are defined here since they are used in multiple test suites
export const EXPECTED_RESULTS: Record<string, SavedObjectReferenceWithContext[]> = {
IN_DEFAULT_SPACE: [
{
...TEST_CASE_OBJECTS.SHAREABLE_TYPE,
spaces: [DEFAULT_SPACE_ID, SPACE_1_ID, SPACE_2_ID],
inboundReferences: [{ type: 'sharedtype', id: CASES.DEFAULT_ONLY.id, name: 'refname' }], // only reflects inbound reference that exist in the default space
},
{
...TEST_CASE_OBJECTS.SHAREABLE_TYPE_DOES_NOT_EXIST,
spaces: [],
inboundReferences: [],
isMissing: true, // doesn't exist anywhere
},
{ ...TEST_CASE_OBJECTS.NON_SHAREABLE_TYPE, spaces: [], inboundReferences: [] }, // not missing, but has an empty spaces array because it is not a shareable type
{
type: 'sharedtype',
id: CASES.DEFAULT_ONLY.id,
spaces: [DEFAULT_SPACE_ID],
inboundReferences: [{ ...TEST_CASE_OBJECTS.SHAREABLE_TYPE, name: 'refname' }],
spacesWithMatchingAliases: [SPACE_1_ID, SPACE_2_ID], // aliases with a matching targetType and sourceId exist in two other spaces
},
{
type: 'sharedtype',
id: CASES.SPACE_1_ONLY.id,
spaces: [],
inboundReferences: [{ ...TEST_CASE_OBJECTS.SHAREABLE_TYPE, name: 'refname' }],
isMissing: true, // doesn't exist in the default space
},
{
type: 'sharedtype',
id: CASES.SPACE_2_ONLY.id,
spaces: [],
inboundReferences: [{ ...TEST_CASE_OBJECTS.SHAREABLE_TYPE, name: 'refname' }],
isMissing: true, // doesn't exist in the default space
},
{
type: 'sharedtype',
id: CASES.ALL_SPACES.id,
spaces: ['*'],
inboundReferences: [{ ...TEST_CASE_OBJECTS.SHAREABLE_TYPE, name: 'refname' }],
},
],
IN_SPACE_1: [
{
...TEST_CASE_OBJECTS.SHAREABLE_TYPE,
spaces: [DEFAULT_SPACE_ID, SPACE_1_ID, SPACE_2_ID],
inboundReferences: [{ type: 'sharedtype', id: CASES.SPACE_1_ONLY.id, name: 'refname' }], // only reflects inbound reference that exist in space 1
},
{
...TEST_CASE_OBJECTS.SHAREABLE_TYPE_DOES_NOT_EXIST,
spaces: [],
inboundReferences: [],
isMissing: true, // doesn't exist anywhere
},
{ ...TEST_CASE_OBJECTS.NON_SHAREABLE_TYPE, spaces: [], inboundReferences: [] }, // not missing, but has an empty spaces array because it is not a shareable type
{
type: 'sharedtype',
id: CASES.DEFAULT_ONLY.id,
spaces: [],
inboundReferences: [{ ...TEST_CASE_OBJECTS.SHAREABLE_TYPE, name: 'refname' }],
isMissing: true, // doesn't exist in space 1
},
{
type: 'sharedtype',
id: CASES.SPACE_1_ONLY.id,
spaces: [SPACE_1_ID],
inboundReferences: [{ ...TEST_CASE_OBJECTS.SHAREABLE_TYPE, name: 'refname' }],
},
{
type: 'sharedtype',
id: CASES.SPACE_2_ONLY.id,
spaces: [],
inboundReferences: [{ ...TEST_CASE_OBJECTS.SHAREABLE_TYPE, name: 'refname' }],
isMissing: true, // doesn't exist in space 1
},
{
type: 'sharedtype',
id: CASES.ALL_SPACES.id,
spaces: ['*'],
inboundReferences: [{ ...TEST_CASE_OBJECTS.SHAREABLE_TYPE, name: 'refname' }],
},
],
IN_SPACE_2: [
{
...TEST_CASE_OBJECTS.SHAREABLE_TYPE,
spaces: [DEFAULT_SPACE_ID, SPACE_1_ID, SPACE_2_ID],
inboundReferences: [{ type: 'sharedtype', id: CASES.SPACE_2_ONLY.id, name: 'refname' }], // only reflects inbound reference that exist in space 2
},
{
...TEST_CASE_OBJECTS.SHAREABLE_TYPE_DOES_NOT_EXIST,
spaces: [],
inboundReferences: [],
isMissing: true, // doesn't exist anywhere
},
{ ...TEST_CASE_OBJECTS.NON_SHAREABLE_TYPE, spaces: [], inboundReferences: [] }, // not missing, but has an empty spaces array because it is not a shareable type
{
type: 'sharedtype',
id: CASES.DEFAULT_ONLY.id,
spaces: [],
inboundReferences: [{ ...TEST_CASE_OBJECTS.SHAREABLE_TYPE, name: 'refname' }],
isMissing: true, // doesn't exist in space 2
},
{
type: 'sharedtype',
id: CASES.SPACE_1_ONLY.id,
spaces: [],
inboundReferences: [{ ...TEST_CASE_OBJECTS.SHAREABLE_TYPE, name: 'refname' }],
isMissing: true, // doesn't exist in space 2
},
{
type: 'sharedtype',
id: CASES.SPACE_2_ONLY.id,
spaces: [SPACE_2_ID],
inboundReferences: [{ ...TEST_CASE_OBJECTS.SHAREABLE_TYPE, name: 'refname' }],
},
{
type: 'sharedtype',
id: CASES.ALL_SPACES.id,
spaces: ['*'],
inboundReferences: [{ ...TEST_CASE_OBJECTS.SHAREABLE_TYPE, name: 'refname' }],
},
],
};

const createRequest = ({ objects }: GetShareableReferencesTestCase) => ({ objects });
const getTestTitle = ({ objects }: GetShareableReferencesTestCase) => {
const objStr = objects.map(({ type, id }) => `${type}:${id}`).join(',');
return `{objects: [${objStr}]}`;
};
const getRedactedSpaces = (authorizedSpace: string | undefined, spaces: string[]) => {
if (!authorizedSpace) {
return spaces; // if authorizedSpace is undefined, we should not redact any spaces
}
const redactedSpaces = spaces.map((x) => (x !== authorizedSpace && x !== '*' ? '?' : x));
return redactedSpaces.sort((a, b) => (a === '?' ? 1 : b === '?' ? -1 : 0)); // unknown spaces are always at the end of the array
};

export function getShareableReferencesTestSuiteFactory(esArchiver: any, supertest: SuperTest<any>) {
const expectForbidden = expectResponses.forbiddenTypes('share_to_space');
const expectResponseBody = (
testCase: GetShareableReferencesTestCase,
statusCode: 200 | 403,
authorizedSpace?: string
): ExpectResponseBody => async (response: Record<string, any>) => {
if (statusCode === 403) {
const types = testCase.objects.map((x) => x.type);
await expectForbidden(types)(response);
} else {
const { expectedResults } = testCase;
const apiResponse = response.body as SavedObjectsCollectMultiNamespaceReferencesResponse;
expect(apiResponse.objects).to.have.length(expectedResults.length);
expectedResults.forEach((expectedResult, i) => {
const { spaces, spacesWithMatchingAliases } = expectedResult;
const expectedSpaces = getRedactedSpaces(authorizedSpace, spaces);
const expectedSpacesWithMatchingAliases =
spacesWithMatchingAliases &&
getRedactedSpaces(authorizedSpace, spacesWithMatchingAliases);
const expected = {
...expectedResult,
spaces: expectedSpaces,
...(expectedSpacesWithMatchingAliases && {
spacesWithMatchingAliases: expectedSpacesWithMatchingAliases,
}),
};
expect(apiResponse.objects[i]).to.eql(expected);
});
}
};
const createTestDefinitions = (
testCases: GetShareableReferencesTestCase | GetShareableReferencesTestCase[],
forbidden: boolean,
options: {
/** If defined, will expect results to have redacted any spaces that do not match this one. */
authorizedSpace?: string;
responseBodyOverride?: ExpectResponseBody;
} = {}
): GetShareableReferencesTestDefinition[] => {
const cases = Array.isArray(testCases) ? testCases : [testCases];
const responseStatusCode = forbidden ? 403 : 200;
return cases.map((x) => ({
title: getTestTitle(x),
responseStatusCode,
request: createRequest(x),
responseBody:
options?.responseBodyOverride ||
expectResponseBody(x, responseStatusCode, options.authorizedSpace),
}));
};

const makeGetShareableReferencesTest = (describeFn: Mocha.SuiteFunction) => (
description: string,
definition: GetShareableReferencesTestSuite
) => {
const { user, spaceId = SPACES.DEFAULT.spaceId, tests } = definition;

describeFn(description, () => {
before(() => esArchiver.load('saved_objects/spaces'));
after(() => esArchiver.unload('saved_objects/spaces'));

for (const test of tests) {
it(`should return ${test.responseStatusCode} ${test.title}`, async () => {
const requestBody = test.request;
await supertest
.post(`${getUrlPrefix(spaceId)}/api/spaces/_get_shareable_references`)
.auth(user?.username, user?.password)
.send(requestBody)
.expect(test.responseStatusCode)
.then(test.responseBody);
});
}
});
};

const addTests = makeGetShareableReferencesTest(describe);
// @ts-ignore
addTests.only = makeGetShareableReferencesTest(describe.only);

return {
addTests,
createTestDefinitions,
};
}
Loading

0 comments on commit c99e438

Please sign in to comment.