Skip to content

Commit

Permalink
add UT
Browse files Browse the repository at this point in the history
Signed-off-by: Su <szhongna@amazon.com>
  • Loading branch information
zhongnansu committed Aug 26, 2022
1 parent 5c212bd commit 145ec29
Show file tree
Hide file tree
Showing 14 changed files with 299 additions and 130 deletions.
8 changes: 5 additions & 3 deletions src/plugins/data/server/index_patterns/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,10 +155,12 @@ export function registerRoutes(http: HttpServiceSetup) {
);
}

const decideClient = async (context: RequestHandlerContext, request: any) => {
const decideClient = async (
context: RequestHandlerContext,
request: any
): Promise<LegacyAPICaller> => {
const dataSourceId = request.query.data_source;
return dataSourceId
? ((await context.dataSource.opensearch.legacy.getClient(dataSourceId)
.callAPI) as LegacyAPICaller)
? (context.dataSource.opensearch.legacy.getClient(dataSourceId).callAPI as LegacyAPICaller)
: context.core.opensearch.legacy.client.callAsCurrentUser;
};
4 changes: 2 additions & 2 deletions src/plugins/data_source/server/client/client_pool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ export interface OpenSearchClientPoolSetup {
}

/**
* OpenSearch client pool.
* OpenSearch client pool for data source.
*
* This client pool uses an LRU cache to manage OpenSearch Js client objects.
* It reuse TPC connections for each OpenSearch endpoint.
*/
export class OpenSearchClientPool {
// LRU cache
// key: data source endpoint, prefixed with identifier for legacy
// key: data source endpoint
// value: OpenSearch client object | Legacy client object
private cache?: LRUCache<string, Client | LegacyClient>;
private isClosed = false;
Expand Down
38 changes: 16 additions & 22 deletions src/plugins/data_source/server/client/configure_client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@ import { ClientOptions } from '@opensearch-project/opensearch';
// eslint-disable-next-line @osd/eslint/no-restricted-paths
import { opensearchClientMock } from '../../../../core/server/opensearch/client/mocks';
import { CryptographyClient } from '../cryptography';
import { DataSourceClientParams } from '../types';

const DATA_SOURCE_ID = 'a54b76ec86771ee865a0f74a305dfff8';
const CREDENETIAL_ID = 'a54dsaadasfasfwe22d23d23d2453df3';
const cryptoClient = new CryptographyClient('test', 'test', new Array(32).fill(0));
const cryptographyClient = new CryptographyClient('test', 'test', new Array(32).fill(0));

// TODO: improve UT
describe('configureClient', () => {
Expand All @@ -33,6 +34,7 @@ describe('configureClient', () => {
let clientOptions: ClientOptions;
let dataSourceAttr: DataSourceAttributes;
let dsClient: ReturnType<typeof opensearchClientMock.createInternalClient>;
let dataSourceClientParams: DataSourceClientParams;

beforeEach(() => {
dsClient = opensearchClientMock.createInternalClient();
Expand Down Expand Up @@ -87,9 +89,13 @@ describe('configureClient', () => {
references: [],
});

ClientMock.mockImplementation(() => {
return dsClient;
});
dataSourceClientParams = {
dataSourceId: DATA_SOURCE_ID,
savedObjects: savedObjectsMock,
cryptographyClient,
};

ClientMock.mockImplementation(() => dsClient);
});

afterEach(() => {
Expand All @@ -106,14 +112,7 @@ describe('configureClient', () => {

parseClientOptionsMock.mockReturnValue(clientOptions);

const client = await configureClient(
DATA_SOURCE_ID,
savedObjectsMock,
cryptoClient,
clientPoolSetup,
config,
logger
);
const client = await configureClient(dataSourceClientParams, clientPoolSetup, config, logger);

expect(parseClientOptionsMock).toHaveBeenCalled();
expect(ClientMock).toHaveBeenCalledTimes(1);
Expand All @@ -123,20 +122,15 @@ describe('configureClient', () => {
});

test('configure client with noAuth == false, will first call decrypt()', async () => {
const spy = jest.spyOn(cryptoClient, 'decodeAndDecrypt').mockResolvedValue('password');
const decodeAndDecryptSpy = jest
.spyOn(cryptographyClient, 'decodeAndDecrypt')
.mockResolvedValue('password');

const client = await configureClient(
DATA_SOURCE_ID,
savedObjectsMock,
cryptoClient,
clientPoolSetup,
config,
logger
);
const client = await configureClient(dataSourceClientParams, clientPoolSetup, config, logger);

expect(ClientMock).toHaveBeenCalledTimes(1);
expect(savedObjectsMock.get).toHaveBeenCalledTimes(2);
expect(spy).toHaveBeenCalledTimes(1);
expect(decodeAndDecryptSpy).toHaveBeenCalledTimes(1);
expect(client).toBe(dsClient.child.mock.results[0].value);
});
});
50 changes: 8 additions & 42 deletions src/plugins/data_source/server/client/configure_client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import { Client } from '@opensearch-project/opensearch';
import {
LegacyAPICaller,
Logger,
SavedObject,
SavedObjectsClientContract,
SavedObjectsErrorHelpers,
Expand All @@ -22,14 +22,12 @@ import { DataSourceClientParams } from '../types';
import { parseClientOptions } from './client_config';
import { OpenSearchClientPoolSetup } from './client_pool';

export const configureClient = async ({
dataSourceId,
savedObjects,
config,
logger,
cryptographyClient,
openSearchClientPoolSetup,
}: DataSourceClientParams): Promise<Client> => {
export const configureClient = async (
{ dataSourceId, savedObjects, cryptographyClient }: DataSourceClientParams,
openSearchClientPoolSetup: OpenSearchClientPoolSetup,
config: DataSourcePluginConfigType,
logger: Logger
): Promise<Client> => {
const dataSource = await getDataSource(dataSourceId, savedObjects);
const rootClient = getRootClient(dataSource.attributes, config, openSearchClientPoolSetup);

Expand Down Expand Up @@ -66,6 +64,7 @@ export const getCredential = async (
username,
password,
} = credentialSavedObject.attributes.credentialMaterials.credentialMaterialsContent;

const decodedPassword = await cryptographyClient.decodeAndDecrypt(password);
const credential = {
username,
Expand Down Expand Up @@ -148,36 +147,3 @@ const getBasicAuthClient = (
headers: { authorization: null },
});
};

// const getLegacyClient = (client: Client, isLegacy: boolean, logger: Logger): Client => {
// if (isLegacy) {
// logger.warn(
// 'Legacy OpenSearch client is used. Please migrate your code to use the new OpenSearch client.'
// );
// return new LegacyScopedClusterClient(callAsCurrentUser, callAsCurrentUser);
// } else {
// return client;
// }
// };

/**
* Calls specified endpoint with provided clientParams on behalf of the
* user initiated request to the OpenSearch Dashboards server (via HTTP request headers).
* See {@link LegacyAPICaller}.
*
* @param endpoint - String descriptor of the endpoint e.g. `cluster.getSettings` or `ping`.
* @param clientParams - A dictionary of parameters that will be passed directly to the OpenSearch JS client.
* @param options - Options that affect the way we call the API and process the result.
*/
// const callAsCurrentUser: LegacyAPICaller = async (
// client: Client,
// endpoint: string,
// clientParams: Record<string, any> = {},
// options?: LegacyCallAPIOptions
// ) => {
// return await (callAPI.bind(null, client as EsClient) as LegacyAPICaller)(
// endpoint,
// clientParams,
// options
// );
// };
4 changes: 2 additions & 2 deletions src/plugins/data_source/server/client/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
* SPDX-License-Identifier: Apache-2.0
*/

export { OpenSearchClientPool } from './client_pool';
export { configureClient } from './configure_client';
export { OpenSearchClientPool, OpenSearchClientPoolSetup } from './client_pool';
export { configureClient, getDataSource, getCredential } from './configure_client';
1 change: 1 addition & 0 deletions src/plugins/data_source/server/data_source_service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ describe('Data Source Service', () => {
test('exposes proper contract', async () => {
const setup = await service.setup(config);
expect(setup).toHaveProperty('getDataSourceClient');
expect(setup).toHaveProperty('getDataSourceLegacyClient');
});
});
});
47 changes: 16 additions & 31 deletions src/plugins/data_source/server/data_source_service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,15 @@
*/

import {
LegacyAPICaller,
LegacyCallAPIOptions,
Logger,
OpenSearchClient,
SavedObjectsClientContract,
} from '../../../../src/core/server';
import { DataSourcePluginConfigType } from '../config';
import { OpenSearchClientPool, configureClient } from './client';
import { CryptographyClient } from './cryptography';
import { configureLegacyClient } from './legacy';

export interface LegacyClientCallAPIParams {
endpoint: string;
clientParams?: Record<string, any>;
options?: LegacyCallAPIOptions;
}

export interface DataSourceClientParams {
dataSourceId: string;
// this saved objects client is used to fetch data source on behalf of users, caller should pass scoped saved objects client
savedObjects: SavedObjectsClientContract;
cryptographyClient: CryptographyClient;
}
import { DataSourceClientParams } from './types';

export interface DataSourceServiceSetup {
getDataSourceClient: (params: DataSourceClientParams) => Promise<OpenSearchClient>;
Expand All @@ -42,40 +29,38 @@ export interface DataSourceServiceSetup {
}
export class DataSourceService {
private readonly openSearchClientPool: OpenSearchClientPool;
private readonly legacyClientPool: OpenSearchClientPool;
private readonly legacyLogger: Logger;

constructor(private logger: Logger) {
this.legacyLogger = logger.get('legacy');
this.openSearchClientPool = new OpenSearchClientPool(logger);
this.legacyClientPool = new OpenSearchClientPool(this.legacyLogger);
}

async setup(config: DataSourcePluginConfigType): Promise<DataSourceServiceSetup> {
const basicParams = {
openSearchClientPoolSetup: await this.openSearchClientPool.setup(config),
config,
logger: this.logger,
};
const opensearchClientPoolSetup = await this.openSearchClientPool.setup(config);
const legacyClientPoolSetup = await this.legacyClientPool.setup(config);

const getDataSourceClient = async (
dataSourceClientParams: DataSourceClientParams
params: DataSourceClientParams
): Promise<OpenSearchClient> => {
return configureClient({
...basicParams,
...dataSourceClientParams,
});
return configureClient(params, opensearchClientPoolSetup, config, this.logger);
};

const getDataSourceLegacyClient = (dataSourceClientParams: DataSourceClientParams) => {
const getDataSourceLegacyClient = (params: DataSourceClientParams) => {
return {
callAPI: (
endpoint: string,
clientParams?: Record<string, any>,
options?: LegacyCallAPIOptions
) =>
configureLegacyClient(
{
...basicParams,
...dataSourceClientParams,
},
{ endpoint, clientParams, options }
params,
{ endpoint, clientParams, options },
legacyClientPoolSetup,
config,
this.legacyLogger
),
};
};
Expand Down
28 changes: 28 additions & 0 deletions src/plugins/data_source/server/legacy/client_config.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/
import { DataSourcePluginConfigType } from '../../config';
import { parseClientOptions } from './client_config';

const TEST_DATA_SOURCE_ENDPOINT = 'http://datasource.com';

const config = {
enabled: true,
clientPool: {
size: 5,
},
} as DataSourcePluginConfigType;

describe('parseClientOptions', () => {
test('include the ssl client configs as defaults', () => {
expect(parseClientOptions(config, TEST_DATA_SOURCE_ENDPOINT)).toEqual(
expect.objectContaining({
host: TEST_DATA_SOURCE_ENDPOINT,
ssl: {
rejectUnauthorized: true,
},
})
);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

export const ClientMock = jest.fn();
jest.doMock('elasticsearch', () => {
const actual = jest.requireActual('elasticsearch');
return {
...actual,
Client: ClientMock,
};
});

export const parseClientOptionsMock = jest.fn();
jest.doMock('./client_config', () => ({
parseClientOptions: parseClientOptionsMock,
}));
Loading

0 comments on commit 145ec29

Please sign in to comment.