Skip to content

Commit

Permalink
[Dashboard] Make Dashboard Saved Objects multiple-isolated (#115817)
Browse files Browse the repository at this point in the history
* Make Dashboard SO multiple-isolated

* Fix integration tests

* Fix Saved Objects API Integration Tests

* Fix more tests

* Fix even more tests

Co-authored-by: Joe Portner <[email protected]>
Co-authored-by: Kibana Machine <[email protected]>
  • Loading branch information
3 people authored Oct 25, 2021
1 parent 6d6cb5c commit edc43c0
Show file tree
Hide file tree
Showing 12 changed files with 107 additions and 61 deletions.
3 changes: 2 additions & 1 deletion src/plugins/dashboard/server/saved_objects/dashboard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ export const createDashboardSavedObjectType = ({
}): SavedObjectsType => ({
name: 'dashboard',
hidden: false,
namespaceType: 'single',
namespaceType: 'multiple-isolated',
convertToMultiNamespaceTypeVersion: '8.0.0',
management: {
icon: 'dashboardApp',
defaultSearchField: 'title',
Expand Down
2 changes: 1 addition & 1 deletion test/api_integration/apis/saved_objects_management/find.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ export default function ({ getService }: FtrProviderContext) {
path: '/app/dashboards#/view/b70c7ae0-3224-11e8-a572-ffca06da1357',
uiCapabilitiesPath: 'dashboard.show',
},
namespaceType: 'single',
namespaceType: 'multiple-isolated',
});
}));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ export default function ({ getService }: FtrProviderContext) {
path: '/app/dashboards#/view/b70c7ae0-3224-11e8-a572-ffca06da1357',
uiCapabilitiesPath: 'dashboard.show',
},
namespaceType: 'single',
namespaceType: 'multiple-isolated',
hiddenType: false,
},
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@
"uiStateJSON": "{}",
"version": 1
},
"namespaces": ["default"],
"type": "dashboard",
"updated_at": "2017-09-21T18:57:40.826Z"
},
Expand Down Expand Up @@ -205,7 +206,7 @@
{
"type": "doc",
"value": {
"id": "space_1:dashboard:space1-dashboard-id",
"id": "dashboard:space1-dashboard-id",
"index": ".kibana",
"source": {
"dashboard": {
Expand All @@ -228,7 +229,7 @@
"uiStateJSON": "{}",
"version": 1
},
"namespace": "space_1",
"namespaces": ["space_1"],
"type": "dashboard",
"updated_at": "2017-09-21T18:57:40.826Z"
},
Expand Down Expand Up @@ -300,7 +301,7 @@
{
"type": "doc",
"value": {
"id": "space_2:dashboard:space2-dashboard-id",
"id": "dashboard:space2-dashboard-id",
"index": ".kibana",
"source": {
"dashboard": {
Expand All @@ -323,7 +324,7 @@
"uiStateJSON": "{}",
"version": 1
},
"namespace": "space_2",
"namespaces": ["space_2"],
"type": "dashboard",
"updated_at": "2017-09-21T18:57:40.826Z"
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export const TEST_CASES: Record<string, ImportTestCase> = Object.freeze({
expectedNewId: `${CID}3`,
}),
CONFLICT_4_OBJ: Object.freeze({ type: 'sharedtype', id: `${CID}4`, expectedNewId: `${CID}4a` }),
NEW_SINGLE_NAMESPACE_OBJ: Object.freeze({ type: 'dashboard', id: 'new-dashboard-id' }),
NEW_SINGLE_NAMESPACE_OBJ: Object.freeze({ type: 'isolatedtype', id: 'new-isolatedtype-id' }),
NEW_MULTI_NAMESPACE_OBJ: Object.freeze({ type: 'sharedtype', id: 'new-sharedtype-id' }),
NEW_NAMESPACE_AGNOSTIC_OBJ: Object.freeze({ type: 'globaltype', id: 'new-globaltype-id' }),
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,6 @@ export default function ({ getService }: FtrProviderContext) {
spaceId,
singleRequest,
responseBodyOverride: expectSavedObjectForbidden([
'dashboard',
'globaltype',
'isolatedtype',
'sharedtype',
Expand All @@ -152,11 +151,7 @@ export default function ({ getService }: FtrProviderContext) {
overwrite,
spaceId,
singleRequest,
responseBodyOverride: expectSavedObjectForbidden([
'dashboard',
'globaltype',
'isolatedtype',
]),
responseBodyOverride: expectSavedObjectForbidden(['globaltype', 'isolatedtype']),
}),
createTestDefinitions(group2, true, { overwrite, spaceId, singleRequest }),
createTestDefinitions(group3, true, { overwrite, spaceId, singleRequest }),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,15 +56,11 @@
{
"type": "_doc",
"value": {
"id": "space_2:dashboard:my_dashboard",
"id": "isolatedtype:my_isolated_object",
"index": ".kibana",
"source": {
"dashboard": {
"description": "Space 2",
"title": "This is the second test space"
},
"namespace": "space_2",
"type": "dashboard",
"type": "isolatedtype",
"updated_at": "2017-09-21T18:49:16.270Z"
},
"type": "_doc"
Expand All @@ -74,15 +70,11 @@
{
"type": "_doc",
"value": {
"id": "space_1:dashboard:my_dashboard",
"id": "isolatedtype:my_isolated_object",
"index": ".kibana",
"source": {
"dashboard": {
"description": "Space 1",
"title": "This is the second test space"
},
"namespace": "space_1",
"type": "dashboard",
"type": "isolatedtype",
"updated_at": "2017-09-21T18:49:16.270Z"
},
"type": "_doc"
Expand All @@ -92,14 +84,10 @@
{
"type": "_doc",
"value": {
"id": "dashboard:my_dashboard",
"id": "isolatedtype:my_isolated_object",
"index": ".kibana",
"source": {
"dashboard": {
"description": "Default Space",
"title": "This is the default test space"
},
"type": "dashboard",
"type": "isolatedtype",
"updated_at": "2017-09-21T18:49:16.270Z"
},
"type": "_doc"
Expand All @@ -109,9 +97,10 @@
{
"type": "_doc",
"value": {
"id": "dashboard:cts_dashboard",
"id": "dashboard:cts_dashboard_default",
"index": ".kibana",
"source": {
"originId": "cts_dashboard",
"dashboard": {
"description": "Copy to Space Dashboard from the default space",
"title": "This is the default test space CTS dashboard"
Expand All @@ -130,7 +119,8 @@
"name": "CTS Vis 3"
}],
"type": "dashboard",
"updated_at": "2017-09-21T18:49:16.270Z"
"updated_at": "2017-09-21T18:49:16.270Z",
"namespaces": ["default"]
},
"type": "_doc"
}
Expand Down Expand Up @@ -227,9 +217,10 @@
{
"type": "_doc",
"value": {
"id": "space_1:dashboard:cts_dashboard",
"id": "dashboard:cts_dashboard_space_1",
"index": ".kibana",
"source": {
"originId": "cts_dashboard",
"dashboard": {
"description": "Copy to Space Dashboard from space_1 space",
"title": "This is the space_1 test space CTS dashboard"
Expand All @@ -253,7 +244,7 @@
],
"type": "dashboard",
"updated_at": "2017-09-21T18:49:16.270Z",
"namespace": "space_1"
"namespaces": ["space_1"]
},
"type": "_doc"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,23 @@ export class Plugin {
},
},
});
core.savedObjects.registerType({
name: 'isolatedtype',
hidden: false,
namespaceType: 'single',
management: {
icon: 'beaker',
importableAndExportable: true,
getTitle(obj) {
return obj.attributes.title;
},
},
mappings: {
properties: {
title: { type: 'text' },
},
},
});
}

public start() {
Expand Down
35 changes: 23 additions & 12 deletions x-pack/test/spaces_api_integration/common/suites/copy_to_space.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,8 @@ interface SpaceBucket {
}

const INITIAL_COUNTS: Record<string, Record<string, number>> = {
[DEFAULT_SPACE_ID]: { dashboard: 2, visualization: 3, 'index-pattern': 1 },
space_1: { dashboard: 2, visualization: 3, 'index-pattern': 1 },
space_2: { dashboard: 1 },
[DEFAULT_SPACE_ID]: { dashboard: 1, visualization: 3, 'index-pattern': 1 },
space_1: { dashboard: 1, visualization: 3, 'index-pattern': 1 },
};
const UUID_PATTERN = 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
Expand Down Expand Up @@ -148,18 +147,23 @@ export function copyToSpaceTestSuiteFactory(
(spaceId: string, destination: string, expectedDashboardCount: number) =>
async (resp: TestResponse) => {
const result = resp.body as CopyResponse;

const dashboardDestinationId = result[destination].successResults![0].destinationId;
expect(dashboardDestinationId).to.match(UUID_PATTERN); // this was copied to space 2 and hit an unresolvable conflict, so the object ID was regenerated silently / the destinationId is a UUID

expect(result).to.eql({
[destination]: {
success: true,
successCount: 1,
successResults: [
{
id: 'cts_dashboard',
id: `cts_dashboard_${spaceId}`,
type: 'dashboard',
meta: {
title: `This is the ${spaceId} test space CTS dashboard`,
icon: 'dashboardApp',
},
destinationId: dashboardDestinationId,
},
],
},
Expand All @@ -172,7 +176,7 @@ export function copyToSpaceTestSuiteFactory(
};

const expectNoConflictsWithoutReferencesResult = (spaceId: string = DEFAULT_SPACE_ID) =>
createExpectNoConflictsWithoutReferencesForSpace(spaceId, getDestinationWithoutConflicts(), 2);
createExpectNoConflictsWithoutReferencesForSpace(spaceId, getDestinationWithoutConflicts(), 1);

const expectNoConflictsForNonExistentSpaceResult = (spaceId: string = DEFAULT_SPACE_ID) =>
createExpectNoConflictsWithoutReferencesForSpace(spaceId, 'non_existent_space', 1);
Expand All @@ -191,6 +195,8 @@ export function copyToSpaceTestSuiteFactory(
expect(vis2DestinationId).to.match(UUID_PATTERN); // this was copied to space 2 and hit an unresolvable conflict, so the object ID was regenerated silently / the destinationId is a UUID
const vis3DestinationId = result[destination].successResults![3].destinationId;
expect(vis3DestinationId).to.match(UUID_PATTERN); // this was copied to space 2 and hit an unresolvable conflict, so the object ID was regenerated silently / the destinationId is a UUID
const dashboardDestinationId = result[destination].successResults![4].destinationId;
expect(dashboardDestinationId).to.match(UUID_PATTERN); // this was copied to space 2 and hit an unresolvable conflict, so the object ID was regenerated silently / the destinationId is a UUID

expect(result).to.eql({
[destination]: {
Expand Down Expand Up @@ -225,20 +231,21 @@ export function copyToSpaceTestSuiteFactory(
destinationId: vis3DestinationId,
},
{
id: 'cts_dashboard',
id: `cts_dashboard_${spaceId}`,
type: 'dashboard',
meta: {
icon: 'dashboardApp',
title: `This is the ${spaceId} test space CTS dashboard`,
},
destinationId: dashboardDestinationId,
},
],
},
} as CopyResponse);

// Query ES to ensure that we copied everything we expected
await assertSpaceCounts(destination, {
dashboard: 2,
dashboard: 1,
visualization: 3,
'index-pattern': 1,
});
Expand Down Expand Up @@ -353,21 +360,22 @@ export function copyToSpaceTestSuiteFactory(
destinationId: `cts_vis_3_${destination}`, // this conflicted with another visualization in the destination space because of a shared originId
},
{
id: 'cts_dashboard',
id: `cts_dashboard_${spaceId}`,
type: 'dashboard',
meta: {
icon: 'dashboardApp',
title: `This is the ${spaceId} test space CTS dashboard`,
},
overwrite: true,
destinationId: `cts_dashboard_${destination}`, // this conflicted with another dashboard in the destination space because of a shared originId
},
],
},
} as CopyResponse);

// Query ES to ensure that we copied everything we expected
await assertSpaceCounts(destination, {
dashboard: 2,
dashboard: 1,
visualization: 5,
'index-pattern': 1,
});
Expand Down Expand Up @@ -403,8 +411,11 @@ export function copyToSpaceTestSuiteFactory(
];
const expectedErrors = [
{
error: { type: 'conflict' },
id: 'cts_dashboard',
error: {
type: 'conflict',
destinationId: `cts_dashboard_${destination}`, // this conflicted with another dashboard in the destination space because of a shared originId
},
id: `cts_dashboard_${spaceId}`,
title: `This is the ${spaceId} test space CTS dashboard`,
type: 'dashboard',
meta: {
Expand Down Expand Up @@ -662,7 +673,7 @@ export function copyToSpaceTestSuiteFactory(
)
);

const dashboardObject = { type: 'dashboard', id: 'cts_dashboard' };
const dashboardObject = { type: 'dashboard', id: `cts_dashboard_${spaceId}` };

it(`should return ${tests.noConflictsWithoutReferences.statusCode} when copying to space without conflicts or references`, async () => {
const destination = getDestinationWithoutConflicts();
Expand Down
8 changes: 4 additions & 4 deletions x-pack/test/spaces_api_integration/common/suites/delete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,28 +65,28 @@ export function deleteTestSuiteFactory(
const expectedBuckets = [
{
key: 'default',
doc_count: 8,
doc_count: 7,
countByType: {
doc_count_error_upper_bound: 0,
sum_other_doc_count: 0,
buckets: [
{ key: 'visualization', doc_count: 3 },
{ key: 'dashboard', doc_count: 2 },
{ key: 'space', doc_count: 2 }, // since space objects are namespace-agnostic, they appear in the "default" agg bucket
{ key: 'dashboard', doc_count: 1 },
{ key: 'index-pattern', doc_count: 1 },
// legacy-url-alias objects cannot exist for the default space
],
},
},
{
doc_count: 7,
doc_count: 6,
key: 'space_1',
countByType: {
doc_count_error_upper_bound: 0,
sum_other_doc_count: 0,
buckets: [
{ key: 'visualization', doc_count: 3 },
{ key: 'dashboard', doc_count: 2 },
{ key: 'dashboard', doc_count: 1 },
{ key: 'index-pattern', doc_count: 1 },
{ key: 'legacy-url-alias', doc_count: 1 }, // alias (1)
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ const {
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
NON_SHAREABLE_TYPE: { type: 'isolatedtype', id: 'my_isolated_object' }, // 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[]> = {
Expand Down
Loading

0 comments on commit edc43c0

Please sign in to comment.