Skip to content

Commit

Permalink
feat: add unit test
Browse files Browse the repository at this point in the history
Signed-off-by: SuZhou-Joe <[email protected]>
  • Loading branch information
SuZhou-Joe committed Mar 22, 2024
1 parent 639ede0 commit 1325e2a
Show file tree
Hide file tree
Showing 6 changed files with 221 additions and 26 deletions.
19 changes: 19 additions & 0 deletions src/core/server/utils/workspace.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import { httpServerMock } from '../mocks';
import { getWorkspaceState, updateWorkspaceState } from './workspace';

describe('updateWorkspaceState', () => {
it('update with payload', () => {
const requestMock = httpServerMock.createOpenSearchDashboardsRequest();
updateWorkspaceState(requestMock, {
id: 'foo',
});
expect(getWorkspaceState(requestMock)).toEqual({
id: 'foo',
});
});
});
8 changes: 4 additions & 4 deletions src/core/server/utils/workspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ export const updateWorkspaceState = (
request: OpenSearchDashboardsRequest,
payload: PluginsStates['workspace']
) => {
if (!payload) {
return undefined;
}

const rawRequest = ensureRawRequest(request);

if (!rawRequest.plugins) {
rawRequest.plugins = {};
}

if (!rawRequest.plugins.workspace) {
rawRequest.plugins.workspace = {};
}
Expand Down
65 changes: 64 additions & 1 deletion src/plugins/workspace/server/plugin.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
* SPDX-License-Identifier: Apache-2.0
*/

import { coreMock } from '../../../core/server/mocks';
import { OnPreRoutingHandler } from 'src/core/server';
import { coreMock, httpServerMock } from '../../../core/server/mocks';
import { WorkspacePlugin } from './plugin';
import { getWorkspaceState } from '../../../core/server/utils';

describe('Workspace server plugin', () => {
it('#setup', async () => {
Expand All @@ -27,5 +29,66 @@ describe('Workspace server plugin', () => {
},
}
`);
expect(setupMock.savedObjects.addClientWrapper).toBeCalledTimes(3);
});

it('#proxyWorkspaceTrafficToRealHandler', async () => {
const setupMock = coreMock.createSetup();
const initializerContextConfigMock = coreMock.createPluginInitializerContext({
enabled: true,
permission: {
enabled: true,
},
});
let onPreRoutingFn: OnPreRoutingHandler = () => httpServerMock.createResponseFactory().ok();
setupMock.http.registerOnPreRouting.mockImplementation((fn) => {
onPreRoutingFn = fn;
return fn;
});
const workspacePlugin = new WorkspacePlugin(initializerContextConfigMock);
await workspacePlugin.setup(setupMock);
const toolKitMock = httpServerMock.createToolkit();

const requestWithWorkspaceInUrl = httpServerMock.createOpenSearchDashboardsRequest({
path: '/w/foo/app',
});
onPreRoutingFn(requestWithWorkspaceInUrl, httpServerMock.createResponseFactory(), toolKitMock);
expect(toolKitMock.rewriteUrl).toBeCalledWith('http://localhost/app');
expect(toolKitMock.next).toBeCalledTimes(0);
expect(getWorkspaceState(requestWithWorkspaceInUrl)).toEqual({
id: 'foo',
});

const requestWithoutWorkspaceInUrl = httpServerMock.createOpenSearchDashboardsRequest({
path: '/app',
});
onPreRoutingFn(
requestWithoutWorkspaceInUrl,
httpServerMock.createResponseFactory(),
toolKitMock
);
expect(toolKitMock.next).toBeCalledTimes(1);
});

it('#start', async () => {
const setupMock = coreMock.createSetup();
const startMock = coreMock.createStart();
const initializerContextConfigMock = coreMock.createPluginInitializerContext({
enabled: true,
permission: {
enabled: true,
},
});

const workspacePlugin = new WorkspacePlugin(initializerContextConfigMock);
await workspacePlugin.setup(setupMock);
await workspacePlugin.start(startMock);
expect(startMock.savedObjects.createSerializer).toBeCalledTimes(1);
});

it('#stop', () => {
const initializerContextConfigMock = coreMock.createPluginInitializerContext();
const workspacePlugin = new WorkspacePlugin(initializerContextConfigMock);
workspacePlugin.stop();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import { updateWorkspaceState } from '../../../../core/server/utils';
import { SavedObject } from '../../../../core/public';
import { httpServerMock, savedObjectsClientMock, coreMock } from '../../../../core/server/mocks';
import { WorkspaceIdConsumerWrapper } from './workspace_id_consumer_wrapper';

describe('WorkspaceIdConsumerWrapper', () => {
const requestHandlerContext = coreMock.createRequestHandlerContext();
const wrapperInstance = new WorkspaceIdConsumerWrapper();
const mockedClient = savedObjectsClientMock.create();
const workspaceEnabledMockRequest = httpServerMock.createOpenSearchDashboardsRequest();
updateWorkspaceState(workspaceEnabledMockRequest, {
id: 'foo',
});
const wrapperClient = wrapperInstance.wrapperFactory({
client: mockedClient,
typeRegistry: requestHandlerContext.savedObjects.typeRegistry,
request: workspaceEnabledMockRequest,
});
const getSavedObject = (savedObject: Partial<SavedObject>) => {
const payload: SavedObject = {
references: [],
id: '',
type: 'dashboard',
attributes: {},
...savedObject,
};

return payload;
};
describe('create', () => {
beforeEach(() => {
mockedClient.create.mockClear();
});
it(`Should add workspaces parameters when create`, async () => {
await wrapperClient.create('dashboard', {
name: 'foo',
});

expect(mockedClient.create).toBeCalledWith(
expect.anything(),
expect.anything(),
expect.objectContaining({
workspaces: ['foo'],
})
);
});

it(`Should use options.workspaces there is workspaces inside options`, async () => {
await wrapperClient.create(
'dashboard',
{
name: 'foo',
},
{
id: 'dashboard:foo',
overwrite: true,
workspaces: undefined,
}
);

expect(mockedClient.create.mock.calls[0][2]?.hasOwnProperty('workspaces')).toEqual(false);
});
});

describe('bulkCreate', () => {
beforeEach(() => {
mockedClient.bulkCreate.mockClear();
});
it(`Should add workspaces parameters when bulk create`, async () => {
await wrapperClient.bulkCreate([
getSavedObject({
id: 'foo',
}),
]);

expect(mockedClient.bulkCreate).toBeCalledWith(
[{ attributes: {}, id: 'foo', references: [], type: 'dashboard' }],
{
workspaces: ['foo'],
}
);
});
});

describe('checkConflict', () => {
beforeEach(() => {
mockedClient.checkConflicts.mockClear();
});

it(`Should add workspaces parameters when checkConflict`, async () => {
await wrapperClient.checkConflicts([]);
expect(mockedClient.checkConflicts).toBeCalledWith([], {
workspaces: ['foo'],
});
});
});

describe('find', () => {
beforeEach(() => {
mockedClient.find.mockClear();
});

it(`Should add workspaces parameters when find`, async () => {
await wrapperClient.find({
type: 'dashboard',
});
expect(mockedClient.find).toBeCalledWith({
type: 'dashboard',
workspaces: ['foo'],
});
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import {
SavedObjectsCheckConflictsObject,
OpenSearchDashboardsRequest,
SavedObjectsFindOptions,
WORKSPACE_TYPE,
} from '../../../../core/server';

type WorkspaceOptions =
Expand All @@ -22,26 +21,16 @@ type WorkspaceOptions =
| undefined;

export class WorkspaceIdConsumerWrapper {
private typeRelatedToWorkspace(type: string | string[]): boolean {
if (Array.isArray(type)) {
return type.some((item) => item === WORKSPACE_TYPE);
}

return type === WORKSPACE_TYPE;
}
private formatWorkspaceIdParams<T extends WorkspaceOptions>(
request: OpenSearchDashboardsRequest,
options: T
options?: T
): T {
if (!options) {
return options;
}
const { workspaces, ...others } = options;
const { workspaces, ...others } = options || {};
const workspaceState = getWorkspaceState(request);
const workspaceIdParsedFromRequest = workspaceState?.id;
const workspaceIdsInUserOptions = options.workspaces;
const workspaceIdsInUserOptions = options?.workspaces;
let finalWorkspaces: string[] = [];
if (options.hasOwnProperty('workspaces')) {
if (options?.hasOwnProperty('workspaces')) {
finalWorkspaces = workspaceIdsInUserOptions || [];
} else if (workspaceIdParsedFromRequest) {
finalWorkspaces = [workspaceIdParsedFromRequest];
Expand Down Expand Up @@ -79,11 +68,7 @@ export class WorkspaceIdConsumerWrapper {
),
delete: wrapperOptions.client.delete,
find: (options: SavedObjectsFindOptions) =>
wrapperOptions.client.find(
this.typeRelatedToWorkspace(options.type)
? options
: this.formatWorkspaceIdParams(wrapperOptions.request, options)
),
wrapperOptions.client.find(this.formatWorkspaceIdParams(wrapperOptions.request, options)),
bulkGet: wrapperOptions.client.bulkGet,
get: wrapperOptions.client.get,
update: wrapperOptions.client.update,
Expand Down
12 changes: 11 additions & 1 deletion src/plugins/workspace/server/workspace_client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ import {
import { IWorkspaceClientImpl, WorkspaceFindOptions, IResponse, IRequestDetail } from './types';
import { workspace } from './saved_objects';
import { generateRandomId } from './utils';
import { WORKSPACE_SAVED_OBJECTS_CLIENT_WRAPPER_ID } from '../common/constants';
import {
WORKSPACE_ID_CONSUMER_WRAPPER_ID,
WORKSPACE_SAVED_OBJECTS_CLIENT_WRAPPER_ID,
} from '../common/constants';

const WORKSPACE_ID_SIZE = 6;

Expand Down Expand Up @@ -56,6 +59,13 @@ export class WorkspaceClient implements IWorkspaceClientImpl {
requestDetail: IRequestDetail
): SavedObjectsClientContract {
return this.savedObjects?.getScopedClient(requestDetail.request, {
/**
* workspace object does not have workspaces field
* so need to bypass the consumer wrapper
* or it will append workspaces into the options.workspaces
* when list all the workspaces inside a workspace
*/
excludedWrappers: [WORKSPACE_ID_CONSUMER_WRAPPER_ID],
includedHiddenTypes: [WORKSPACE_TYPE],
}) as SavedObjectsClientContract;
}
Expand Down

0 comments on commit 1325e2a

Please sign in to comment.