diff --git a/src/plugins/search/public/es_search/es_search_strategy.test.ts b/src/plugins/search/public/es_search/es_search_strategy.test.ts new file mode 100644 index 0000000000000..40d25468bb89a --- /dev/null +++ b/src/plugins/search/public/es_search/es_search_strategy.test.ts @@ -0,0 +1,52 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { coreMock } from '../../../../core/public/mocks'; +import { esSearchStrategyProvider } from './es_search_strategy'; +import { CoreSetup } from 'kibana/public'; +import { ES_SEARCH_STRATEGY } from '../../common/es_search'; + +describe('ES search strategy', () => { + let mockCoreSetup: MockedKeys; + const mockSearch = jest.fn(); + + beforeEach(() => { + mockCoreSetup = coreMock.createSetup(); + mockSearch.mockClear(); + }); + + it('returns a strategy with `search` that calls the sync search `search`', () => { + const request = { params: {} }; + const options = {}; + + const esSearch = esSearchStrategyProvider( + { + core: mockCoreSetup, + }, + mockSearch + ); + esSearch.search(request, options); + + expect(mockSearch.mock.calls[0][0]).toEqual({ + ...request, + serverStrategy: ES_SEARCH_STRATEGY, + }); + expect(mockSearch.mock.calls[0][1]).toBe(options); + }); +}); diff --git a/src/plugins/search/public/es_search/es_search_strategy.ts b/src/plugins/search/public/es_search/es_search_strategy.ts index 03217c9382636..80f320dd68768 100644 --- a/src/plugins/search/public/es_search/es_search_strategy.ts +++ b/src/plugins/search/public/es_search/es_search_strategy.ts @@ -22,7 +22,7 @@ import { ES_SEARCH_STRATEGY, IEsSearchResponse } from '../../common'; import { SYNC_SEARCH_STRATEGY } from '../sync_search_strategy'; import { TSearchStrategyProvider, ISearchStrategy, ISearchGeneric, ISearchContext } from '..'; -export const esClientSearchStrategyProvider: TSearchStrategyProvider = ( +export const esSearchStrategyProvider: TSearchStrategyProvider = ( context: ISearchContext, search: ISearchGeneric ): ISearchStrategy => { diff --git a/src/plugins/search/public/es_search/plugin.test.ts b/src/plugins/search/public/es_search/plugin.test.ts new file mode 100644 index 0000000000000..b2784dfc0fe02 --- /dev/null +++ b/src/plugins/search/public/es_search/plugin.test.ts @@ -0,0 +1,43 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { coreMock } from '../../../../core/public/mocks'; +import { EsSearchService } from './plugin'; +import { CoreSetup } from '../../../../core/public'; +import { searchSetupMock } from '../mocks'; + +describe('ES search strategy service', () => { + let service: EsSearchService; + let mockCoreSetup: MockedKeys; + const opaqueId = Symbol(); + + beforeEach(() => { + service = new EsSearchService({ opaqueId }); + mockCoreSetup = coreMock.createSetup(); + }); + + describe('setup()', () => { + it('registers the ES search strategy', async () => { + service.setup(mockCoreSetup, { + search: searchSetupMock, + }); + expect(searchSetupMock.registerSearchStrategyProvider).toBeCalled(); + }); + }); +}); diff --git a/src/plugins/search/public/es_search/plugin.ts b/src/plugins/search/public/es_search/plugin.ts index 8a04574b9659e..ca26f78f21a59 100644 --- a/src/plugins/search/public/es_search/plugin.ts +++ b/src/plugins/search/public/es_search/plugin.ts @@ -19,7 +19,7 @@ import { Plugin, CoreSetup, PluginInitializerContext } from '../../../../core/public'; import { ES_SEARCH_STRATEGY } from '../../common/es_search'; -import { esClientSearchStrategyProvider } from './es_search_strategy'; +import { esSearchStrategyProvider } from './es_search_strategy'; import { ISearchSetup } from '../i_search_setup'; export interface IEsSearchSetupDependencies { @@ -32,7 +32,7 @@ export class EsSearchService implements Plugin { deps.search.registerSearchStrategyProvider( this.initializerContext.opaqueId, ES_SEARCH_STRATEGY, - esClientSearchStrategyProvider + esSearchStrategyProvider ); } diff --git a/src/plugins/search/public/i_search_strategy.ts b/src/plugins/search/public/i_search_strategy.ts index a8b8744c52bde..bd67409d5054a 100644 --- a/src/plugins/search/public/i_search_strategy.ts +++ b/src/plugins/search/public/i_search_strategy.ts @@ -61,7 +61,3 @@ export type TRegisterSearchStrategyProvider = ( export type TSearchStrategiesMap = { [K in TStrategyTypes]?: TSearchStrategyProviderEnhanced; }; - -export type TGetSearchStrategy = ( - strategyName: K -) => Promise>; diff --git a/src/plugins/search/public/mocks.ts b/src/plugins/search/public/mocks.ts new file mode 100644 index 0000000000000..81a028007bc94 --- /dev/null +++ b/src/plugins/search/public/mocks.ts @@ -0,0 +1,23 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export const searchSetupMock = { + registerSearchStrategyContext: jest.fn(), + registerSearchStrategyProvider: jest.fn(), +}; diff --git a/src/plugins/search/public/plugin.test.ts b/src/plugins/search/public/plugin.test.ts index d26e58ef1bf65..e4b404f295df0 100644 --- a/src/plugins/search/public/plugin.test.ts +++ b/src/plugins/search/public/plugin.test.ts @@ -21,8 +21,6 @@ import { coreMock } from '../../../core/public/mocks'; import { SearchPublicPlugin } from './plugin'; import { CoreSetup } from '../../../core/public'; -import { SYNC_SEARCH_STRATEGY } from './sync_search_strategy'; -import { ISearchAppMountContext } from './i_search_app_mount_context'; describe('Search service', () => { let plugin: SearchPublicPlugin; @@ -39,22 +37,5 @@ describe('Search service', () => { expect(setup).toHaveProperty('registerSearchStrategyContext'); expect(setup).toHaveProperty('registerSearchStrategyProvider'); }); - - it('app mount', async () => { - plugin.setup(mockCoreSetup); - - const mountContext = mockCoreSetup.application.registerMountContext.mock.calls[0][1]({ - core: mockCoreSetup, - }) as ISearchAppMountContext; - // console.log( - // 'mockCoreSetup.application.registerMountContext.mock.calls[0][1]', - // mockCoreSetup.application.registerMountContext.mock.calls[0][1]() - // ); - // console.log('mountContext', mountContext); - - await mountContext.search({}, {}, SYNC_SEARCH_STRATEGY); - - expect(mockCoreSetup.http.fetch.mock.calls[0]).toMatchInlineSnapshot(`undefined`); - }); }); }); diff --git a/src/plugins/search/public/sync_search_strategy.test.ts b/src/plugins/search/public/sync_search_strategy.test.ts new file mode 100644 index 0000000000000..46f266d114b98 --- /dev/null +++ b/src/plugins/search/public/sync_search_strategy.test.ts @@ -0,0 +1,56 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { coreMock } from '../../../core/public/mocks'; +import { SYNC_SEARCH_STRATEGY, syncSearchStrategyProvider } from './sync_search_strategy'; +import { CoreSetup } from '../../../core/public'; + +describe('Sync search strategy', () => { + let mockCoreSetup: MockedKeys; + const mockSearch = jest.fn(); + + beforeEach(() => { + mockCoreSetup = coreMock.createSetup(); + }); + + it('returns a strategy with `search` that calls the backend API', () => { + mockCoreSetup.http.fetch.mockImplementationOnce(() => Promise.resolve()); + + const syncSearch = syncSearchStrategyProvider( + { + core: mockCoreSetup, + }, + mockSearch + ); + syncSearch.search( + { + serverStrategy: SYNC_SEARCH_STRATEGY, + }, + {} + ); + expect(mockCoreSetup.http.fetch.mock.calls[0][0]).toBe(`/api/search/${SYNC_SEARCH_STRATEGY}`); + expect(mockCoreSetup.http.fetch.mock.calls[0][1]).toEqual({ + body: JSON.stringify({ + serverStrategy: 'SYNC_SEARCH_STRATEGY', + }), + method: 'POST', + signal: undefined, + }); + }); +}); diff --git a/src/plugins/search/public/sync_search_strategy.ts b/src/plugins/search/public/sync_search_strategy.ts index 4ffb52b68116a..8f4b2670136f4 100644 --- a/src/plugins/search/public/sync_search_strategy.ts +++ b/src/plugins/search/public/sync_search_strategy.ts @@ -32,10 +32,6 @@ export interface ISyncSearchRequest extends IKibanaSearchRequest { export const syncSearchStrategyProvider: TSearchStrategyProvider = ( context: ISearchContext ) => { - if (!context.core) { - throw new Error('core undefined!'); - } - const search: ISearch = ( request: ISyncSearchRequest, options: ISearchOptions diff --git a/src/plugins/search/server/create_api.test.ts b/src/plugins/search/server/create_api.test.ts new file mode 100644 index 0000000000000..5468f5f5b82cb --- /dev/null +++ b/src/plugins/search/server/create_api.test.ts @@ -0,0 +1,62 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { createApi } from './create_api'; + +import { TSearchStrategiesMap } from './i_search_strategy'; +import { IRouteHandlerSearchContext } from './i_route_handler_search_context'; +import { DEFAULT_SEARCH_STRATEGY } from '../common'; + +// let mockCoreSetup: MockedKeys; + +const mockDefaultSearch = jest.fn(() => Promise.resolve({ percentComplete: 0 })); +const mockDefaultSearchStrategyProvider = jest.fn(() => + Promise.resolve({ + search: mockDefaultSearch, + }) +); +const mockStrategies: TSearchStrategiesMap = { + [DEFAULT_SEARCH_STRATEGY]: mockDefaultSearchStrategyProvider, +}; + +describe('createApi', () => { + let api: IRouteHandlerSearchContext; + + beforeEach(() => { + api = createApi({ + caller: jest.fn(), + searchStrategies: mockStrategies, + }); + mockDefaultSearchStrategyProvider.mockClear(); + }); + + it('should default to DEFAULT_SEARCH_STRATEGY if none is provided', async () => { + await api.search({ + params: {}, + }); + expect(mockDefaultSearchStrategyProvider).toBeCalled(); + expect(mockDefaultSearch).toBeCalled(); + }); + + it('should throw if no provider is found for the given name', () => { + expect(api.search({}, 'noneByThisName')).rejects.toThrowErrorMatchingInlineSnapshot( + `"No strategy found for noneByThisName"` + ); + }); +}); diff --git a/src/plugins/search/server/create_api.ts b/src/plugins/search/server/create_api.ts index fe95d4a204b6c..cd78ad3481db2 100644 --- a/src/plugins/search/server/create_api.ts +++ b/src/plugins/search/server/create_api.ts @@ -38,9 +38,6 @@ export function createApi({ } // Give providers access to other search strategies by injecting this function const strategy = await strategyProvider(caller, api.search); - if (!strategy) { - throw new Error(`No strategy named ${name}`); - } return strategy.search(request); }, }; diff --git a/src/plugins/search/server/es_search/index.ts b/src/plugins/search/server/es_search/index.ts index 5135be39ed76f..4c76e82b95049 100644 --- a/src/plugins/search/server/es_search/index.ts +++ b/src/plugins/search/server/es_search/index.ts @@ -18,10 +18,10 @@ */ import { PluginInitializerContext } from '../../../../core/server'; -import { EsSearchServerPlugin } from './plugin'; +import { EsSearchService } from './plugin'; export { ES_SEARCH_STRATEGY, IEsSearchRequest, IEsSearchResponse } from '../../common'; export function plugin(initializerContext: PluginInitializerContext) { - return new EsSearchServerPlugin(initializerContext); + return new EsSearchService(initializerContext); } diff --git a/src/plugins/search/server/es_search/plugin.ts b/src/plugins/search/server/es_search/plugin.ts index d8cfcab676125..495bee9cc8b6d 100644 --- a/src/plugins/search/server/es_search/plugin.ts +++ b/src/plugins/search/server/es_search/plugin.ts @@ -26,7 +26,7 @@ interface IEsSearchDependencies { search: ISearchSetup; } -export class EsSearchServerPlugin implements Plugin { +export class EsSearchService implements Plugin { constructor(private initializerContext: PluginInitializerContext) {} public setup(core: CoreSetup, deps: IEsSearchDependencies) { diff --git a/src/plugins/search/server/i_search_strategy.ts b/src/plugins/search/server/i_search_strategy.ts index e7e747636cdb2..d00dd552c9e95 100644 --- a/src/plugins/search/server/i_search_strategy.ts +++ b/src/plugins/search/server/i_search_strategy.ts @@ -64,7 +64,3 @@ export type TRegisterSearchStrategyProvider = ( export type TSearchStrategiesMap = { [K in TStrategyTypes]?: TSearchStrategyProviderEnhanced; }; - -export type TGettSearchStrategy = ( - strategyName: K -) => Promise>; diff --git a/src/plugins/search/server/index.test.ts b/src/plugins/search/server/index.test.ts new file mode 100644 index 0000000000000..75e3d6a83ea62 --- /dev/null +++ b/src/plugins/search/server/index.test.ts @@ -0,0 +1,27 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { plugin } from '.'; +import { coreMock } from '../../../core/server/mocks'; + +it('search service is instantiated', () => { + const context = coreMock.createPluginInitializerContext({}); + const searchPlugin = plugin(context); + expect(searchPlugin).toBeDefined(); +}); diff --git a/src/plugins/search/server/mocks.ts b/src/plugins/search/server/mocks.ts new file mode 100644 index 0000000000000..ac585363495c6 --- /dev/null +++ b/src/plugins/search/server/mocks.ts @@ -0,0 +1,24 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export const searchSetupMock = { + registerSearchStrategyContext: jest.fn(), + registerSearchStrategyProvider: jest.fn(), + __LEGACY: jest.fn(), +}; diff --git a/src/plugins/search/server/plugin.test.ts b/src/plugins/search/server/plugin.test.ts new file mode 100644 index 0000000000000..c2f99cbe23f32 --- /dev/null +++ b/src/plugins/search/server/plugin.test.ts @@ -0,0 +1,56 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { coreMock } from '../../../core/server/mocks'; + +import { SearchServerPlugin } from './plugin'; +import { CoreSetup } from '../../../core/server'; + +const mockSearchApi = { search: jest.fn() }; +jest.mock('./create_api', () => ({ + createApi: () => mockSearchApi, +})); + +describe('Search service', () => { + let plugin: SearchServerPlugin; + let mockCoreSetup: MockedKeys; + + beforeEach(() => { + plugin = new SearchServerPlugin(coreMock.createPluginInitializerContext({})); + mockCoreSetup = coreMock.createSetup(); + mockSearchApi.search.mockClear(); + }); + + describe('setup()', () => { + it('exposes proper contract', async () => { + const setup = plugin.setup(mockCoreSetup); + expect(setup).toHaveProperty('registerSearchStrategyContext'); + expect(setup).toHaveProperty('registerSearchStrategyProvider'); + expect(setup).toHaveProperty('__LEGACY'); + }); + }); + + describe('__LEGACY', () => { + it('calls searchAPI.search', async () => { + const setup = plugin.setup(mockCoreSetup); + setup.__LEGACY.search(jest.fn(), {}, 'foo'); + expect(mockSearchApi.search).toBeCalled(); + }); + }); +}); diff --git a/src/plugins/search/server/plugin.ts b/src/plugins/search/server/plugin.ts index 65ac6b7be73b3..bec6d9e5a6380 100644 --- a/src/plugins/search/server/plugin.ts +++ b/src/plugins/search/server/plugin.ts @@ -35,7 +35,7 @@ import { TRegisterSearchStrategyProvider, } from './i_search_strategy'; import { IRouteHandlerSearchContext } from './i_route_handler_search_context'; -import { EsSearchServerPlugin } from './es_search/plugin'; +import { EsSearchService } from './es_search/plugin'; declare module 'kibana/server' { interface RequestHandlerContext { @@ -94,7 +94,7 @@ export class SearchServerPlugin implements Plugin { // ES search capabilities are written in a way that it could easily be a separate plugin, // however these two plugins are tightly coupled due to the default search strategy using // es search types. - new EsSearchServerPlugin(this.initializerContext).setup(core, { search: api }); + new EsSearchService(this.initializerContext).setup(core, { search: api }); return api; }