Skip to content

Commit

Permalink
[Backport workspace]Patch/first pr (opensearch-project#194) (opensear…
Browse files Browse the repository at this point in the history
…ch-project#196)

* Patch/first pr (opensearch-project#194)

* temp: add unit test

Signed-off-by: SuZhou-Joe <suzhou@amazon.com>

* feat: add function test for workspace CRUD routes

Signed-off-by: SuZhou-Joe <suzhou@amazon.com>

* feat: use saved objects client instead of internal repository

Signed-off-by: SuZhou-Joe <suzhou@amazon.com>

* feat: update CHANGELOG

Signed-off-by: SuZhou-Joe <suzhou@amazon.com>

* feat: exclude permission check wrapper

Signed-off-by: SuZhou-Joe <suzhou@amazon.com>

* feat: add integration test

Signed-off-by: SuZhou-Joe <suzhou@amazon.com>

* feat: add configuration

Signed-off-by: SuZhou-Joe <suzhou@amazon.com>

* feat: enable workspace flag when run workspace related test

Signed-off-by: SuZhou-Joe <suzhou@amazon.com>

---------

Signed-off-by: SuZhou-Joe <suzhou@amazon.com>

* feat: update test

Signed-off-by: SuZhou-Joe <suzhou@amazon.com>

* feat: change to equal 3

Signed-off-by: SuZhou-Joe <suzhou@amazon.com>

* feat: test

Signed-off-by: SuZhou-Joe <suzhou@amazon.com>

* feat: make permissions field optional

Signed-off-by: SuZhou-Joe <suzhou@amazon.com>

* fix: make permissions as optional params

Signed-off-by: SuZhou-Joe <suzhou@amazon.com>

* fix: make permissions params optional

Signed-off-by: SuZhou-Joe <suzhou@amazon.com>

---------

Signed-off-by: SuZhou-Joe <suzhou@amazon.com>
  • Loading branch information
SuZhou-Joe committed Oct 9, 2023
1 parent 8132e14 commit cef4ce7
Show file tree
Hide file tree
Showing 6 changed files with 310 additions and 11 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
- Adds Data explorer framework and implements Discover using it ([#4806](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4806))
- [Theme] Use themes' definitions to render the initial view ([#4936](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4936/))
- [Theme] Make `next` theme the default ([#4854](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4854/))
- [Workspace] Setup workspace skeleton and implement basic CRUD API ([#5075](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/5075/))

### 🐛 Bug Fixes

Expand Down
150 changes: 150 additions & 0 deletions src/plugins/workspace/server/integration_tests/routes.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import { WorkspaceAttribute } from 'src/core/types';
import { omit } from 'lodash';
import * as osdTestServer from '../../../../core/test_helpers/osd_server';
import { WorkspaceRoutePermissionItem } from '../types';
import { WorkspacePermissionMode } from '../../../../core/server';

const testWorkspace: WorkspaceAttribute & {
permissions: WorkspaceRoutePermissionItem;
} = {
id: 'fake_id',
name: 'test_workspace',
description: 'test_workspace_description',
};

describe('workspace service', () => {
let root: ReturnType<typeof osdTestServer.createRoot>;
let opensearchServer: osdTestServer.TestOpenSearchUtils;
beforeAll(async () => {
const { startOpenSearch, startOpenSearchDashboards } = osdTestServer.createTestServers({
adjustTimeout: (t: number) => jest.setTimeout(t),
settings: {
osd: {
workspace: {
enabled: true,
},
},
},
});
opensearchServer = await startOpenSearch();
const startOSDResp = await startOpenSearchDashboards();
root = startOSDResp.root;
}, 30000);
afterAll(async () => {
await root.shutdown();
await opensearchServer.stop();
});
describe('Workspace CRUD apis', () => {
afterEach(async () => {
const listResult = await osdTestServer.request
.post(root, `/api/workspaces/_list`)
.send({
page: 1,
})
.expect(200);
await Promise.all(
listResult.body.result.workspaces.map((item: WorkspaceAttribute) =>
osdTestServer.request.delete(root, `/api/workspaces/${item.id}`).expect(200)
)
);
});
it('create', async () => {
await osdTestServer.request
.post(root, `/api/workspaces`)
.send({
attributes: testWorkspace,
})
.expect(400);

const result: any = await osdTestServer.request
.post(root, `/api/workspaces`)
.send({
attributes: omit(testWorkspace, 'id'),
})
.expect(200);

expect(result.body.success).toEqual(true);
expect(typeof result.body.result.id).toBe('string');
});
it('get', async () => {
const result = await osdTestServer.request
.post(root, `/api/workspaces`)
.send({
attributes: omit(testWorkspace, 'id'),
})
.expect(200);

const getResult = await osdTestServer.request.get(
root,
`/api/workspaces/${result.body.result.id}`
);
expect(getResult.body.result.name).toEqual(testWorkspace.name);
});
it('update', async () => {
const result: any = await osdTestServer.request
.post(root, `/api/workspaces`)
.send({
attributes: omit(testWorkspace, 'id'),
})
.expect(200);

await osdTestServer.request
.put(root, `/api/workspaces/${result.body.result.id}`)
.send({
attributes: {
...omit(testWorkspace, 'id'),
name: 'updated',
},
})
.expect(200);

const getResult = await osdTestServer.request.get(
root,
`/api/workspaces/${result.body.result.id}`
);

expect(getResult.body.success).toEqual(true);
expect(getResult.body.result.name).toEqual('updated');
});
it('delete', async () => {
const result: any = await osdTestServer.request
.post(root, `/api/workspaces`)
.send({
attributes: omit(testWorkspace, 'id'),
})
.expect(200);

await osdTestServer.request
.delete(root, `/api/workspaces/${result.body.result.id}`)
.expect(200);

const getResult = await osdTestServer.request.get(
root,
`/api/workspaces/${result.body.result.id}`
);

expect(getResult.body.success).toEqual(false);
});
it('list', async () => {
await osdTestServer.request
.post(root, `/api/workspaces`)
.send({
attributes: omit(testWorkspace, 'id'),
})
.expect(200);

const listResult = await osdTestServer.request
.post(root, `/api/workspaces/_list`)
.send({
page: 1,
})
.expect(200);
expect(listResult.body.result.total).toEqual(3);
});
});
});
35 changes: 25 additions & 10 deletions src/plugins/workspace/server/routes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,9 @@ const workspaceAttributesSchema = schema.object({
icon: schema.maybe(schema.string()),
reserved: schema.maybe(schema.boolean()),
defaultVISTheme: schema.maybe(schema.string()),
permissions: schema.oneOf([workspacePermission, schema.arrayOf(workspacePermission)]),
permissions: schema.maybe(
schema.oneOf([workspacePermission, schema.arrayOf(workspacePermission)])
),
});

const convertToACL = (
Expand Down Expand Up @@ -126,7 +128,9 @@ export function registerRoutes({
...result.result,
workspaces: result.result.workspaces.map((workspace) => ({
...workspace,
permissions: convertFromACL(workspace.permissions),
...(workspace.permissions
? { permissions: convertFromACL(workspace.permissions) }
: {}),
})),
},
},
Expand Down Expand Up @@ -161,7 +165,9 @@ export function registerRoutes({
...result,
result: {
...result.result,
permissions: convertFromACL(result.result.permissions),
...(result.result.permissions
? { permissions: convertFromACL(result.result.permissions) }
: {}),
},
},
});
Expand All @@ -180,9 +186,13 @@ export function registerRoutes({
const { attributes } = req.body;
const rawRequest = ensureRawRequest(req);
const authInfo = rawRequest?.auth?.credentials?.authInfo as { user_name?: string } | null;
const permissions = Array.isArray(attributes.permissions)
? attributes.permissions
: [attributes.permissions];
const { permissions: permissionsInAttributes, ...others } = attributes;
let permissions: WorkspaceRoutePermissionItem[] = [];
if (permissionsInAttributes) {
permissions = Array.isArray(permissionsInAttributes)
? permissionsInAttributes
: [permissionsInAttributes];
}

if (!!authInfo?.user_name) {
permissions.push({
Expand All @@ -204,8 +214,8 @@ export function registerRoutes({
logger,
},
{
...attributes,
permissions: convertToACL(permissions),
...others,
...(permissions.length ? { permissions: convertToACL(permissions) } : {}),
}
);
return res.ok({ body: result });
Expand All @@ -226,6 +236,11 @@ export function registerRoutes({
router.handleLegacyErrors(async (context, req, res) => {
const { id } = req.params;
const { attributes } = req.body;
const { permissions, ...others } = attributes;
let finalPermissions: WorkspaceRoutePermissionItem[] = [];
if (permissions) {
finalPermissions = Array.isArray(permissions) ? permissions : [permissions];
}

const result = await client.update(
{
Expand All @@ -235,8 +250,8 @@ export function registerRoutes({
},
id,
{
...attributes,
permissions: convertToACL(attributes.permissions),
...others,
...(finalPermissions.length ? { permissions: convertToACL(finalPermissions) } : {}),
}
);
return res.ok({ body: result });
Expand Down
2 changes: 1 addition & 1 deletion src/plugins/workspace/server/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
} from '../../../core/server';

export interface WorkspaceAttributeWithPermission extends WorkspaceAttribute {
permissions: Permissions;
permissions?: Permissions;
}

export interface WorkspaceFindOptions {
Expand Down
1 change: 1 addition & 0 deletions test/api_integration/apis/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,5 +45,6 @@ export default function ({ loadTestFile }) {
loadTestFile(require.resolve('./stats'));
loadTestFile(require.resolve('./ui_metric'));
loadTestFile(require.resolve('./telemetry'));
loadTestFile(require.resolve('./workspace'));
});
}
132 changes: 132 additions & 0 deletions test/api_integration/apis/workspace/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import expect from '@osd/expect';
import { WorkspaceAttribute } from 'opensearch-dashboards/server';
import { omit } from 'lodash';
import { FtrProviderContext } from '../../ftr_provider_context';

const testWorkspace: WorkspaceAttribute = {
id: 'fake_id',
name: 'test_workspace',
description: 'test_workspace_description',
};

export default function ({ getService }: FtrProviderContext) {
const supertest = getService('supertest');

describe('Workspace CRUD apis', () => {
afterEach(async () => {
const listResult = await supertest
.post(`/api/workspaces/_list`)
.send({
page: 1,
})
.set('osd-xsrf', 'opensearch-dashboards')
.expect(200);
await Promise.all(
listResult.body.result.workspaces.map((item: WorkspaceAttribute) =>
supertest
.delete(`/api/workspaces/${item.id}`)
.set('osd-xsrf', 'opensearch-dashboards')
.expect(200)
)
);
});
it('create', async () => {
await supertest
.post(`/api/workspaces`)
.send({
attributes: testWorkspace,
})
.set('osd-xsrf', 'opensearch-dashboards')
.expect(400);

const result: any = await supertest
.post(`/api/workspaces`)
.send({
attributes: omit(testWorkspace, 'id'),
})
.set('osd-xsrf', 'opensearch-dashboards')
.expect(200);

expect(result.body.success).equal(true);
expect(result.body.result.id).to.be.a('string');
});
it('get', async () => {
const result = await supertest
.post(`/api/workspaces`)
.send({
attributes: omit(testWorkspace, 'id'),
})
.set('osd-xsrf', 'opensearch-dashboards')
.expect(200);

const getResult = await supertest.get(`/api/workspaces/${result.body.result.id}`);
expect(getResult.body.result.name).equal(testWorkspace.name);
});
it('update', async () => {
const result: any = await supertest
.post(`/api/workspaces`)
.send({
attributes: omit(testWorkspace, 'id'),
})
.set('osd-xsrf', 'opensearch-dashboards')
.expect(200);

await supertest
.put(`/api/workspaces/${result.body.result.id}`)
.send({
attributes: {
...omit(testWorkspace, 'id'),
name: 'updated',
},
})
.set('osd-xsrf', 'opensearch-dashboards')
.expect(200);

const getResult = await supertest.get(`/api/workspaces/${result.body.result.id}`);

expect(getResult.body.success).equal(true);
expect(getResult.body.result.name).equal('updated');
});
it('delete', async () => {
const result: any = await supertest
.post(`/api/workspaces`)
.send({
attributes: omit(testWorkspace, 'id'),
})
.set('osd-xsrf', 'opensearch-dashboards')
.expect(200);

await supertest
.delete(`/api/workspaces/${result.body.result.id}`)
.set('osd-xsrf', 'opensearch-dashboards')
.expect(200);

const getResult = await supertest.get(`/api/workspaces/${result.body.result.id}`);

expect(getResult.body.success).equal(false);
});
it('list', async () => {
await supertest
.post(`/api/workspaces`)
.send({
attributes: omit(testWorkspace, 'id'),
})
.set('osd-xsrf', 'opensearch-dashboards')
.expect(200);

const listResult = await supertest
.post(`/api/workspaces/_list`)
.send({
page: 1,
})
.set('osd-xsrf', 'opensearch-dashboards')
.expect(200);
expect(listResult.body.result.total).equal(1);
});
}).tags('is:workspace');
}

0 comments on commit cef4ce7

Please sign in to comment.