From 356281a6c1a45a5f4bd0145d54bf59360b10ffee Mon Sep 17 00:00:00 2001 From: Luke Elmers Date: Thu, 20 Aug 2020 14:44:36 -0600 Subject: [PATCH 01/15] Move search server routes into a directory. --- .../data/server/search/routes/index.ts | 20 +++++++++++++++++++ .../{routes.test.ts => routes/search.test.ts} | 18 +++++++++-------- .../search/{routes.ts => routes/search.ts} | 17 ++++++++-------- .../data/server/search/search_service.ts | 15 ++++++++++---- src/plugins/data/server/search/types.ts | 2 +- 5 files changed, 51 insertions(+), 21 deletions(-) create mode 100644 src/plugins/data/server/search/routes/index.ts rename src/plugins/data/server/search/{routes.test.ts => routes/search.test.ts} (82%) rename src/plugins/data/server/search/{routes.ts => routes/search.ts} (87%) diff --git a/src/plugins/data/server/search/routes/index.ts b/src/plugins/data/server/search/routes/index.ts new file mode 100644 index 0000000000000..220740d7cce6e --- /dev/null +++ b/src/plugins/data/server/search/routes/index.ts @@ -0,0 +1,20 @@ +/* + * 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 * from './search'; diff --git a/src/plugins/data/server/search/routes.test.ts b/src/plugins/data/server/search/routes/search.test.ts similarity index 82% rename from src/plugins/data/server/search/routes.test.ts rename to src/plugins/data/server/search/routes/search.test.ts index d91aeee1fe818..a9c1b4427c2a1 100644 --- a/src/plugins/data/server/search/routes.test.ts +++ b/src/plugins/data/server/search/routes/search.test.ts @@ -17,19 +17,21 @@ * under the License. */ -import { CoreSetup, RequestHandlerContext } from '../../../../../src/core/server'; -import { coreMock, httpServerMock } from '../../../../../src/core/server/mocks'; -import { registerSearchRoute } from './routes'; -import { DataPluginStart } from '../plugin'; -import { dataPluginMock } from '../mocks'; +import { CoreSetup, RequestHandlerContext, StartServicesAccessor } from 'src/core/server'; +import { coreMock, httpServerMock } from '../../../../../../src/core/server/mocks'; +import { registerSearchRoute } from './search'; +import { DataPluginStart } from '../../plugin'; +import { dataPluginMock } from '../../mocks'; describe('Search service', () => { let mockDataStart: MockedKeys; - let mockCoreSetup: MockedKeys>; + let mockCoreSetup: MockedKeys>; + let getStartServices: jest.Mocked>; beforeEach(() => { mockDataStart = dataPluginMock.createStartContract(); mockCoreSetup = coreMock.createSetup({ pluginStartContract: mockDataStart }); + getStartServices = mockCoreSetup.getStartServices; }); it('handler calls context.search.search with the given request and strategy', async () => { @@ -44,7 +46,7 @@ describe('Search service', () => { }); const mockResponse = httpServerMock.createResponseFactory(); - registerSearchRoute(mockCoreSetup); + registerSearchRoute(mockCoreSetup.http.createRouter(), { getStartServices }); const mockRouter = mockCoreSetup.http.createRouter.mock.results[0].value; const handler = mockRouter.post.mock.calls[0][1]; @@ -75,7 +77,7 @@ describe('Search service', () => { }); const mockResponse = httpServerMock.createResponseFactory(); - registerSearchRoute(mockCoreSetup); + registerSearchRoute(mockCoreSetup.http.createRouter(), { getStartServices }); const mockRouter = mockCoreSetup.http.createRouter.mock.results[0].value; const handler = mockRouter.post.mock.calls[0][1]; diff --git a/src/plugins/data/server/search/routes.ts b/src/plugins/data/server/search/routes/search.ts similarity index 87% rename from src/plugins/data/server/search/routes.ts rename to src/plugins/data/server/search/routes/search.ts index 3d813f745305f..769093bc79a8c 100644 --- a/src/plugins/data/server/search/routes.ts +++ b/src/plugins/data/server/search/routes/search.ts @@ -18,13 +18,14 @@ */ import { schema } from '@kbn/config-schema'; -import { CoreSetup } from '../../../../core/server'; -import { getRequestAbortedSignal } from '../lib'; -import { DataPluginStart } from '../plugin'; - -export function registerSearchRoute(core: CoreSetup): void { - const router = core.http.createRouter(); +import { IRouter } from 'src/core/server'; +import { getRequestAbortedSignal } from '../../lib'; +import { SearchRouteDependencies } from '../search_service'; +export function registerSearchRoute( + router: IRouter, + { getStartServices }: SearchRouteDependencies +): void { router.post( { path: '/internal/search/{strategy}/{id?}', @@ -44,7 +45,7 @@ export function registerSearchRoute(core: CoreSetup): v const { strategy, id } = request.params; const signal = getRequestAbortedSignal(request.events.aborted$); - const [, , selfStart] = await core.getStartServices(); + const [, , selfStart] = await getStartServices(); try { const response = await selfStart.search.search( @@ -85,7 +86,7 @@ export function registerSearchRoute(core: CoreSetup): v async (context, request, res) => { const { strategy, id } = request.params; - const [, , selfStart] = await core.getStartServices(); + const [, , selfStart] = await getStartServices(); const searchStrategy = selfStart.search.getSearchStrategy(strategy); if (!searchStrategy.cancel) return res.ok(); diff --git a/src/plugins/data/server/search/search_service.ts b/src/plugins/data/server/search/search_service.ts index edc94961c79d8..7918960d66539 100644 --- a/src/plugins/data/server/search/search_service.ts +++ b/src/plugins/data/server/search/search_service.ts @@ -24,7 +24,8 @@ import { Plugin, PluginInitializerContext, RequestHandlerContext, -} from '../../../../core/server'; + StartServicesAccessor, +} from 'src/core/server'; import { ISearchSetup, ISearchStart, ISearchStrategy, SearchEnhancements } from './types'; import { AggsService, AggsSetupDependencies } from './aggs'; @@ -55,6 +56,11 @@ export interface SearchServiceStartDependencies { fieldFormats: FieldFormatsStart; } +/** @internal */ +export interface SearchRouteDependencies { + getStartServices: StartServicesAccessor<{}, DataPluginStart>; +} + export class SearchService implements Plugin { private readonly aggsService = new AggsService(); private defaultSearchStrategyName: string = ES_SEARCH_STRATEGY; @@ -66,11 +72,14 @@ export class SearchService implements Plugin { ) {} public setup( - core: CoreSetup, + core: CoreSetup<{}, DataPluginStart>, { registerFunction, usageCollection }: SearchServiceSetupDependencies ): ISearchSetup { const usage = usageCollection ? usageProvider(core) : undefined; + const router = core.http.createRouter(); + registerSearchRoute(router, { getStartServices: core.getStartServices }); + this.registerSearchStrategy( ES_SEARCH_STRATEGY, esSearchStrategyProvider( @@ -85,8 +94,6 @@ export class SearchService implements Plugin { registerUsageCollector(usageCollection, this.initializerContext); } - registerSearchRoute(core); - return { __enhance: (enhancements: SearchEnhancements) => { if (this.searchStrategies.hasOwnProperty(enhancements.defaultStrategy)) { diff --git a/src/plugins/data/server/search/types.ts b/src/plugins/data/server/search/types.ts index 5ce1bb3e6b9f8..ae83724b26209 100644 --- a/src/plugins/data/server/search/types.ts +++ b/src/plugins/data/server/search/types.ts @@ -17,7 +17,7 @@ * under the License. */ -import { RequestHandlerContext } from '../../../../core/server'; +import { RequestHandlerContext } from 'src/core/server'; import { IKibanaSearchResponse, IKibanaSearchRequest } from '../../common/search'; import { AggsSetup, AggsStart } from './aggs'; import { SearchUsage } from './collectors/usage'; From 84ad62f8589c329945bf607f2f96d42ac78c6456 Mon Sep 17 00:00:00 2001 From: Luke Elmers Date: Tue, 25 Aug 2020 20:56:09 -0600 Subject: [PATCH 02/15] Add internal/_msearch route. --- .../data/server/search/routes/index.ts | 1 + .../data/server/search/routes/msearch.test.ts | 127 ++++++++++++++++++ .../data/server/search/routes/msearch.ts | 116 ++++++++++++++++ .../data/server/search/search_service.ts | 3 +- 4 files changed, 246 insertions(+), 1 deletion(-) create mode 100644 src/plugins/data/server/search/routes/msearch.test.ts create mode 100644 src/plugins/data/server/search/routes/msearch.ts diff --git a/src/plugins/data/server/search/routes/index.ts b/src/plugins/data/server/search/routes/index.ts index 220740d7cce6e..2217890ff778e 100644 --- a/src/plugins/data/server/search/routes/index.ts +++ b/src/plugins/data/server/search/routes/index.ts @@ -17,4 +17,5 @@ * under the License. */ +export * from './msearch'; export * from './search'; diff --git a/src/plugins/data/server/search/routes/msearch.test.ts b/src/plugins/data/server/search/routes/msearch.test.ts new file mode 100644 index 0000000000000..3764a37a12ddf --- /dev/null +++ b/src/plugins/data/server/search/routes/msearch.test.ts @@ -0,0 +1,127 @@ +/* + * 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 { CoreSetup, RequestHandlerContext, StartServicesAccessor } from 'src/core/server'; +import { coreMock, httpServerMock } from '../../../../../../src/core/server/mocks'; +import { registerMsearchRoute, convertRequestBody } from './msearch'; +import { DataPluginStart } from '../../plugin'; +import { dataPluginMock } from '../../mocks'; + +describe('msearch route', () => { + let mockDataStart: MockedKeys; + let mockCoreSetup: MockedKeys>; + let getStartServices: jest.Mocked>; + + beforeEach(() => { + mockDataStart = dataPluginMock.createStartContract(); + mockCoreSetup = coreMock.createSetup({ pluginStartContract: mockDataStart }); + getStartServices = mockCoreSetup.getStartServices; + }); + + it('handler calls /_msearch with the given request', async () => { + const response = { id: 'yay' }; + const mockClient = { transport: { request: jest.fn().mockResolvedValue(response) } }; + const mockContext = { core: { elasticsearch: { client: { asCurrentUser: mockClient } } } }; + const mockBody = { searches: [{ header: {}, body: {} }] }; + const mockQuery = {}; + const mockRequest = httpServerMock.createKibanaRequest({ + body: mockBody, + query: mockQuery, + }); + const mockResponse = httpServerMock.createResponseFactory(); + + registerMsearchRoute(mockCoreSetup.http.createRouter(), { getStartServices }); + + const mockRouter = mockCoreSetup.http.createRouter.mock.results[0].value; + const handler = mockRouter.post.mock.calls[0][1]; + await handler((mockContext as unknown) as RequestHandlerContext, mockRequest, mockResponse); + + expect(mockClient.transport.request.mock.calls[0][0].method).toBe('GET'); + expect(mockClient.transport.request.mock.calls[0][0].path).toBe('/_msearch'); + expect(mockClient.transport.request.mock.calls[0][0].body).toEqual( + convertRequestBody(mockBody as any) + ); + expect(mockResponse.ok).toBeCalled(); + expect(mockResponse.ok.mock.calls[0][0]).toEqual({ + body: response, + }); + }); + + it('handler throws an error if the search throws an error', async () => { + const response = { + message: 'oh no', + body: { + error: 'oops', + }, + }; + const mockClient = { + transport: { request: jest.fn().mockReturnValue(Promise.reject(response)) }, + }; + const mockContext = { core: { elasticsearch: { client: { asCurrentUser: mockClient } } } }; + const mockBody = { searches: [{ header: {}, body: {} }] }; + const mockQuery = {}; + const mockRequest = httpServerMock.createKibanaRequest({ + body: mockBody, + query: mockQuery, + }); + const mockResponse = httpServerMock.createResponseFactory(); + + registerMsearchRoute(mockCoreSetup.http.createRouter(), { getStartServices }); + + const mockRouter = mockCoreSetup.http.createRouter.mock.results[0].value; + const handler = mockRouter.post.mock.calls[0][1]; + await handler((mockContext as unknown) as RequestHandlerContext, mockRequest, mockResponse); + + expect(mockClient.transport.request).toBeCalled(); + expect(mockResponse.customError).toBeCalled(); + + const error: any = mockResponse.customError.mock.calls[0][0]; + expect(error.body.message).toBe('oh no'); + expect(error.body.attributes.error).toBe('oops'); + }); + + describe('convertRequestBody', () => { + it('combines header & body into proper msearch request', () => { + const request = { + searches: [{ header: { index: 'foo', preference: 0 }, body: { test: true } }], + }; + expect(convertRequestBody(request)).toMatchInlineSnapshot(` + "{\\"index\\":\\"foo\\",\\"preference\\":0} + {\\"test\\":true} + " + `); + }); + + it('handles multiple searches', () => { + const request = { + searches: [ + { header: { index: 'foo', preference: 0 }, body: { test: true } }, + { header: { index: 'bar', preference: 1 }, body: { hello: 'world' } }, + ], + }; + expect(convertRequestBody(request)).toMatchInlineSnapshot(` + "{\\"index\\":\\"foo\\",\\"preference\\":0} + {\\"test\\":true} + {\\"index\\":\\"bar\\",\\"preference\\":1} + {\\"hello\\":\\"world\\"} + " + `); + }); + }); +}); diff --git a/src/plugins/data/server/search/routes/msearch.ts b/src/plugins/data/server/search/routes/msearch.ts new file mode 100644 index 0000000000000..6a15b707aae48 --- /dev/null +++ b/src/plugins/data/server/search/routes/msearch.ts @@ -0,0 +1,116 @@ +/* + * 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 { schema } from '@kbn/config-schema'; +import { IRouter } from 'src/core/server'; +import { SearchRouteDependencies } from '../search_service'; + +interface MsearchHeaders { + index: string; + preference: number; +} + +interface MsearchRequest { + header: MsearchHeaders; + body: any; +} + +interface RequestBody { + searches: MsearchRequest[]; +} + +/** @internal */ +export function convertRequestBody(requestBody: RequestBody): string { + return requestBody.searches.reduce((req, curr) => { + const header = JSON.stringify({ ...curr.header }); + const body = JSON.stringify({ ...curr.body }); + req += `${header}\n${body}\n`; + return req; + }, ''); +} + +/** + * The msearch route takes in an array of searches, each consisting of header + * and body json, and reformts them into a single request for the _msearch API. + * + * The reason for taking requests in a different format is so that we can + * inject values into each request without needing to manually parse each one. + * + * This route is internal and _should not be used_ in any new areas of code. + * It only exists as a means of removing remaining dependencies on the + * legacy ES client. + * + * @deprecated + */ +export function registerMsearchRoute(router: IRouter, deps: SearchRouteDependencies): void { + router.post( + { + path: '/internal/_msearch', + validate: { + body: schema.object({ + searches: schema.arrayOf( + schema.object({ + header: schema.object( + { + index: schema.string(), + preference: schema.number(), + }, + { unknowns: 'allow' } + ), + body: schema.object({}, { unknowns: 'allow' }), + }) + ), + }), + query: schema.object({ + // We don't use `schema.boolean` here, because all query string parameters are treated as + // strings and @kbn/config-schema doesn't coerce strings to booleans. + ignore_throttled: schema.oneOf([schema.literal('true'), schema.literal('false')]), + rest_total_hits_as_int: schema.oneOf([schema.literal('true'), schema.literal('false')]), + max_concurrent_shard_requests: schema.maybe(schema.number()), + }), + }, + }, + async (context, request, res) => { + const client = context.core.elasticsearch.client.asCurrentUser; + const body = convertRequestBody(request.body); + const querystring = request.query; + + try { + const response = await client.transport.request({ + method: 'GET', + path: '/_msearch', + body, + querystring, + }); + + return res.ok({ body: response }); + } catch (err) { + return res.customError({ + statusCode: err.statusCode || 500, + body: { + message: err.message, + attributes: { + error: err.body?.error || err.message, + }, + }, + }); + } + } + ); +} diff --git a/src/plugins/data/server/search/search_service.ts b/src/plugins/data/server/search/search_service.ts index 7918960d66539..80129c0429ba0 100644 --- a/src/plugins/data/server/search/search_service.ts +++ b/src/plugins/data/server/search/search_service.ts @@ -31,7 +31,7 @@ import { ISearchSetup, ISearchStart, ISearchStrategy, SearchEnhancements } from import { AggsService, AggsSetupDependencies } from './aggs'; import { FieldFormatsStart } from '../field_formats'; -import { registerSearchRoute } from './routes'; +import { registerMsearchRoute, registerSearchRoute } from './routes'; import { ES_SEARCH_STRATEGY, esSearchStrategyProvider } from './es_search'; import { DataPluginStart } from '../plugin'; import { UsageCollectionSetup } from '../../../usage_collection/server'; @@ -79,6 +79,7 @@ export class SearchService implements Plugin { const router = core.http.createRouter(); registerSearchRoute(router, { getStartServices: core.getStartServices }); + registerMsearchRoute(router, { getStartServices: core.getStartServices }); this.registerSearchStrategy( ES_SEARCH_STRATEGY, From 9a8de032ed328f8e583fe2babc9269d395fc8bb6 Mon Sep 17 00:00:00 2001 From: Luke Elmers Date: Tue, 25 Aug 2020 20:57:37 -0600 Subject: [PATCH 03/15] Remove legacy search API, rewrite default search strategy to use internal route. --- src/plugins/data/public/plugin.ts | 11 +-- src/plugins/data/public/search/fetch/types.ts | 4 +- .../public/search/legacy/call_client.test.ts | 8 ++- .../legacy/default_search_strategy.test.ts | 43 ++++-------- .../search/legacy/default_search_strategy.ts | 67 ++++++++++++------- src/plugins/data/public/search/mocks.ts | 6 -- .../data/public/search/search_service.ts | 26 ++----- .../create_search_source.test.ts | 6 +- .../data/public/search/search_source/mocks.ts | 9 +-- .../search_source/search_source.test.ts | 6 +- .../search/search_source/search_source.ts | 8 +-- src/plugins/data/public/search/types.ts | 10 --- 12 files changed, 81 insertions(+), 123 deletions(-) diff --git a/src/plugins/data/public/plugin.ts b/src/plugins/data/public/plugin.ts index 3bc19a578a417..3b18e0fbed537 100644 --- a/src/plugins/data/public/plugin.ts +++ b/src/plugins/data/public/plugin.ts @@ -19,13 +19,7 @@ import './index.scss'; -import { - PluginInitializerContext, - CoreSetup, - CoreStart, - Plugin, - PackageInfo, -} from 'src/core/public'; +import { PluginInitializerContext, CoreSetup, CoreStart, Plugin } from 'src/core/public'; import { ConfigSchema } from '../config'; import { Storage, IStorageWrapper, createStartServicesGetter } from '../../kibana_utils/public'; import { @@ -100,7 +94,6 @@ export class DataPublicPlugin private readonly fieldFormatsService: FieldFormatsService; private readonly queryService: QueryService; private readonly storage: IStorageWrapper; - private readonly packageInfo: PackageInfo; constructor(initializerContext: PluginInitializerContext) { this.searchService = new SearchService(); @@ -108,7 +101,6 @@ export class DataPublicPlugin this.fieldFormatsService = new FieldFormatsService(); this.autocomplete = new AutocompleteService(initializerContext); this.storage = new Storage(window.localStorage); - this.packageInfo = initializerContext.env.packageInfo; } public setup( @@ -145,7 +137,6 @@ export class DataPublicPlugin const searchService = this.searchService.setup(core, { usageCollection, - packageInfo: this.packageInfo, expressions, }); diff --git a/src/plugins/data/public/search/fetch/types.ts b/src/plugins/data/public/search/fetch/types.ts index 670c4f731971a..33a205b342ae8 100644 --- a/src/plugins/data/public/search/fetch/types.ts +++ b/src/plugins/data/public/search/fetch/types.ts @@ -17,8 +17,8 @@ * under the License. */ +import { HttpStart } from 'src/core/public'; import { GetConfigFn } from '../../../common'; -import { ISearchStartLegacy } from '../types'; /** * @internal @@ -35,9 +35,9 @@ export interface FetchOptions { } export interface FetchHandlers { - legacySearchService: ISearchStartLegacy; config: { get: GetConfigFn }; esShardTimeout: number; + http: HttpStart; } export interface SearchError { diff --git a/src/plugins/data/public/search/legacy/call_client.test.ts b/src/plugins/data/public/search/legacy/call_client.test.ts index a3c4e720b4cab..f0f36856e1b9a 100644 --- a/src/plugins/data/public/search/legacy/call_client.test.ts +++ b/src/plugins/data/public/search/legacy/call_client.test.ts @@ -17,6 +17,7 @@ * under the License. */ +import { coreMock } from '../../../../../core/public/mocks'; import { callClient } from './call_client'; import { SearchStrategySearchParams } from './types'; import { defaultSearchStrategy } from './default_search_strategy'; @@ -54,7 +55,12 @@ describe('callClient', () => { test('Passes the additional arguments it is given to the search strategy', () => { const searchRequests = [{ _searchStrategyId: 0 }]; - const args = { legacySearchService: {}, config: {}, esShardTimeout: 0 } as FetchHandlers; + const args = { + http: coreMock.createStart().http, + legacySearchService: {}, + config: { get: jest.fn() }, + esShardTimeout: 0, + } as FetchHandlers; callClient(searchRequests, [], args); diff --git a/src/plugins/data/public/search/legacy/default_search_strategy.test.ts b/src/plugins/data/public/search/legacy/default_search_strategy.test.ts index 4148055c1eb58..f1eb88f1c5671 100644 --- a/src/plugins/data/public/search/legacy/default_search_strategy.test.ts +++ b/src/plugins/data/public/search/legacy/default_search_strategy.test.ts @@ -17,9 +17,9 @@ * under the License. */ -import { IUiSettingsClient } from 'kibana/public'; +import { HttpStart, IUiSettingsClient } from 'src/core/public'; +import { coreMock } from '../../../../../core/public/mocks'; import { defaultSearchStrategy } from './default_search_strategy'; -import { searchServiceMock } from '../mocks'; import { SearchStrategySearchParams } from './types'; import { UI_SETTINGS } from '../../../common'; @@ -31,30 +31,19 @@ function getConfigStub(config: any = {}) { } as IUiSettingsClient; } -const msearchMockResponse: any = Promise.resolve([]); -msearchMockResponse.abort = jest.fn(); -const msearchMock = jest.fn().mockReturnValue(msearchMockResponse); - -const searchMockResponse: any = Promise.resolve([]); -searchMockResponse.abort = jest.fn(); -const searchMock = jest.fn().mockReturnValue(searchMockResponse); +const msearchMock = jest.fn().mockResolvedValue({ body: { responses: [] } }); describe('defaultSearchStrategy', function () { describe('search', function () { let searchArgs: MockedKeys>; let es: any; + let http: jest.Mocked; beforeEach(() => { - msearchMockResponse.abort.mockClear(); msearchMock.mockClear(); - searchMockResponse.abort.mockClear(); - searchMock.mockClear(); - - const searchService = searchServiceMock.createStartContract(); - searchService.aggs.calculateAutoTimeExpression = jest.fn().mockReturnValue('1d'); - searchService.__LEGACY.esClient.search = searchMock; - searchService.__LEGACY.esClient.msearch = msearchMock; + http = coreMock.createStart().http; + http.post.mockResolvedValue(msearchMock); searchArgs = { searchRequests: [ @@ -63,16 +52,16 @@ describe('defaultSearchStrategy', function () { }, ], esShardTimeout: 0, - legacySearchService: searchService.__LEGACY, + http, }; - es = searchArgs.legacySearchService.esClient; + es = http.post; }); test('does not send max_concurrent_shard_requests by default', async () => { const config = getConfigStub({ [UI_SETTINGS.COURIER_BATCH_SEARCHES]: true }); await search({ ...searchArgs, config }); - expect(es.msearch.mock.calls[0][0].max_concurrent_shard_requests).toBe(undefined); + expect(es.mock.calls[0][1].query.max_concurrent_shard_requests).toBe(undefined); }); test('allows configuration of max_concurrent_shard_requests', async () => { @@ -81,13 +70,13 @@ describe('defaultSearchStrategy', function () { [UI_SETTINGS.COURIER_MAX_CONCURRENT_SHARD_REQUESTS]: 42, }); await search({ ...searchArgs, config }); - expect(es.msearch.mock.calls[0][0].max_concurrent_shard_requests).toBe(42); + expect(es.mock.calls[0][1].query.max_concurrent_shard_requests).toBe(42); }); test('should set rest_total_hits_as_int to true on a request', async () => { const config = getConfigStub({ [UI_SETTINGS.COURIER_BATCH_SEARCHES]: true }); await search({ ...searchArgs, config }); - expect(es.msearch.mock.calls[0][0]).toHaveProperty('rest_total_hits_as_int', true); + expect(es.mock.calls[0][1].query).toHaveProperty('rest_total_hits_as_int', true); }); test('should set ignore_throttled=false when including frozen indices', async () => { @@ -96,15 +85,7 @@ describe('defaultSearchStrategy', function () { [UI_SETTINGS.SEARCH_INCLUDE_FROZEN]: true, }); await search({ ...searchArgs, config }); - expect(es.msearch.mock.calls[0][0]).toHaveProperty('ignore_throttled', false); - }); - - test('should properly call abort with msearch', () => { - const config = getConfigStub({ - [UI_SETTINGS.COURIER_BATCH_SEARCHES]: true, - }); - search({ ...searchArgs, config }).abort(); - expect(msearchMockResponse.abort).toHaveBeenCalled(); + expect(es.mock.calls[0][1].query).toHaveProperty('ignore_throttled', false); }); }); }); diff --git a/src/plugins/data/public/search/legacy/default_search_strategy.ts b/src/plugins/data/public/search/legacy/default_search_strategy.ts index 6ccb0a01cf898..b32315163bb87 100644 --- a/src/plugins/data/public/search/legacy/default_search_strategy.ts +++ b/src/plugins/data/public/search/legacy/default_search_strategy.ts @@ -17,6 +17,8 @@ * under the License. */ +import { BehaviorSubject } from 'rxjs'; + import { getPreference, getTimeout } from '../fetch'; import { getMSearchParams } from './get_msearch_params'; import { SearchStrategyProvider, SearchStrategySearchParams } from './types'; @@ -30,34 +32,53 @@ export const defaultSearchStrategy: SearchStrategyProvider = { }, }; -function msearch({ - searchRequests, - legacySearchService, - config, - esShardTimeout, -}: SearchStrategySearchParams) { - const es = legacySearchService.esClient; - const inlineRequests = searchRequests.map(({ index, body, search_type: searchType }) => { - const inlineHeader = { - index: index.title || index, - search_type: searchType, - ignore_unavailable: true, - preference: getPreference(config.get), - }; - const inlineBody = { - ...body, - timeout: getTimeout(esShardTimeout), +function msearch({ searchRequests, config, http, esShardTimeout }: SearchStrategySearchParams) { + const requests = searchRequests.map(({ index, body, search_type: searchType }) => { + return { + header: { + index: index.title || index, + ignore_unavailable: true, + preference: getPreference(config.get), + search_type: searchType, + }, + body: { + ...body, + timeout: getTimeout(esShardTimeout), + }, }; - return `${JSON.stringify(inlineHeader)}\n${JSON.stringify(inlineBody)}`; }); - const searching = es.msearch({ - ...getMSearchParams(config.get), - body: `${inlineRequests.join('\n')}\n`, + const abortController = new AbortController(); + let resolved = false; + + const loadingCount$ = new BehaviorSubject(0); + http.addLoadingCountSource(loadingCount$); + + // Start LoadingIndicator + loadingCount$.next(loadingCount$.getValue() + 1); + + const cleanup = () => { + if (!resolved) { + resolved = true; + // Decrement loading counter & cleanup BehaviorSubject + loadingCount$.next(loadingCount$.getValue() - 1); + loadingCount$.complete(); + } + }; + + const searching = http.post('/internal/_msearch', { + query: getMSearchParams(config.get), + body: JSON.stringify({ searches: requests }), + signal: abortController.signal, }); + searching.finally(() => cleanup()); + return { - searching: searching.then(({ responses }: any) => responses), - abort: searching.abort, + abort: () => { + abortController.abort(); + cleanup(); + }, + searching: searching.then(({ body }) => body?.responses), }; } diff --git a/src/plugins/data/public/search/mocks.ts b/src/plugins/data/public/search/mocks.ts index 8ccf46fe7c97d..f4ed7d8b122b9 100644 --- a/src/plugins/data/public/search/mocks.ts +++ b/src/plugins/data/public/search/mocks.ts @@ -35,12 +35,6 @@ function createStartContract(): jest.Mocked { aggs: searchAggsStartMock(), search: jest.fn(), searchSource: searchSourceMock, - __LEGACY: { - esClient: { - search: jest.fn(), - msearch: jest.fn(), - }, - }, }; } diff --git a/src/plugins/data/public/search/search_service.ts b/src/plugins/data/public/search/search_service.ts index 9a30a15936fe5..8caa4b3b0dd67 100644 --- a/src/plugins/data/public/search/search_service.ts +++ b/src/plugins/data/public/search/search_service.ts @@ -17,11 +17,10 @@ * under the License. */ -import { Plugin, CoreSetup, CoreStart, PackageInfo } from 'src/core/public'; +import { Plugin, CoreSetup, CoreStart } from 'src/core/public'; import { ISearchSetup, ISearchStart, SearchEnhancements } from './types'; import { createSearchSource, SearchSource, SearchSourceDependencies } from './search_source'; -import { getEsClient, LegacyApiCaller } from './legacy'; import { AggsService, AggsStartDependencies } from './aggs'; import { IndexPatternsContract } from '../index_patterns/index_patterns'; import { ISearchInterceptor, SearchInterceptor } from './search_interceptor'; @@ -33,9 +32,8 @@ import { ExpressionsSetup } from '../../../expressions/public'; /** @internal */ export interface SearchServiceSetupDependencies { - packageInfo: PackageInfo; - usageCollection?: UsageCollectionSetup; expressions: ExpressionsSetup; + usageCollection?: UsageCollectionSetup; } /** @internal */ @@ -45,28 +43,18 @@ export interface SearchServiceStartDependencies { } export class SearchService implements Plugin { - private esClient?: LegacyApiCaller; private readonly aggsService = new AggsService(); private searchInterceptor!: ISearchInterceptor; private usageCollector?: SearchUsageCollector; public setup( { http, getStartServices, injectedMetadata, notifications, uiSettings }: CoreSetup, - { expressions, packageInfo, usageCollection }: SearchServiceSetupDependencies + { expressions, usageCollection }: SearchServiceSetupDependencies ): ISearchSetup { - const esApiVersion = injectedMetadata.getInjectedVar('esApiVersion') as string; const esRequestTimeout = injectedMetadata.getInjectedVar('esRequestTimeout') as number; - const packageVersion = packageInfo.version; this.usageCollector = createUsageCollector(getStartServices, usageCollection); - this.esClient = getEsClient({ - esRequestTimeout, - esApiVersion, - http, - packageVersion, - }); - /** * A global object that intercepts all searches and provides convenience methods for cancelling * all pending search requests, as well as getting the number of pending search requests. @@ -107,15 +95,12 @@ export class SearchService implements Plugin { return this.searchInterceptor.search(request, options); }) as ISearchGeneric; - const legacySearch = { - esClient: this.esClient!, - }; - const searchSourceDependencies: SearchSourceDependencies = { getConfig: uiSettings.get.bind(uiSettings), + // TODO: we don't need this, apply on the server esShardTimeout: injectedMetadata.getInjectedVar('esShardTimeout') as number, search, - legacySearch, + http, }; return { @@ -127,7 +112,6 @@ export class SearchService implements Plugin { return new SearchSource({}, searchSourceDependencies); }, }, - __LEGACY: legacySearch, }; } diff --git a/src/plugins/data/public/search/search_source/create_search_source.test.ts b/src/plugins/data/public/search/search_source/create_search_source.test.ts index 56f6ca6c56270..1300c67d3c0fc 100644 --- a/src/plugins/data/public/search/search_source/create_search_source.test.ts +++ b/src/plugins/data/public/search/search_source/create_search_source.test.ts @@ -22,7 +22,7 @@ import { SearchSourceDependencies } from './search_source'; import { IIndexPattern } from '../../../common/index_patterns'; import { IndexPatternsContract } from '../../index_patterns/index_patterns'; import { Filter } from '../../../common/es_query/filters'; -import { dataPluginMock } from '../../mocks'; +import { coreMock } from '../../../../../core/public/mocks'; describe('createSearchSource', () => { const indexPatternMock: IIndexPattern = {} as IIndexPattern; @@ -31,13 +31,11 @@ describe('createSearchSource', () => { let createSearchSource: ReturnType; beforeEach(() => { - const data = dataPluginMock.createStartContract(); - dependencies = { getConfig: jest.fn(), search: jest.fn(), - legacySearch: data.search.__LEGACY, esShardTimeout: 30000, + http: coreMock.createStart().http, }; indexPatternContractMock = ({ diff --git a/src/plugins/data/public/search/search_source/mocks.ts b/src/plugins/data/public/search/search_source/mocks.ts index 4e1c35557ffa6..16f665994e3bd 100644 --- a/src/plugins/data/public/search/search_source/mocks.ts +++ b/src/plugins/data/public/search/search_source/mocks.ts @@ -17,7 +17,7 @@ * under the License. */ -import { uiSettingsServiceMock } from '../../../../../core/public/mocks'; +import { httpServiceMock, uiSettingsServiceMock } from '../../../../../core/public/mocks'; import { ISearchSource, SearchSource } from './search_source'; import { SearchSourceFields } from './types'; @@ -54,10 +54,5 @@ export const createSearchSourceMock = (fields?: SearchSourceFields) => getConfig: uiSettingsServiceMock.createStartContract().get, esShardTimeout: 30000, search: jest.fn(), - legacySearch: { - esClient: { - search: jest.fn(), - msearch: jest.fn(), - }, - }, + http: httpServiceMock.createStartContract(), }); diff --git a/src/plugins/data/public/search/search_source/search_source.test.ts b/src/plugins/data/public/search/search_source/search_source.test.ts index 2f0fa0765e25a..a5bf700624a33 100644 --- a/src/plugins/data/public/search/search_source/search_source.test.ts +++ b/src/plugins/data/public/search/search_source/search_source.test.ts @@ -22,7 +22,7 @@ import { GetConfigFn } from 'src/plugins/data/common'; import { SearchSource, SearchSourceDependencies } from './search_source'; import { IndexPattern, SortDirection } from '../..'; import { fetchSoon } from '../legacy'; -import { dataPluginMock } from '../../../../data/public/mocks'; +import { coreMock } from '../../../../../core/public/mocks'; jest.mock('../legacy', () => ({ fetchSoon: jest.fn().mockResolvedValue({}), @@ -54,8 +54,6 @@ describe('SearchSource', () => { let searchSourceDependencies: SearchSourceDependencies; beforeEach(() => { - const data = dataPluginMock.createStartContract(); - mockSearchMethod = jest.fn(() => { return new Observable((subscriber) => { setTimeout(() => { @@ -70,8 +68,8 @@ describe('SearchSource', () => { searchSourceDependencies = { getConfig: jest.fn(), search: mockSearchMethod, - legacySearch: data.search.__LEGACY, esShardTimeout: 30000, + http: coreMock.createStart().http, }; }); diff --git a/src/plugins/data/public/search/search_source/search_source.ts b/src/plugins/data/public/search/search_source/search_source.ts index d2e3370762059..ae6817510feaf 100644 --- a/src/plugins/data/public/search/search_source/search_source.ts +++ b/src/plugins/data/public/search/search_source/search_source.ts @@ -72,6 +72,7 @@ import { setWith } from '@elastic/safer-lodash-set'; import { uniqueId, uniq, extend, pick, difference, omit, isObject, keys, isFunction } from 'lodash'; import { map } from 'rxjs/operators'; +import { HttpStart } from 'src/core/public'; import { normalizeSortRequest } from './normalize_sort_request'; import { filterDocvalueFields } from './filter_docvalue_fields'; import { fieldWildcardFilter } from '../../../../kibana_utils/common'; @@ -90,7 +91,6 @@ import { getHighlightRequest } from '../../../common/field_formats'; import { GetConfigFn } from '../../../common/types'; import { fetchSoon } from '../legacy'; import { extractReferences } from './extract_references'; -import { ISearchStartLegacy } from '../types'; /** @internal */ export const searchSourceRequiredUiSettings = [ @@ -111,7 +111,7 @@ export const searchSourceRequiredUiSettings = [ export interface SearchSourceDependencies { getConfig: GetConfigFn; search: ISearchGeneric; - legacySearch: ISearchStartLegacy; + http: HttpStart; esShardTimeout: number; } @@ -243,7 +243,7 @@ export class SearchSource { * @return {Promise>} */ private async legacyFetch(searchRequest: SearchRequest, options: FetchOptions) { - const { esShardTimeout, legacySearch, getConfig } = this.dependencies; + const { esShardTimeout, http, getConfig } = this.dependencies; return await fetchSoon( searchRequest, @@ -252,7 +252,7 @@ export class SearchSource { ...options, }, { - legacySearchService: legacySearch, + http, config: { get: getConfig }, esShardTimeout, } diff --git a/src/plugins/data/public/search/types.ts b/src/plugins/data/public/search/types.ts index 55726e40f5a77..22f31308615d4 100644 --- a/src/plugins/data/public/search/types.ts +++ b/src/plugins/data/public/search/types.ts @@ -19,7 +19,6 @@ import { Observable } from 'rxjs'; import { PackageInfo } from 'kibana/server'; -import { LegacyApiCaller } from './legacy/es_client'; import { ISearchInterceptor } from './search_interceptor'; import { ISearchSource, SearchSourceFields } from './search_source'; import { SearchUsageCollector } from './collectors'; @@ -51,10 +50,6 @@ export type ISearchGeneric = < options?: ISearchOptions ) => Observable; -export interface ISearchStartLegacy { - esClient: LegacyApiCaller; -} - export interface SearchEnhancements { searchInterceptor: ISearchInterceptor; } @@ -78,11 +73,6 @@ export interface ISearchStart { create: (fields?: SearchSourceFields) => Promise; createEmpty: () => ISearchSource; }; - /** - * @deprecated - * @internal - */ - __LEGACY: ISearchStartLegacy; } export { SEARCH_EVENT_TYPE } from './collectors'; From 371a4dfe71bf497d788d711deae6b6844d25c861 Mon Sep 17 00:00:00 2001 From: Luke Elmers Date: Tue, 25 Aug 2020 21:03:43 -0600 Subject: [PATCH 04/15] Remove legacy es_client code. --- .../search/legacy/es_client/get_es_client.ts | 98 ------------------- .../public/search/legacy/es_client/index.ts | 21 ---- .../public/search/legacy/es_client/types.ts | 30 ------ .../data/public/search/legacy/index.ts | 1 - 4 files changed, 150 deletions(-) delete mode 100644 src/plugins/data/public/search/legacy/es_client/get_es_client.ts delete mode 100644 src/plugins/data/public/search/legacy/es_client/index.ts delete mode 100644 src/plugins/data/public/search/legacy/es_client/types.ts diff --git a/src/plugins/data/public/search/legacy/es_client/get_es_client.ts b/src/plugins/data/public/search/legacy/es_client/get_es_client.ts deleted file mode 100644 index 4367544ad9ff4..0000000000000 --- a/src/plugins/data/public/search/legacy/es_client/get_es_client.ts +++ /dev/null @@ -1,98 +0,0 @@ -/* - * 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. - */ - -// @ts-ignore -import { default as es } from 'elasticsearch-browser/elasticsearch'; -import { CoreStart, PackageInfo } from 'kibana/public'; -import { BehaviorSubject } from 'rxjs'; - -export function getEsClient({ - esRequestTimeout, - esApiVersion, - http, - packageVersion, -}: { - esRequestTimeout: number; - esApiVersion: string; - http: CoreStart['http']; - packageVersion: PackageInfo['version']; -}) { - // Use legacy es client for msearch. - const client = es.Client({ - host: getEsUrl(http, packageVersion), - log: 'info', - requestTimeout: esRequestTimeout, - apiVersion: esApiVersion, - }); - - const loadingCount$ = new BehaviorSubject(0); - http.addLoadingCountSource(loadingCount$); - - return { - search: wrapEsClientMethod(client, 'search', loadingCount$), - msearch: wrapEsClientMethod(client, 'msearch', loadingCount$), - create: wrapEsClientMethod(client, 'create', loadingCount$), - }; -} - -function wrapEsClientMethod(esClient: any, method: string, loadingCount$: BehaviorSubject) { - return (args: any) => { - // esClient returns a promise, with an additional abort handler - // To tap into the abort handling, we have to override that abort handler. - const customPromiseThingy = esClient[method](args); - const { abort } = customPromiseThingy; - let resolved = false; - - // Start LoadingIndicator - loadingCount$.next(loadingCount$.getValue() + 1); - - // Stop LoadingIndicator when user aborts - customPromiseThingy.abort = () => { - abort(); - if (!resolved) { - resolved = true; - loadingCount$.next(loadingCount$.getValue() - 1); - } - }; - - // Stop LoadingIndicator when promise finishes - customPromiseThingy.finally(() => { - resolved = true; - loadingCount$.next(loadingCount$.getValue() - 1); - }); - - return customPromiseThingy; - }; -} - -function getEsUrl(http: CoreStart['http'], packageVersion: PackageInfo['version']) { - const a = document.createElement('a'); - a.href = http.basePath.prepend('/elasticsearch'); - const protocolPort = /https/.test(a.protocol) ? 443 : 80; - const port = a.port || protocolPort; - return { - host: a.hostname, - port, - protocol: a.protocol, - pathname: a.pathname, - headers: { - 'kbn-version': packageVersion, - }, - }; -} diff --git a/src/plugins/data/public/search/legacy/es_client/index.ts b/src/plugins/data/public/search/legacy/es_client/index.ts deleted file mode 100644 index 78ac83af642d8..0000000000000 --- a/src/plugins/data/public/search/legacy/es_client/index.ts +++ /dev/null @@ -1,21 +0,0 @@ -/* - * 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 { getEsClient } from './get_es_client'; -export { LegacyApiCaller } from './types'; diff --git a/src/plugins/data/public/search/legacy/es_client/types.ts b/src/plugins/data/public/search/legacy/es_client/types.ts deleted file mode 100644 index 2d35188322a4e..0000000000000 --- a/src/plugins/data/public/search/legacy/es_client/types.ts +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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 { SearchResponse } from 'elasticsearch'; -import { SearchRequest } from '../../fetch'; - -export interface LegacyApiCaller { - search: (searchRequest: SearchRequest) => LegacyApiCallerResponse; - msearch: (searchRequest: SearchRequest) => LegacyApiCallerResponse; -} - -interface LegacyApiCallerResponse extends Promise> { - abort: () => void; -} diff --git a/src/plugins/data/public/search/legacy/index.ts b/src/plugins/data/public/search/legacy/index.ts index e2ae72824f3f4..74e516f407e8c 100644 --- a/src/plugins/data/public/search/legacy/index.ts +++ b/src/plugins/data/public/search/legacy/index.ts @@ -18,4 +18,3 @@ */ export { fetchSoon } from './fetch_soon'; -export { getEsClient, LegacyApiCaller } from './es_client'; From 24754673a6af24ae5a0b30c29d70a11dd8bd4d30 Mon Sep 17 00:00:00 2001 From: Luke Elmers Date: Tue, 25 Aug 2020 22:15:04 -0600 Subject: [PATCH 05/15] Handle msearch options on server. --- src/plugins/data/public/search/fetch/types.ts | 1 - .../legacy/default_search_strategy.test.ts | 59 ++++++----------- .../search/legacy/default_search_strategy.ts | 15 ++--- .../search/legacy/get_msearch_params.test.ts | 64 ------------------- .../search/legacy/get_msearch_params.ts | 29 --------- .../search/search_source/search_source.ts | 3 +- .../data/server/search/routes/msearch.test.ts | 53 ++++++++++----- .../data/server/search/routes/msearch.ts | 47 ++++++++++---- .../data/server/search/routes/search.test.ts | 21 ++++-- .../data/server/search/search_service.ts | 11 +++- 10 files changed, 121 insertions(+), 182 deletions(-) delete mode 100644 src/plugins/data/public/search/legacy/get_msearch_params.test.ts delete mode 100644 src/plugins/data/public/search/legacy/get_msearch_params.ts diff --git a/src/plugins/data/public/search/fetch/types.ts b/src/plugins/data/public/search/fetch/types.ts index 33a205b342ae8..ec10961225efa 100644 --- a/src/plugins/data/public/search/fetch/types.ts +++ b/src/plugins/data/public/search/fetch/types.ts @@ -36,7 +36,6 @@ export interface FetchOptions { export interface FetchHandlers { config: { get: GetConfigFn }; - esShardTimeout: number; http: HttpStart; } diff --git a/src/plugins/data/public/search/legacy/default_search_strategy.test.ts b/src/plugins/data/public/search/legacy/default_search_strategy.test.ts index f1eb88f1c5671..e0916b23a4b48 100644 --- a/src/plugins/data/public/search/legacy/default_search_strategy.test.ts +++ b/src/plugins/data/public/search/legacy/default_search_strategy.test.ts @@ -17,26 +17,18 @@ * under the License. */ -import { HttpStart, IUiSettingsClient } from 'src/core/public'; +import { HttpStart } from 'src/core/public'; import { coreMock } from '../../../../../core/public/mocks'; import { defaultSearchStrategy } from './default_search_strategy'; import { SearchStrategySearchParams } from './types'; -import { UI_SETTINGS } from '../../../common'; const { search } = defaultSearchStrategy; -function getConfigStub(config: any = {}) { - return { - get: (key) => config[key], - } as IUiSettingsClient; -} - const msearchMock = jest.fn().mockResolvedValue({ body: { responses: [] } }); describe('defaultSearchStrategy', function () { describe('search', function () { - let searchArgs: MockedKeys>; - let es: any; + let searchArgs: MockedKeys; let http: jest.Mocked; beforeEach(() => { @@ -51,41 +43,26 @@ describe('defaultSearchStrategy', function () { index: { title: 'foo' }, }, ], - esShardTimeout: 0, http, + config: { + get: jest.fn(), + }, }; - - es = http.post; - }); - - test('does not send max_concurrent_shard_requests by default', async () => { - const config = getConfigStub({ [UI_SETTINGS.COURIER_BATCH_SEARCHES]: true }); - await search({ ...searchArgs, config }); - expect(es.mock.calls[0][1].query.max_concurrent_shard_requests).toBe(undefined); - }); - - test('allows configuration of max_concurrent_shard_requests', async () => { - const config = getConfigStub({ - [UI_SETTINGS.COURIER_BATCH_SEARCHES]: true, - [UI_SETTINGS.COURIER_MAX_CONCURRENT_SHARD_REQUESTS]: 42, - }); - await search({ ...searchArgs, config }); - expect(es.mock.calls[0][1].query.max_concurrent_shard_requests).toBe(42); - }); - - test('should set rest_total_hits_as_int to true on a request', async () => { - const config = getConfigStub({ [UI_SETTINGS.COURIER_BATCH_SEARCHES]: true }); - await search({ ...searchArgs, config }); - expect(es.mock.calls[0][1].query).toHaveProperty('rest_total_hits_as_int', true); }); - test('should set ignore_throttled=false when including frozen indices', async () => { - const config = getConfigStub({ - [UI_SETTINGS.COURIER_BATCH_SEARCHES]: true, - [UI_SETTINGS.SEARCH_INCLUDE_FROZEN]: true, - }); - await search({ ...searchArgs, config }); - expect(es.mock.calls[0][1].query).toHaveProperty('ignore_throttled', false); + test('calls http.post with the correct arguments', async () => { + await search({ ...searchArgs }); + expect(http.post.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + "/internal/_msearch", + Object { + "body": "{\\"searches\\":[{\\"header\\":{\\"index\\":\\"foo\\"}}]}", + "signal": AbortSignal {}, + }, + ], + ] + `); }); }); }); diff --git a/src/plugins/data/public/search/legacy/default_search_strategy.ts b/src/plugins/data/public/search/legacy/default_search_strategy.ts index b32315163bb87..8e45715b7cc38 100644 --- a/src/plugins/data/public/search/legacy/default_search_strategy.ts +++ b/src/plugins/data/public/search/legacy/default_search_strategy.ts @@ -19,8 +19,7 @@ import { BehaviorSubject } from 'rxjs'; -import { getPreference, getTimeout } from '../fetch'; -import { getMSearchParams } from './get_msearch_params'; +import { getPreference } from '../fetch'; import { SearchStrategyProvider, SearchStrategySearchParams } from './types'; // @deprecated @@ -32,19 +31,14 @@ export const defaultSearchStrategy: SearchStrategyProvider = { }, }; -function msearch({ searchRequests, config, http, esShardTimeout }: SearchStrategySearchParams) { - const requests = searchRequests.map(({ index, body, search_type: searchType }) => { +function msearch({ searchRequests, config, http }: SearchStrategySearchParams) { + const requests = searchRequests.map(({ index, body }) => { return { header: { index: index.title || index, - ignore_unavailable: true, preference: getPreference(config.get), - search_type: searchType, - }, - body: { - ...body, - timeout: getTimeout(esShardTimeout), }, + body, }; }); @@ -67,7 +61,6 @@ function msearch({ searchRequests, config, http, esShardTimeout }: SearchStrateg }; const searching = http.post('/internal/_msearch', { - query: getMSearchParams(config.get), body: JSON.stringify({ searches: requests }), signal: abortController.signal, }); diff --git a/src/plugins/data/public/search/legacy/get_msearch_params.test.ts b/src/plugins/data/public/search/legacy/get_msearch_params.test.ts deleted file mode 100644 index d3206950174c8..0000000000000 --- a/src/plugins/data/public/search/legacy/get_msearch_params.test.ts +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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 { getMSearchParams } from './get_msearch_params'; -import { GetConfigFn, UI_SETTINGS } from '../../../common'; - -function getConfigStub(config: any = {}): GetConfigFn { - return (key) => config[key]; -} - -describe('getMSearchParams', () => { - test('includes rest_total_hits_as_int', () => { - const config = getConfigStub(); - const msearchParams = getMSearchParams(config); - expect(msearchParams.rest_total_hits_as_int).toBe(true); - }); - - test('includes ignore_throttled according to search:includeFrozen', () => { - let config = getConfigStub({ [UI_SETTINGS.SEARCH_INCLUDE_FROZEN]: true }); - let msearchParams = getMSearchParams(config); - expect(msearchParams.ignore_throttled).toBe(false); - - config = getConfigStub({ [UI_SETTINGS.SEARCH_INCLUDE_FROZEN]: false }); - msearchParams = getMSearchParams(config); - expect(msearchParams.ignore_throttled).toBe(true); - }); - - test('includes max_concurrent_shard_requests according to courier:maxConcurrentShardRequests if greater than 0', () => { - let config = getConfigStub({ [UI_SETTINGS.COURIER_MAX_CONCURRENT_SHARD_REQUESTS]: 0 }); - let msearchParams = getMSearchParams(config); - expect(msearchParams.max_concurrent_shard_requests).toBe(undefined); - - config = getConfigStub({ [UI_SETTINGS.COURIER_MAX_CONCURRENT_SHARD_REQUESTS]: 5 }); - msearchParams = getMSearchParams(config); - expect(msearchParams.max_concurrent_shard_requests).toBe(5); - }); - - test('does not include other search params that are included in the msearch header or body', () => { - const config = getConfigStub({ - [UI_SETTINGS.SEARCH_INCLUDE_FROZEN]: false, - [UI_SETTINGS.COURIER_MAX_CONCURRENT_SHARD_REQUESTS]: 5, - }); - const msearchParams = getMSearchParams(config); - expect(msearchParams.hasOwnProperty('ignore_unavailable')).toBe(false); - expect(msearchParams.hasOwnProperty('preference')).toBe(false); - expect(msearchParams.hasOwnProperty('timeout')).toBe(false); - }); -}); diff --git a/src/plugins/data/public/search/legacy/get_msearch_params.ts b/src/plugins/data/public/search/legacy/get_msearch_params.ts deleted file mode 100644 index c4f77b25078cd..0000000000000 --- a/src/plugins/data/public/search/legacy/get_msearch_params.ts +++ /dev/null @@ -1,29 +0,0 @@ -/* - * 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 { GetConfigFn } from '../../../common'; -import { getIgnoreThrottled, getMaxConcurrentShardRequests } from '../fetch'; - -export function getMSearchParams(getConfig: GetConfigFn) { - return { - rest_total_hits_as_int: true, - ignore_throttled: getIgnoreThrottled(getConfig), - max_concurrent_shard_requests: getMaxConcurrentShardRequests(getConfig), - }; -} diff --git a/src/plugins/data/public/search/search_source/search_source.ts b/src/plugins/data/public/search/search_source/search_source.ts index ae6817510feaf..2bd66abca80d4 100644 --- a/src/plugins/data/public/search/search_source/search_source.ts +++ b/src/plugins/data/public/search/search_source/search_source.ts @@ -243,7 +243,7 @@ export class SearchSource { * @return {Promise>} */ private async legacyFetch(searchRequest: SearchRequest, options: FetchOptions) { - const { esShardTimeout, http, getConfig } = this.dependencies; + const { http, getConfig } = this.dependencies; return await fetchSoon( searchRequest, @@ -254,7 +254,6 @@ export class SearchSource { { http, config: { get: getConfig }, - esShardTimeout, } ); } diff --git a/src/plugins/data/server/search/routes/msearch.test.ts b/src/plugins/data/server/search/routes/msearch.test.ts index 3764a37a12ddf..0a52cf23c5472 100644 --- a/src/plugins/data/server/search/routes/msearch.test.ts +++ b/src/plugins/data/server/search/routes/msearch.test.ts @@ -17,8 +17,19 @@ * under the License. */ -import { CoreSetup, RequestHandlerContext, StartServicesAccessor } from 'src/core/server'; -import { coreMock, httpServerMock } from '../../../../../../src/core/server/mocks'; +import { Observable } from 'rxjs'; + +import { + CoreSetup, + RequestHandlerContext, + SharedGlobalConfig, + StartServicesAccessor, +} from 'src/core/server'; +import { + coreMock, + httpServerMock, + pluginInitializerContextConfigMock, +} from '../../../../../../src/core/server/mocks'; import { registerMsearchRoute, convertRequestBody } from './msearch'; import { DataPluginStart } from '../../plugin'; import { dataPluginMock } from '../../mocks'; @@ -27,17 +38,24 @@ describe('msearch route', () => { let mockDataStart: MockedKeys; let mockCoreSetup: MockedKeys>; let getStartServices: jest.Mocked>; + let globalConfig$: Observable; beforeEach(() => { mockDataStart = dataPluginMock.createStartContract(); mockCoreSetup = coreMock.createSetup({ pluginStartContract: mockDataStart }); getStartServices = mockCoreSetup.getStartServices; + globalConfig$ = pluginInitializerContextConfigMock({}).legacy.globalConfig$; }); it('handler calls /_msearch with the given request', async () => { const response = { id: 'yay' }; const mockClient = { transport: { request: jest.fn().mockResolvedValue(response) } }; - const mockContext = { core: { elasticsearch: { client: { asCurrentUser: mockClient } } } }; + const mockContext = { + core: { + elasticsearch: { client: { asCurrentUser: mockClient } }, + uiSettings: { client: { get: jest.fn() } }, + }, + }; const mockBody = { searches: [{ header: {}, body: {} }] }; const mockQuery = {}; const mockRequest = httpServerMock.createKibanaRequest({ @@ -46,7 +64,7 @@ describe('msearch route', () => { }); const mockResponse = httpServerMock.createResponseFactory(); - registerMsearchRoute(mockCoreSetup.http.createRouter(), { getStartServices }); + registerMsearchRoute(mockCoreSetup.http.createRouter(), { getStartServices, globalConfig$ }); const mockRouter = mockCoreSetup.http.createRouter.mock.results[0].value; const handler = mockRouter.post.mock.calls[0][1]; @@ -55,7 +73,7 @@ describe('msearch route', () => { expect(mockClient.transport.request.mock.calls[0][0].method).toBe('GET'); expect(mockClient.transport.request.mock.calls[0][0].path).toBe('/_msearch'); expect(mockClient.transport.request.mock.calls[0][0].body).toEqual( - convertRequestBody(mockBody as any) + convertRequestBody(mockBody as any, { timeout: '0ms' }) ); expect(mockResponse.ok).toBeCalled(); expect(mockResponse.ok.mock.calls[0][0]).toEqual({ @@ -73,7 +91,12 @@ describe('msearch route', () => { const mockClient = { transport: { request: jest.fn().mockReturnValue(Promise.reject(response)) }, }; - const mockContext = { core: { elasticsearch: { client: { asCurrentUser: mockClient } } } }; + const mockContext = { + core: { + elasticsearch: { client: { asCurrentUser: mockClient } }, + uiSettings: { client: { get: jest.fn() } }, + }, + }; const mockBody = { searches: [{ header: {}, body: {} }] }; const mockQuery = {}; const mockRequest = httpServerMock.createKibanaRequest({ @@ -82,7 +105,7 @@ describe('msearch route', () => { }); const mockResponse = httpServerMock.createResponseFactory(); - registerMsearchRoute(mockCoreSetup.http.createRouter(), { getStartServices }); + registerMsearchRoute(mockCoreSetup.http.createRouter(), { getStartServices, globalConfig$ }); const mockRouter = mockCoreSetup.http.createRouter.mock.results[0].value; const handler = mockRouter.post.mock.calls[0][1]; @@ -101,9 +124,9 @@ describe('msearch route', () => { const request = { searches: [{ header: { index: 'foo', preference: 0 }, body: { test: true } }], }; - expect(convertRequestBody(request)).toMatchInlineSnapshot(` - "{\\"index\\":\\"foo\\",\\"preference\\":0} - {\\"test\\":true} + expect(convertRequestBody(request, { timeout: '30000ms' })).toMatchInlineSnapshot(` + "{\\"ignore_unavailable\\":true,\\"index\\":\\"foo\\",\\"preference\\":0} + {\\"timeout\\":\\"30000ms\\",\\"test\\":true} " `); }); @@ -115,11 +138,11 @@ describe('msearch route', () => { { header: { index: 'bar', preference: 1 }, body: { hello: 'world' } }, ], }; - expect(convertRequestBody(request)).toMatchInlineSnapshot(` - "{\\"index\\":\\"foo\\",\\"preference\\":0} - {\\"test\\":true} - {\\"index\\":\\"bar\\",\\"preference\\":1} - {\\"hello\\":\\"world\\"} + expect(convertRequestBody(request, { timeout: '30000ms' })).toMatchInlineSnapshot(` + "{\\"ignore_unavailable\\":true,\\"index\\":\\"foo\\",\\"preference\\":0} + {\\"timeout\\":\\"30000ms\\",\\"test\\":true} + {\\"ignore_unavailable\\":true,\\"index\\":\\"bar\\",\\"preference\\":1} + {\\"timeout\\":\\"30000ms\\",\\"hello\\":\\"world\\"} " `); }); diff --git a/src/plugins/data/server/search/routes/msearch.ts b/src/plugins/data/server/search/routes/msearch.ts index 6a15b707aae48..dce2fb0f30e8f 100644 --- a/src/plugins/data/server/search/routes/msearch.ts +++ b/src/plugins/data/server/search/routes/msearch.ts @@ -17,9 +17,13 @@ * under the License. */ +import { first } from 'rxjs/operators'; import { schema } from '@kbn/config-schema'; + import { IRouter } from 'src/core/server'; +import { UI_SETTINGS } from '../../../common'; import { SearchRouteDependencies } from '../search_service'; +import { getDefaultSearchParams } from '..'; interface MsearchHeaders { index: string; @@ -36,10 +40,19 @@ interface RequestBody { } /** @internal */ -export function convertRequestBody(requestBody: RequestBody): string { +export function convertRequestBody( + requestBody: RequestBody, + { timeout }: { timeout?: string } +): string { return requestBody.searches.reduce((req, curr) => { - const header = JSON.stringify({ ...curr.header }); - const body = JSON.stringify({ ...curr.body }); + const header = JSON.stringify({ + ignore_unavailable: true, + ...curr.header, + }); + const body = JSON.stringify({ + timeout, + ...curr.body, + }); req += `${header}\n${body}\n`; return req; }, ''); @@ -77,26 +90,34 @@ export function registerMsearchRoute(router: IRouter, deps: SearchRouteDependenc }) ), }), - query: schema.object({ - // We don't use `schema.boolean` here, because all query string parameters are treated as - // strings and @kbn/config-schema doesn't coerce strings to booleans. - ignore_throttled: schema.oneOf([schema.literal('true'), schema.literal('false')]), - rest_total_hits_as_int: schema.oneOf([schema.literal('true'), schema.literal('false')]), - max_concurrent_shard_requests: schema.maybe(schema.number()), - }), }, }, async (context, request, res) => { const client = context.core.elasticsearch.client.asCurrentUser; - const body = convertRequestBody(request.body); - const querystring = request.query; + + // get shardTimeout + const config = await deps.globalConfig$.pipe(first()).toPromise(); + const { timeout } = getDefaultSearchParams(config); + + const body = convertRequestBody(request.body, { timeout }); try { + const ignoreThrottled = !(await context.core.uiSettings.client.get( + UI_SETTINGS.SEARCH_INCLUDE_FROZEN + )); + const maxConcurrentShardRequests = await context.core.uiSettings.client.get( + UI_SETTINGS.COURIER_MAX_CONCURRENT_SHARD_REQUESTS + ); const response = await client.transport.request({ method: 'GET', path: '/_msearch', body, - querystring, + querystring: { + rest_total_hits_as_int: true, + ignore_throttled: ignoreThrottled, + max_concurrent_shard_requests: + maxConcurrentShardRequests > 0 ? maxConcurrentShardRequests : undefined, + }, }); return res.ok({ body: response }); diff --git a/src/plugins/data/server/search/routes/search.test.ts b/src/plugins/data/server/search/routes/search.test.ts index a9c1b4427c2a1..e2518acd7d505 100644 --- a/src/plugins/data/server/search/routes/search.test.ts +++ b/src/plugins/data/server/search/routes/search.test.ts @@ -17,8 +17,19 @@ * under the License. */ -import { CoreSetup, RequestHandlerContext, StartServicesAccessor } from 'src/core/server'; -import { coreMock, httpServerMock } from '../../../../../../src/core/server/mocks'; +import { Observable } from 'rxjs'; + +import { + CoreSetup, + RequestHandlerContext, + SharedGlobalConfig, + StartServicesAccessor, +} from 'src/core/server'; +import { + coreMock, + httpServerMock, + pluginInitializerContextConfigMock, +} from '../../../../../../src/core/server/mocks'; import { registerSearchRoute } from './search'; import { DataPluginStart } from '../../plugin'; import { dataPluginMock } from '../../mocks'; @@ -27,11 +38,13 @@ describe('Search service', () => { let mockDataStart: MockedKeys; let mockCoreSetup: MockedKeys>; let getStartServices: jest.Mocked>; + let globalConfig$: Observable; beforeEach(() => { mockDataStart = dataPluginMock.createStartContract(); mockCoreSetup = coreMock.createSetup({ pluginStartContract: mockDataStart }); getStartServices = mockCoreSetup.getStartServices; + globalConfig$ = pluginInitializerContextConfigMock({}).legacy.globalConfig$; }); it('handler calls context.search.search with the given request and strategy', async () => { @@ -46,7 +59,7 @@ describe('Search service', () => { }); const mockResponse = httpServerMock.createResponseFactory(); - registerSearchRoute(mockCoreSetup.http.createRouter(), { getStartServices }); + registerSearchRoute(mockCoreSetup.http.createRouter(), { getStartServices, globalConfig$ }); const mockRouter = mockCoreSetup.http.createRouter.mock.results[0].value; const handler = mockRouter.post.mock.calls[0][1]; @@ -77,7 +90,7 @@ describe('Search service', () => { }); const mockResponse = httpServerMock.createResponseFactory(); - registerSearchRoute(mockCoreSetup.http.createRouter(), { getStartServices }); + registerSearchRoute(mockCoreSetup.http.createRouter(), { getStartServices, globalConfig$ }); const mockRouter = mockCoreSetup.http.createRouter.mock.results[0].value; const handler = mockRouter.post.mock.calls[0][1]; diff --git a/src/plugins/data/server/search/search_service.ts b/src/plugins/data/server/search/search_service.ts index 80129c0429ba0..beb13c3ec59d6 100644 --- a/src/plugins/data/server/search/search_service.ts +++ b/src/plugins/data/server/search/search_service.ts @@ -17,6 +17,7 @@ * under the License. */ +import { Observable } from 'rxjs'; import { CoreSetup, CoreStart, @@ -24,6 +25,7 @@ import { Plugin, PluginInitializerContext, RequestHandlerContext, + SharedGlobalConfig, StartServicesAccessor, } from 'src/core/server'; import { ISearchSetup, ISearchStart, ISearchStrategy, SearchEnhancements } from './types'; @@ -59,6 +61,7 @@ export interface SearchServiceStartDependencies { /** @internal */ export interface SearchRouteDependencies { getStartServices: StartServicesAccessor<{}, DataPluginStart>; + globalConfig$: Observable; } export class SearchService implements Plugin { @@ -78,8 +81,12 @@ export class SearchService implements Plugin { const usage = usageCollection ? usageProvider(core) : undefined; const router = core.http.createRouter(); - registerSearchRoute(router, { getStartServices: core.getStartServices }); - registerMsearchRoute(router, { getStartServices: core.getStartServices }); + const routeDependencies = { + getStartServices: core.getStartServices, + globalConfig$: this.initializerContext.config.legacy.globalConfig$, + }; + registerSearchRoute(router, routeDependencies); + registerMsearchRoute(router, routeDependencies); this.registerSearchStrategy( ES_SEARCH_STRATEGY, From 775586ac7e7bcd0f8e66bd06fd23d41878be09b7 Mon Sep 17 00:00:00 2001 From: Luke Elmers Date: Tue, 25 Aug 2020 22:21:35 -0600 Subject: [PATCH 06/15] Remove elasticsearch-browser dependency. --- package.json | 1 - packages/kbn-optimizer/src/worker/webpack.config.ts | 1 - packages/kbn-ui-shared-deps/entry.js | 3 --- packages/kbn-ui-shared-deps/index.js | 7 ------- packages/kbn-ui-shared-deps/package.json | 1 - yarn.lock | 5 ----- 6 files changed, 18 deletions(-) diff --git a/package.json b/package.json index 84f6f30f064f9..5b8b38e2650bf 100644 --- a/package.json +++ b/package.json @@ -362,7 +362,6 @@ "dedent": "^0.7.0", "deepmerge": "^4.2.2", "delete-empty": "^2.0.0", - "elasticsearch-browser": "^16.7.0", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.2", "enzyme-adapter-utils": "^1.13.0", diff --git a/packages/kbn-optimizer/src/worker/webpack.config.ts b/packages/kbn-optimizer/src/worker/webpack.config.ts index 6b07384910abb..9f2c5654a8bd4 100644 --- a/packages/kbn-optimizer/src/worker/webpack.config.ts +++ b/packages/kbn-optimizer/src/worker/webpack.config.ts @@ -79,7 +79,6 @@ export function getWebpackConfig(bundle: Bundle, bundleRefs: BundleRefs, worker: // or which have require() statements that should be ignored because the file is // already bundled with all its necessary depedencies noParse: [ - /[\/\\]node_modules[\/\\]elasticsearch-browser[\/\\]/, /[\/\\]node_modules[\/\\]lodash[\/\\]index\.js$/, /[\/\\]node_modules[\/\\]vega[\/\\]build[\/\\]vega\.js$/, ], diff --git a/packages/kbn-ui-shared-deps/entry.js b/packages/kbn-ui-shared-deps/entry.js index 0f981f3d07610..365b84b83bd5f 100644 --- a/packages/kbn-ui-shared-deps/entry.js +++ b/packages/kbn-ui-shared-deps/entry.js @@ -54,6 +54,3 @@ export const ElasticEuiChartsTheme = require('@elastic/eui/dist/eui_charts_theme import * as Theme from './theme.ts'; export { Theme }; - -// massive deps that we should really get rid of or reduce in size substantially -export const ElasticsearchBrowser = require('elasticsearch-browser/elasticsearch.js'); diff --git a/packages/kbn-ui-shared-deps/index.js b/packages/kbn-ui-shared-deps/index.js index 40e89f199b6a1..84ca3435e02bc 100644 --- a/packages/kbn-ui-shared-deps/index.js +++ b/packages/kbn-ui-shared-deps/index.js @@ -62,12 +62,5 @@ exports.externals = { '@elastic/eui/dist/eui_charts_theme': '__kbnSharedDeps__.ElasticEuiChartsTheme', '@elastic/eui/dist/eui_theme_light.json': '__kbnSharedDeps__.Theme.euiLightVars', '@elastic/eui/dist/eui_theme_dark.json': '__kbnSharedDeps__.Theme.euiDarkVars', - - /** - * massive deps that we should really get rid of or reduce in size substantially - */ - elasticsearch: '__kbnSharedDeps__.ElasticsearchBrowser', - 'elasticsearch-browser': '__kbnSharedDeps__.ElasticsearchBrowser', - 'elasticsearch-browser/elasticsearch': '__kbnSharedDeps__.ElasticsearchBrowser', }; exports.publicPathLoader = require.resolve('./public_path_loader'); diff --git a/packages/kbn-ui-shared-deps/package.json b/packages/kbn-ui-shared-deps/package.json index 531513481b1d4..96f05c42df589 100644 --- a/packages/kbn-ui-shared-deps/package.json +++ b/packages/kbn-ui-shared-deps/package.json @@ -19,7 +19,6 @@ "compression-webpack-plugin": "^4.0.0", "core-js": "^3.6.4", "custom-event-polyfill": "^0.3.0", - "elasticsearch-browser": "^16.7.0", "jquery": "^3.5.0", "mini-css-extract-plugin": "0.8.0", "moment": "^2.24.0", diff --git a/yarn.lock b/yarn.lock index 845685ff36f7d..3af2990639c0e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11247,11 +11247,6 @@ elastic-apm-node@^3.7.0: traceparent "^1.0.0" unicode-byte-truncate "^1.0.0" -elasticsearch-browser@^16.7.0: - version "16.7.0" - resolved "https://registry.yarnpkg.com/elasticsearch-browser/-/elasticsearch-browser-16.7.0.tgz#1f32a402cd36a9bb14a9ea6cb70f8e126d4cb9b1" - integrity sha512-UES2Fbnzy4Ivq4QvES4sfk/a5UytJczeJdfxRWa4kuHEllKOffKQLTxJ8Ti86OREpACQxppqvYgzctJuEiIr7Q== - elasticsearch@^16.4.0: version "16.5.0" resolved "https://registry.yarnpkg.com/elasticsearch/-/elasticsearch-16.5.0.tgz#619a48040be25d345fdddf09fa6042a88c3974d6" From d7df81e3d3cb55a0f9c2d7196f9872f4ff35f1bd Mon Sep 17 00:00:00 2001 From: Luke Elmers Date: Tue, 25 Aug 2020 22:46:15 -0600 Subject: [PATCH 07/15] Update generated docs. --- src/plugins/data/public/public.api.md | 1 + src/plugins/data/server/server.api.md | 133 +------------------------- 2 files changed, 5 insertions(+), 129 deletions(-) diff --git a/src/plugins/data/public/public.api.md b/src/plugins/data/public/public.api.md index 261f16229460a..31c8279f91bcd 100644 --- a/src/plugins/data/public/public.api.md +++ b/src/plugins/data/public/public.api.md @@ -29,6 +29,7 @@ import { ExpressionsSetup } from 'src/plugins/expressions/public'; import { FetchOptions as FetchOptions_2 } from 'src/plugins/data/public'; import { History } from 'history'; import { Href } from 'history'; +import { HttpStart } from 'src/core/public'; import { IconType } from '@elastic/eui'; import { InjectedIntl } from '@kbn/i18n/react'; import { ISearchSource as ISearchSource_2 } from 'src/plugins/data/public'; diff --git a/src/plugins/data/server/server.api.md b/src/plugins/data/server/server.api.md index 9f114f2132009..f2ba1d09b9bad 100644 --- a/src/plugins/data/server/server.api.md +++ b/src/plugins/data/server/server.api.md @@ -5,163 +5,40 @@ ```ts import { $Values } from '@kbn/utility-types'; -import { ApiResponse } from '@elastic/elasticsearch/lib/Transport'; import { Assign } from '@kbn/utility-types'; -import Boom from 'boom'; -import { BulkIndexDocumentsParams } from 'elasticsearch'; -import { CatAliasesParams } from 'elasticsearch'; -import { CatAllocationParams } from 'elasticsearch'; -import { CatCommonParams } from 'elasticsearch'; -import { CatFielddataParams } from 'elasticsearch'; -import { CatHealthParams } from 'elasticsearch'; -import { CatHelpParams } from 'elasticsearch'; -import { CatIndicesParams } from 'elasticsearch'; -import { CatRecoveryParams } from 'elasticsearch'; -import { CatSegmentsParams } from 'elasticsearch'; -import { CatShardsParams } from 'elasticsearch'; -import { CatSnapshotsParams } from 'elasticsearch'; -import { CatTasksParams } from 'elasticsearch'; -import { CatThreadPoolParams } from 'elasticsearch'; -import { ClearScrollParams } from 'elasticsearch'; -import { Client } from 'elasticsearch'; -import { ClusterAllocationExplainParams } from 'elasticsearch'; -import { ClusterGetSettingsParams } from 'elasticsearch'; -import { ClusterHealthParams } from 'elasticsearch'; -import { ClusterPendingTasksParams } from 'elasticsearch'; -import { ClusterPutSettingsParams } from 'elasticsearch'; -import { ClusterRerouteParams } from 'elasticsearch'; -import { ClusterStateParams } from 'elasticsearch'; -import { ClusterStatsParams } from 'elasticsearch'; import { CoreSetup } from 'src/core/server'; import { CoreSetup as CoreSetup_2 } from 'kibana/server'; import { CoreStart } from 'src/core/server'; -import { CountParams } from 'elasticsearch'; -import { CreateDocumentParams } from 'elasticsearch'; -import { DeleteDocumentByQueryParams } from 'elasticsearch'; -import { DeleteDocumentParams } from 'elasticsearch'; -import { DeleteScriptParams } from 'elasticsearch'; -import { DeleteTemplateParams } from 'elasticsearch'; import { Duration } from 'moment'; import { Ensure } from '@kbn/utility-types'; import { ErrorToastOptions } from 'src/core/public/notifications'; -import { ExistsParams } from 'elasticsearch'; -import { ExplainParams } from 'elasticsearch'; import { ExpressionAstFunction } from 'src/plugins/expressions/common'; import { ExpressionsServerSetup } from 'src/plugins/expressions/server'; import { FetchOptions } from 'src/plugins/data/public'; -import { FieldStatsParams } from 'elasticsearch'; -import { GenericParams } from 'elasticsearch'; -import { GetParams } from 'elasticsearch'; -import { GetResponse } from 'elasticsearch'; -import { GetScriptParams } from 'elasticsearch'; -import { GetSourceParams } from 'elasticsearch'; -import { GetTemplateParams } from 'elasticsearch'; -import { IncomingHttpHeaders } from 'http'; -import { IndexDocumentParams } from 'elasticsearch'; -import { IndicesAnalyzeParams } from 'elasticsearch'; -import { IndicesClearCacheParams } from 'elasticsearch'; -import { IndicesCloseParams } from 'elasticsearch'; -import { IndicesCreateParams } from 'elasticsearch'; -import { IndicesDeleteAliasParams } from 'elasticsearch'; -import { IndicesDeleteParams } from 'elasticsearch'; -import { IndicesDeleteTemplateParams } from 'elasticsearch'; -import { IndicesExistsAliasParams } from 'elasticsearch'; -import { IndicesExistsParams } from 'elasticsearch'; -import { IndicesExistsTemplateParams } from 'elasticsearch'; -import { IndicesExistsTypeParams } from 'elasticsearch'; -import { IndicesFlushParams } from 'elasticsearch'; -import { IndicesFlushSyncedParams } from 'elasticsearch'; -import { IndicesForcemergeParams } from 'elasticsearch'; -import { IndicesGetAliasParams } from 'elasticsearch'; -import { IndicesGetFieldMappingParams } from 'elasticsearch'; -import { IndicesGetMappingParams } from 'elasticsearch'; -import { IndicesGetParams } from 'elasticsearch'; -import { IndicesGetSettingsParams } from 'elasticsearch'; -import { IndicesGetTemplateParams } from 'elasticsearch'; -import { IndicesGetUpgradeParams } from 'elasticsearch'; -import { IndicesOpenParams } from 'elasticsearch'; -import { IndicesPutAliasParams } from 'elasticsearch'; -import { IndicesPutMappingParams } from 'elasticsearch'; -import { IndicesPutSettingsParams } from 'elasticsearch'; -import { IndicesPutTemplateParams } from 'elasticsearch'; -import { IndicesRecoveryParams } from 'elasticsearch'; -import { IndicesRefreshParams } from 'elasticsearch'; -import { IndicesRolloverParams } from 'elasticsearch'; -import { IndicesSegmentsParams } from 'elasticsearch'; -import { IndicesShardStoresParams } from 'elasticsearch'; -import { IndicesShrinkParams } from 'elasticsearch'; -import { IndicesStatsParams } from 'elasticsearch'; -import { IndicesUpdateAliasesParams } from 'elasticsearch'; -import { IndicesUpgradeParams } from 'elasticsearch'; -import { IndicesValidateQueryParams } from 'elasticsearch'; -import { InfoParams } from 'elasticsearch'; -import { IngestDeletePipelineParams } from 'elasticsearch'; -import { IngestGetPipelineParams } from 'elasticsearch'; -import { IngestPutPipelineParams } from 'elasticsearch'; -import { IngestSimulateParams } from 'elasticsearch'; import { ISearchSource } from 'src/plugins/data/public'; -import { KibanaClient } from '@elastic/elasticsearch/api/kibana'; -import { KibanaConfigType as KibanaConfigType_2 } from 'src/core/server/kibana_config'; import { KibanaRequest } from 'kibana/server'; -import { LegacyAPICaller as LegacyAPICaller_2 } from 'kibana/server'; +import { LegacyAPICaller } from 'kibana/server'; import { Logger as Logger_2 } from 'kibana/server'; -import { MGetParams } from 'elasticsearch'; -import { MGetResponse } from 'elasticsearch'; import { Moment } from 'moment'; import moment from 'moment'; -import { MSearchParams } from 'elasticsearch'; -import { MSearchResponse } from 'elasticsearch'; -import { MSearchTemplateParams } from 'elasticsearch'; -import { MTermVectorsParams } from 'elasticsearch'; -import { NodesHotThreadsParams } from 'elasticsearch'; -import { NodesInfoParams } from 'elasticsearch'; -import { NodesStatsParams } from 'elasticsearch'; import { Observable } from 'rxjs'; -import { PingParams } from 'elasticsearch'; import { Plugin as Plugin_2 } from 'src/core/server'; import { PluginInitializerContext as PluginInitializerContext_2 } from 'src/core/server'; -import { PutScriptParams } from 'elasticsearch'; -import { PutTemplateParams } from 'elasticsearch'; import { RecursiveReadonly } from '@kbn/utility-types'; -import { ReindexParams } from 'elasticsearch'; -import { ReindexRethrottleParams } from 'elasticsearch'; -import { RenderSearchTemplateParams } from 'elasticsearch'; import { RequestAdapter } from 'src/plugins/inspector/common'; +import { RequestHandlerContext } from 'src/core/server'; import { RequestStatistics } from 'src/plugins/inspector/common'; import { SavedObject } from 'src/core/server'; -import { SavedObjectsClientContract as SavedObjectsClientContract_2 } from 'src/core/server'; -import { ScrollParams } from 'elasticsearch'; +import { SavedObjectsClientContract } from 'src/core/server'; import { Search } from '@elastic/elasticsearch/api/requestParams'; -import { SearchParams } from 'elasticsearch'; import { SearchResponse } from 'elasticsearch'; -import { SearchShardsParams } from 'elasticsearch'; -import { SearchTemplateParams } from 'elasticsearch'; import { SerializedFieldFormat as SerializedFieldFormat_2 } from 'src/plugins/expressions/common'; import { ShardsResponse } from 'elasticsearch'; -import { SnapshotCreateParams } from 'elasticsearch'; -import { SnapshotCreateRepositoryParams } from 'elasticsearch'; -import { SnapshotDeleteParams } from 'elasticsearch'; -import { SnapshotDeleteRepositoryParams } from 'elasticsearch'; -import { SnapshotGetParams } from 'elasticsearch'; -import { SnapshotGetRepositoryParams } from 'elasticsearch'; -import { SnapshotRestoreParams } from 'elasticsearch'; -import { SnapshotStatusParams } from 'elasticsearch'; -import { SnapshotVerifyRepositoryParams } from 'elasticsearch'; -import { SuggestParams } from 'elasticsearch'; -import { TasksCancelParams } from 'elasticsearch'; -import { TasksGetParams } from 'elasticsearch'; -import { TasksListParams } from 'elasticsearch'; -import { TermvectorsParams } from 'elasticsearch'; import { ToastInputFields } from 'src/core/public/notifications'; -import { TransportRequestOptions } from '@elastic/elasticsearch/lib/Transport'; -import { TransportRequestParams } from '@elastic/elasticsearch/lib/Transport'; -import { TransportRequestPromise } from '@elastic/elasticsearch/lib/Transport'; import { Type } from '@kbn/config-schema'; import { TypeOf } from '@kbn/config-schema'; import { Unit } from '@elastic/datemath'; import { UnwrapPromiseOrReturn } from '@kbn/utility-types'; -import { UpdateDocumentByQueryParams } from 'elasticsearch'; -import { UpdateDocumentParams } from 'elasticsearch'; // Warning: (ae-forgotten-export) The symbol "AggConfigSerialized" needs to be exported by the entry point index.d.ts // Warning: (ae-missing-release-tag) "AggConfigOptions" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) @@ -659,7 +536,7 @@ export const indexPatterns: { // // @public (undocumented) export class IndexPatternsFetcher { - constructor(callDataCluster: LegacyAPICaller_2); + constructor(callDataCluster: LegacyAPICaller); getFieldsForTimePattern(options: { pattern: string; metaFields: string[]; @@ -706,8 +583,6 @@ export interface ISearchStart ISearchStrategy; - // Warning: (ae-forgotten-export) The symbol "RequestHandlerContext" needs to be exported by the entry point index.d.ts - // // (undocumented) search: (context: RequestHandlerContext, request: IKibanaSearchRequest, options: ISearchOptions) => Promise; } From 260d23c63abf3db9325cb362d90e3cc97bc7eea8 Mon Sep 17 00:00:00 2001 From: Liza K Date: Thu, 27 Aug 2020 12:41:08 +0300 Subject: [PATCH 08/15] Code review fixes --- src/plugins/data/public/search/fetch/types.ts | 2 ++ .../search/legacy/default_search_strategy.ts | 15 +++++---------- .../data/public/search/search_interceptor.ts | 5 +++-- src/plugins/data/public/search/search_service.ts | 6 ++++++ .../public/search/search_source/search_source.ts | 6 +++++- 5 files changed, 21 insertions(+), 13 deletions(-) diff --git a/src/plugins/data/public/search/fetch/types.ts b/src/plugins/data/public/search/fetch/types.ts index ec10961225efa..7560f2516bbc6 100644 --- a/src/plugins/data/public/search/fetch/types.ts +++ b/src/plugins/data/public/search/fetch/types.ts @@ -19,6 +19,7 @@ import { HttpStart } from 'src/core/public'; import { GetConfigFn } from '../../../common'; +import { BehaviorSubject } from 'rxjs'; /** * @internal @@ -37,6 +38,7 @@ export interface FetchOptions { export interface FetchHandlers { config: { get: GetConfigFn }; http: HttpStart; + loadingCount$: BehaviorSubject; } export interface SearchError { diff --git a/src/plugins/data/public/search/legacy/default_search_strategy.ts b/src/plugins/data/public/search/legacy/default_search_strategy.ts index 8e45715b7cc38..d491846d8929c 100644 --- a/src/plugins/data/public/search/legacy/default_search_strategy.ts +++ b/src/plugins/data/public/search/legacy/default_search_strategy.ts @@ -17,8 +17,6 @@ * under the License. */ -import { BehaviorSubject } from 'rxjs'; - import { getPreference } from '../fetch'; import { SearchStrategyProvider, SearchStrategySearchParams } from './types'; @@ -31,7 +29,7 @@ export const defaultSearchStrategy: SearchStrategyProvider = { }, }; -function msearch({ searchRequests, config, http }: SearchStrategySearchParams) { +function msearch({ searchRequests, config, http, loadingCount$ }: SearchStrategySearchParams) { const requests = searchRequests.map(({ index, body }) => { return { header: { @@ -45,9 +43,6 @@ function msearch({ searchRequests, config, http }: SearchStrategySearchParams) { const abortController = new AbortController(); let resolved = false; - const loadingCount$ = new BehaviorSubject(0); - http.addLoadingCountSource(loadingCount$); - // Start LoadingIndicator loadingCount$.next(loadingCount$.getValue() + 1); @@ -63,15 +58,15 @@ function msearch({ searchRequests, config, http }: SearchStrategySearchParams) { const searching = http.post('/internal/_msearch', { body: JSON.stringify({ searches: requests }), signal: abortController.signal, - }); - - searching.finally(() => cleanup()); + }) + .then(({ body }) => body?.responses) + .finally(() => cleanup()); return { abort: () => { abortController.abort(); cleanup(); }, - searching: searching.then(({ body }) => body?.responses), + searching, }; } diff --git a/src/plugins/data/public/search/search_interceptor.ts b/src/plugins/data/public/search/search_interceptor.ts index 30e509edd4987..51f7039a694eb 100644 --- a/src/plugins/data/public/search/search_interceptor.ts +++ b/src/plugins/data/public/search/search_interceptor.ts @@ -34,6 +34,7 @@ export interface SearchInterceptorDeps { http: CoreSetup['http']; uiSettings: CoreSetup['uiSettings']; startServices: Promise<[CoreStart, any, unknown]>; + loadingCount$: BehaviorSubject; usageCollector?: SearchUsageCollector; } @@ -48,7 +49,7 @@ export class SearchInterceptor { * Observable that emits when the number of pending requests changes. * @internal */ - protected pendingCount$ = new BehaviorSubject(0); + protected pendingCount$!: BehaviorSubject; /** * The subscriptions from scheduling the automatic timeout for each request. @@ -78,7 +79,7 @@ export class SearchInterceptor { protected readonly deps: SearchInterceptorDeps, protected readonly requestTimeout?: number ) { - this.deps.http.addLoadingCountSource(this.pendingCount$); + this.pendingCount$ = deps.loadingCount$; this.deps.startServices.then(([coreStart]) => { this.application = coreStart.application; diff --git a/src/plugins/data/public/search/search_service.ts b/src/plugins/data/public/search/search_service.ts index 8caa4b3b0dd67..6d6bfad9a36be 100644 --- a/src/plugins/data/public/search/search_service.ts +++ b/src/plugins/data/public/search/search_service.ts @@ -29,6 +29,7 @@ import { SearchUsageCollector, createUsageCollector } from './collectors'; import { UsageCollectionSetup } from '../../../usage_collection/public'; import { esdsl, esRawResponse } from './expressions'; import { ExpressionsSetup } from '../../../expressions/public'; +import { BehaviorSubject } from 'rxjs'; /** @internal */ export interface SearchServiceSetupDependencies { @@ -46,6 +47,7 @@ export class SearchService implements Plugin { private readonly aggsService = new AggsService(); private searchInterceptor!: ISearchInterceptor; private usageCollector?: SearchUsageCollector; + private loadingCount$!: BehaviorSubject; public setup( { http, getStartServices, injectedMetadata, notifications, uiSettings }: CoreSetup, @@ -55,6 +57,8 @@ export class SearchService implements Plugin { this.usageCollector = createUsageCollector(getStartServices, usageCollection); + this.loadingCount$ = new BehaviorSubject(0); + /** * A global object that intercepts all searches and provides convenience methods for cancelling * all pending search requests, as well as getting the number of pending search requests. @@ -65,6 +69,7 @@ export class SearchService implements Plugin { { toasts: notifications.toasts, http, + loadingCount$: this.loadingCount$, uiSettings, startServices: getStartServices(), usageCollector: this.usageCollector!, @@ -101,6 +106,7 @@ export class SearchService implements Plugin { esShardTimeout: injectedMetadata.getInjectedVar('esShardTimeout') as number, search, http, + loadingCount$: this.loadingCount$, }; return { diff --git a/src/plugins/data/public/search/search_source/search_source.ts b/src/plugins/data/public/search/search_source/search_source.ts index 2bd66abca80d4..141649b071f05 100644 --- a/src/plugins/data/public/search/search_source/search_source.ts +++ b/src/plugins/data/public/search/search_source/search_source.ts @@ -91,6 +91,7 @@ import { getHighlightRequest } from '../../../common/field_formats'; import { GetConfigFn } from '../../../common/types'; import { fetchSoon } from '../legacy'; import { extractReferences } from './extract_references'; +import { BehaviorSubject } from 'rxjs'; /** @internal */ export const searchSourceRequiredUiSettings = [ @@ -113,6 +114,8 @@ export interface SearchSourceDependencies { search: ISearchGeneric; http: HttpStart; esShardTimeout: number; + loadingCount$: BehaviorSubject; + } /** @public **/ @@ -243,7 +246,7 @@ export class SearchSource { * @return {Promise>} */ private async legacyFetch(searchRequest: SearchRequest, options: FetchOptions) { - const { http, getConfig } = this.dependencies; + const { http, getConfig, loadingCount$ } = this.dependencies; return await fetchSoon( searchRequest, @@ -254,6 +257,7 @@ export class SearchSource { { http, config: { get: getConfig }, + loadingCount$, } ); } From 9540e4c3762d3a8f57b5b9261c7fe23d5bb626d6 Mon Sep 17 00:00:00 2001 From: Liza K Date: Thu, 27 Aug 2020 12:42:30 +0300 Subject: [PATCH 09/15] code review --- src/plugins/data/public/search/fetch/types.ts | 2 +- .../public/search/legacy/default_search_strategy.ts | 13 +++++++------ src/plugins/data/public/search/search_service.ts | 2 +- .../public/search/search_source/search_source.ts | 3 +-- src/plugins/data/server/search/routes/msearch.ts | 3 +-- 5 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/plugins/data/public/search/fetch/types.ts b/src/plugins/data/public/search/fetch/types.ts index 7560f2516bbc6..9ac4d0044c24d 100644 --- a/src/plugins/data/public/search/fetch/types.ts +++ b/src/plugins/data/public/search/fetch/types.ts @@ -18,8 +18,8 @@ */ import { HttpStart } from 'src/core/public'; -import { GetConfigFn } from '../../../common'; import { BehaviorSubject } from 'rxjs'; +import { GetConfigFn } from '../../../common'; /** * @internal diff --git a/src/plugins/data/public/search/legacy/default_search_strategy.ts b/src/plugins/data/public/search/legacy/default_search_strategy.ts index d491846d8929c..cbcd0da20207f 100644 --- a/src/plugins/data/public/search/legacy/default_search_strategy.ts +++ b/src/plugins/data/public/search/legacy/default_search_strategy.ts @@ -55,12 +55,13 @@ function msearch({ searchRequests, config, http, loadingCount$ }: SearchStrategy } }; - const searching = http.post('/internal/_msearch', { - body: JSON.stringify({ searches: requests }), - signal: abortController.signal, - }) - .then(({ body }) => body?.responses) - .finally(() => cleanup()); + const searching = http + .post('/internal/_msearch', { + body: JSON.stringify({ searches: requests }), + signal: abortController.signal, + }) + .then(({ body }) => body?.responses) + .finally(() => cleanup()); return { abort: () => { diff --git a/src/plugins/data/public/search/search_service.ts b/src/plugins/data/public/search/search_service.ts index 6d6bfad9a36be..7ea800b9d819c 100644 --- a/src/plugins/data/public/search/search_service.ts +++ b/src/plugins/data/public/search/search_service.ts @@ -18,6 +18,7 @@ */ import { Plugin, CoreSetup, CoreStart } from 'src/core/public'; +import { BehaviorSubject } from 'rxjs'; import { ISearchSetup, ISearchStart, SearchEnhancements } from './types'; import { createSearchSource, SearchSource, SearchSourceDependencies } from './search_source'; @@ -29,7 +30,6 @@ import { SearchUsageCollector, createUsageCollector } from './collectors'; import { UsageCollectionSetup } from '../../../usage_collection/public'; import { esdsl, esRawResponse } from './expressions'; import { ExpressionsSetup } from '../../../expressions/public'; -import { BehaviorSubject } from 'rxjs'; /** @internal */ export interface SearchServiceSetupDependencies { diff --git a/src/plugins/data/public/search/search_source/search_source.ts b/src/plugins/data/public/search/search_source/search_source.ts index 141649b071f05..7b07c37429378 100644 --- a/src/plugins/data/public/search/search_source/search_source.ts +++ b/src/plugins/data/public/search/search_source/search_source.ts @@ -73,6 +73,7 @@ import { setWith } from '@elastic/safer-lodash-set'; import { uniqueId, uniq, extend, pick, difference, omit, isObject, keys, isFunction } from 'lodash'; import { map } from 'rxjs/operators'; import { HttpStart } from 'src/core/public'; +import { BehaviorSubject } from 'rxjs'; import { normalizeSortRequest } from './normalize_sort_request'; import { filterDocvalueFields } from './filter_docvalue_fields'; import { fieldWildcardFilter } from '../../../../kibana_utils/common'; @@ -91,7 +92,6 @@ import { getHighlightRequest } from '../../../common/field_formats'; import { GetConfigFn } from '../../../common/types'; import { fetchSoon } from '../legacy'; import { extractReferences } from './extract_references'; -import { BehaviorSubject } from 'rxjs'; /** @internal */ export const searchSourceRequiredUiSettings = [ @@ -115,7 +115,6 @@ export interface SearchSourceDependencies { http: HttpStart; esShardTimeout: number; loadingCount$: BehaviorSubject; - } /** @public **/ diff --git a/src/plugins/data/server/search/routes/msearch.ts b/src/plugins/data/server/search/routes/msearch.ts index dce2fb0f30e8f..c854a06b6b0dd 100644 --- a/src/plugins/data/server/search/routes/msearch.ts +++ b/src/plugins/data/server/search/routes/msearch.ts @@ -53,8 +53,7 @@ export function convertRequestBody( timeout, ...curr.body, }); - req += `${header}\n${body}\n`; - return req; + return `${req}${header}\n${body}\n`; }, ''); } From 6de42057aacf553fb4961bd622589761fd8bd2ed Mon Sep 17 00:00:00 2001 From: Liza K Date: Thu, 27 Aug 2020 12:48:45 +0300 Subject: [PATCH 10/15] doc --- ...data-public.searchinterceptordeps.loadingcount_.md | 11 +++++++++++ ...lugin-plugins-data-public.searchinterceptordeps.md | 1 + src/plugins/data/public/public.api.md | 2 ++ 3 files changed, 14 insertions(+) create mode 100644 docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptordeps.loadingcount_.md diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptordeps.loadingcount_.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptordeps.loadingcount_.md new file mode 100644 index 0000000000000..516ba8c11ee00 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptordeps.loadingcount_.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [SearchInterceptorDeps](./kibana-plugin-plugins-data-public.searchinterceptordeps.md) > [loadingCount$](./kibana-plugin-plugins-data-public.searchinterceptordeps.loadingcount_.md) + +## SearchInterceptorDeps.loadingCount$ property + +Signature: + +```typescript +loadingCount$: BehaviorSubject; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptordeps.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptordeps.md index 63eb67ce48246..fb2090af5f3cc 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptordeps.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptordeps.md @@ -15,6 +15,7 @@ export interface SearchInterceptorDeps | Property | Type | Description | | --- | --- | --- | | [http](./kibana-plugin-plugins-data-public.searchinterceptordeps.http.md) | CoreSetup['http'] | | +| [loadingCount$](./kibana-plugin-plugins-data-public.searchinterceptordeps.loadingcount_.md) | BehaviorSubject<number> | | | [startServices](./kibana-plugin-plugins-data-public.searchinterceptordeps.startservices.md) | Promise<[CoreStart, any, unknown]> | | | [toasts](./kibana-plugin-plugins-data-public.searchinterceptordeps.toasts.md) | ToastsSetup | | | [uiSettings](./kibana-plugin-plugins-data-public.searchinterceptordeps.uisettings.md) | CoreSetup['uiSettings'] | | diff --git a/src/plugins/data/public/public.api.md b/src/plugins/data/public/public.api.md index 31c8279f91bcd..a44f4fd6c2c8c 100644 --- a/src/plugins/data/public/public.api.md +++ b/src/plugins/data/public/public.api.md @@ -1774,6 +1774,8 @@ export interface SearchInterceptorDeps { // (undocumented) http: CoreSetup_2['http']; // (undocumented) + loadingCount$: BehaviorSubject; + // (undocumented) startServices: Promise<[CoreStart, any, unknown]>; // (undocumented) toasts: ToastsSetup; From 5049b35f0cbae4fccda14f47624ee8aaa35b6d37 Mon Sep 17 00:00:00 2001 From: Liza K Date: Thu, 27 Aug 2020 12:59:15 +0300 Subject: [PATCH 11/15] loading count --- x-pack/plugins/data_enhanced/public/plugin.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/x-pack/plugins/data_enhanced/public/plugin.ts b/x-pack/plugins/data_enhanced/public/plugin.ts index 7f6e3feac0671..e76a2af25cca3 100644 --- a/x-pack/plugins/data_enhanced/public/plugin.ts +++ b/x-pack/plugins/data_enhanced/public/plugin.ts @@ -5,6 +5,7 @@ */ import { CoreSetup, CoreStart, Plugin } from 'src/core/public'; +import { BehaviorSubject } from 'rxjs'; import { DataPublicPluginSetup, DataPublicPluginStart } from '../../../../src/plugins/data/public'; import { setAutocompleteService } from './services'; import { setupKqlQuerySuggestionProvider, KUERY_LANGUAGE_NAME } from './autocomplete'; @@ -39,6 +40,7 @@ export class DataEnhancedPlugin uiSettings: core.uiSettings, startServices: core.getStartServices(), usageCollector: data.search.usageCollector, + loadingCount$: new BehaviorSubject(0), }, core.injectedMetadata.getInjectedVar('esRequestTimeout') as number ); From 002c13c6c3dac2c5844f2594dbb268fbe75770be Mon Sep 17 00:00:00 2001 From: Liza K Date: Thu, 27 Aug 2020 13:31:37 +0300 Subject: [PATCH 12/15] simplify code review and fix jest tets --- ...data-public.searchinterceptordeps.loadingcount_.md | 11 ----------- ...lugin-plugins-data-public.searchinterceptordeps.md | 1 - src/plugins/data/public/public.api.md | 2 -- .../data/public/search/legacy/call_client.test.ts | 2 ++ .../search/legacy/default_search_strategy.test.ts | 2 ++ src/plugins/data/public/search/search_interceptor.ts | 5 ++--- src/plugins/data/public/search/search_service.ts | 9 ++++----- .../search/search_source/create_search_source.test.ts | 2 ++ src/plugins/data/public/search/search_source/mocks.ts | 2 ++ .../public/search/search_source/search_source.test.ts | 3 ++- x-pack/plugins/data_enhanced/public/plugin.ts | 1 - 11 files changed, 16 insertions(+), 24 deletions(-) delete mode 100644 docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptordeps.loadingcount_.md diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptordeps.loadingcount_.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptordeps.loadingcount_.md deleted file mode 100644 index 516ba8c11ee00..0000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptordeps.loadingcount_.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [SearchInterceptorDeps](./kibana-plugin-plugins-data-public.searchinterceptordeps.md) > [loadingCount$](./kibana-plugin-plugins-data-public.searchinterceptordeps.loadingcount_.md) - -## SearchInterceptorDeps.loadingCount$ property - -Signature: - -```typescript -loadingCount$: BehaviorSubject; -``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptordeps.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptordeps.md index fb2090af5f3cc..63eb67ce48246 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptordeps.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptordeps.md @@ -15,7 +15,6 @@ export interface SearchInterceptorDeps | Property | Type | Description | | --- | --- | --- | | [http](./kibana-plugin-plugins-data-public.searchinterceptordeps.http.md) | CoreSetup['http'] | | -| [loadingCount$](./kibana-plugin-plugins-data-public.searchinterceptordeps.loadingcount_.md) | BehaviorSubject<number> | | | [startServices](./kibana-plugin-plugins-data-public.searchinterceptordeps.startservices.md) | Promise<[CoreStart, any, unknown]> | | | [toasts](./kibana-plugin-plugins-data-public.searchinterceptordeps.toasts.md) | ToastsSetup | | | [uiSettings](./kibana-plugin-plugins-data-public.searchinterceptordeps.uisettings.md) | CoreSetup['uiSettings'] | | diff --git a/src/plugins/data/public/public.api.md b/src/plugins/data/public/public.api.md index a44f4fd6c2c8c..31c8279f91bcd 100644 --- a/src/plugins/data/public/public.api.md +++ b/src/plugins/data/public/public.api.md @@ -1774,8 +1774,6 @@ export interface SearchInterceptorDeps { // (undocumented) http: CoreSetup_2['http']; // (undocumented) - loadingCount$: BehaviorSubject; - // (undocumented) startServices: Promise<[CoreStart, any, unknown]>; // (undocumented) toasts: ToastsSetup; diff --git a/src/plugins/data/public/search/legacy/call_client.test.ts b/src/plugins/data/public/search/legacy/call_client.test.ts index f0f36856e1b9a..38f3ab200da90 100644 --- a/src/plugins/data/public/search/legacy/call_client.test.ts +++ b/src/plugins/data/public/search/legacy/call_client.test.ts @@ -23,6 +23,7 @@ import { SearchStrategySearchParams } from './types'; import { defaultSearchStrategy } from './default_search_strategy'; import { FetchHandlers } from '../fetch'; import { handleResponse } from '../fetch/handle_response'; +import { BehaviorSubject } from 'rxjs'; const mockAbortFn = jest.fn(); jest.mock('../fetch/handle_response', () => ({ @@ -60,6 +61,7 @@ describe('callClient', () => { legacySearchService: {}, config: { get: jest.fn() }, esShardTimeout: 0, + loadingCount$: new BehaviorSubject(0), } as FetchHandlers; callClient(searchRequests, [], args); diff --git a/src/plugins/data/public/search/legacy/default_search_strategy.test.ts b/src/plugins/data/public/search/legacy/default_search_strategy.test.ts index e0916b23a4b48..e74ab49131430 100644 --- a/src/plugins/data/public/search/legacy/default_search_strategy.test.ts +++ b/src/plugins/data/public/search/legacy/default_search_strategy.test.ts @@ -21,6 +21,7 @@ import { HttpStart } from 'src/core/public'; import { coreMock } from '../../../../../core/public/mocks'; import { defaultSearchStrategy } from './default_search_strategy'; import { SearchStrategySearchParams } from './types'; +import { BehaviorSubject } from 'rxjs'; const { search } = defaultSearchStrategy; @@ -47,6 +48,7 @@ describe('defaultSearchStrategy', function () { config: { get: jest.fn(), }, + loadingCount$: new BehaviorSubject(0) as any, }; }); diff --git a/src/plugins/data/public/search/search_interceptor.ts b/src/plugins/data/public/search/search_interceptor.ts index 51f7039a694eb..30e509edd4987 100644 --- a/src/plugins/data/public/search/search_interceptor.ts +++ b/src/plugins/data/public/search/search_interceptor.ts @@ -34,7 +34,6 @@ export interface SearchInterceptorDeps { http: CoreSetup['http']; uiSettings: CoreSetup['uiSettings']; startServices: Promise<[CoreStart, any, unknown]>; - loadingCount$: BehaviorSubject; usageCollector?: SearchUsageCollector; } @@ -49,7 +48,7 @@ export class SearchInterceptor { * Observable that emits when the number of pending requests changes. * @internal */ - protected pendingCount$!: BehaviorSubject; + protected pendingCount$ = new BehaviorSubject(0); /** * The subscriptions from scheduling the automatic timeout for each request. @@ -79,7 +78,7 @@ export class SearchInterceptor { protected readonly deps: SearchInterceptorDeps, protected readonly requestTimeout?: number ) { - this.pendingCount$ = deps.loadingCount$; + this.deps.http.addLoadingCountSource(this.pendingCount$); this.deps.startServices.then(([coreStart]) => { this.application = coreStart.application; diff --git a/src/plugins/data/public/search/search_service.ts b/src/plugins/data/public/search/search_service.ts index 7ea800b9d819c..a49d2ef0956ff 100644 --- a/src/plugins/data/public/search/search_service.ts +++ b/src/plugins/data/public/search/search_service.ts @@ -47,7 +47,6 @@ export class SearchService implements Plugin { private readonly aggsService = new AggsService(); private searchInterceptor!: ISearchInterceptor; private usageCollector?: SearchUsageCollector; - private loadingCount$!: BehaviorSubject; public setup( { http, getStartServices, injectedMetadata, notifications, uiSettings }: CoreSetup, @@ -57,8 +56,6 @@ export class SearchService implements Plugin { this.usageCollector = createUsageCollector(getStartServices, usageCollection); - this.loadingCount$ = new BehaviorSubject(0); - /** * A global object that intercepts all searches and provides convenience methods for cancelling * all pending search requests, as well as getting the number of pending search requests. @@ -69,7 +66,6 @@ export class SearchService implements Plugin { { toasts: notifications.toasts, http, - loadingCount$: this.loadingCount$, uiSettings, startServices: getStartServices(), usageCollector: this.usageCollector!, @@ -100,13 +96,16 @@ export class SearchService implements Plugin { return this.searchInterceptor.search(request, options); }) as ISearchGeneric; + const loadingCount$ = new BehaviorSubject(0); + http.addLoadingCountSource(loadingCount$); + const searchSourceDependencies: SearchSourceDependencies = { getConfig: uiSettings.get.bind(uiSettings), // TODO: we don't need this, apply on the server esShardTimeout: injectedMetadata.getInjectedVar('esShardTimeout') as number, search, http, - loadingCount$: this.loadingCount$, + loadingCount$, }; return { diff --git a/src/plugins/data/public/search/search_source/create_search_source.test.ts b/src/plugins/data/public/search/search_source/create_search_source.test.ts index 1300c67d3c0fc..2820aab67ea3a 100644 --- a/src/plugins/data/public/search/search_source/create_search_source.test.ts +++ b/src/plugins/data/public/search/search_source/create_search_source.test.ts @@ -23,6 +23,7 @@ import { IIndexPattern } from '../../../common/index_patterns'; import { IndexPatternsContract } from '../../index_patterns/index_patterns'; import { Filter } from '../../../common/es_query/filters'; import { coreMock } from '../../../../../core/public/mocks'; +import { BehaviorSubject } from 'rxjs'; describe('createSearchSource', () => { const indexPatternMock: IIndexPattern = {} as IIndexPattern; @@ -36,6 +37,7 @@ describe('createSearchSource', () => { search: jest.fn(), esShardTimeout: 30000, http: coreMock.createStart().http, + loadingCount$: new BehaviorSubject(0), }; indexPatternContractMock = ({ diff --git a/src/plugins/data/public/search/search_source/mocks.ts b/src/plugins/data/public/search/search_source/mocks.ts index 16f665994e3bd..bc3e287d9fe80 100644 --- a/src/plugins/data/public/search/search_source/mocks.ts +++ b/src/plugins/data/public/search/search_source/mocks.ts @@ -17,6 +17,7 @@ * under the License. */ +import { BehaviorSubject } from 'rxjs'; import { httpServiceMock, uiSettingsServiceMock } from '../../../../../core/public/mocks'; import { ISearchSource, SearchSource } from './search_source'; @@ -55,4 +56,5 @@ export const createSearchSourceMock = (fields?: SearchSourceFields) => esShardTimeout: 30000, search: jest.fn(), http: httpServiceMock.createStartContract(), + loadingCount$: new BehaviorSubject(0), }); diff --git a/src/plugins/data/public/search/search_source/search_source.test.ts b/src/plugins/data/public/search/search_source/search_source.test.ts index a5bf700624a33..a8baed9faa84d 100644 --- a/src/plugins/data/public/search/search_source/search_source.test.ts +++ b/src/plugins/data/public/search/search_source/search_source.test.ts @@ -17,7 +17,7 @@ * under the License. */ -import { Observable } from 'rxjs'; +import { Observable, BehaviorSubject } from 'rxjs'; import { GetConfigFn } from 'src/plugins/data/common'; import { SearchSource, SearchSourceDependencies } from './search_source'; import { IndexPattern, SortDirection } from '../..'; @@ -70,6 +70,7 @@ describe('SearchSource', () => { search: mockSearchMethod, esShardTimeout: 30000, http: coreMock.createStart().http, + loadingCount$: new BehaviorSubject(0), }; }); diff --git a/x-pack/plugins/data_enhanced/public/plugin.ts b/x-pack/plugins/data_enhanced/public/plugin.ts index e76a2af25cca3..34973c9a9a6a0 100644 --- a/x-pack/plugins/data_enhanced/public/plugin.ts +++ b/x-pack/plugins/data_enhanced/public/plugin.ts @@ -40,7 +40,6 @@ export class DataEnhancedPlugin uiSettings: core.uiSettings, startServices: core.getStartServices(), usageCollector: data.search.usageCollector, - loadingCount$: new BehaviorSubject(0), }, core.injectedMetadata.getInjectedVar('esRequestTimeout') as number ); From 1dded0abdd5527c3832e04117fa5b1180a16857d Mon Sep 17 00:00:00 2001 From: Liza K Date: Thu, 27 Aug 2020 13:56:51 +0300 Subject: [PATCH 13/15] type check --- x-pack/plugins/data_enhanced/public/plugin.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/x-pack/plugins/data_enhanced/public/plugin.ts b/x-pack/plugins/data_enhanced/public/plugin.ts index 34973c9a9a6a0..7f6e3feac0671 100644 --- a/x-pack/plugins/data_enhanced/public/plugin.ts +++ b/x-pack/plugins/data_enhanced/public/plugin.ts @@ -5,7 +5,6 @@ */ import { CoreSetup, CoreStart, Plugin } from 'src/core/public'; -import { BehaviorSubject } from 'rxjs'; import { DataPublicPluginSetup, DataPublicPluginStart } from '../../../../src/plugins/data/public'; import { setAutocompleteService } from './services'; import { setupKqlQuerySuggestionProvider, KUERY_LANGUAGE_NAME } from './autocomplete'; From e0d68091620865028b7f14ca23ff4a1a266544c7 Mon Sep 17 00:00:00 2001 From: Luke Elmers Date: Tue, 1 Sep 2020 16:20:49 -0600 Subject: [PATCH 14/15] Ensure preference is optional and can be provided as string or number. --- .../data/server/search/routes/msearch.ts | 4 +- test/api_integration/apis/index.js | 1 + test/api_integration/apis/search/index.ts | 24 +++++ test/api_integration/apis/search/search.ts | 90 +++++++++++++++++++ 4 files changed, 117 insertions(+), 2 deletions(-) create mode 100644 test/api_integration/apis/search/index.ts create mode 100644 test/api_integration/apis/search/search.ts diff --git a/src/plugins/data/server/search/routes/msearch.ts b/src/plugins/data/server/search/routes/msearch.ts index c854a06b6b0dd..efb40edd90d58 100644 --- a/src/plugins/data/server/search/routes/msearch.ts +++ b/src/plugins/data/server/search/routes/msearch.ts @@ -27,7 +27,7 @@ import { getDefaultSearchParams } from '..'; interface MsearchHeaders { index: string; - preference: number; + preference?: number | string; } interface MsearchRequest { @@ -81,7 +81,7 @@ export function registerMsearchRoute(router: IRouter, deps: SearchRouteDependenc header: schema.object( { index: schema.string(), - preference: schema.number(), + preference: schema.maybe(schema.oneOf([schema.number(), schema.string()])), }, { unknowns: 'allow' } ), diff --git a/test/api_integration/apis/index.js b/test/api_integration/apis/index.js index 79815199aa20c..bfbf873cf0616 100644 --- a/test/api_integration/apis/index.js +++ b/test/api_integration/apis/index.js @@ -28,6 +28,7 @@ export default function ({ loadTestFile }) { loadTestFile(require.resolve('./saved_objects_management')); loadTestFile(require.resolve('./saved_objects')); loadTestFile(require.resolve('./scripts')); + loadTestFile(require.resolve('./search')); loadTestFile(require.resolve('./shorten')); loadTestFile(require.resolve('./suggestions')); loadTestFile(require.resolve('./status')); diff --git a/test/api_integration/apis/search/index.ts b/test/api_integration/apis/search/index.ts new file mode 100644 index 0000000000000..bf7ebeeccd62e --- /dev/null +++ b/test/api_integration/apis/search/index.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 default function ({ loadTestFile }) { + describe('search', () => { + loadTestFile(require.resolve('./search')); + }); +} diff --git a/test/api_integration/apis/search/search.ts b/test/api_integration/apis/search/search.ts new file mode 100644 index 0000000000000..0e2f5e565d87a --- /dev/null +++ b/test/api_integration/apis/search/search.ts @@ -0,0 +1,90 @@ +/* + * 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 expect from '@kbn/expect'; +import { Response } from 'supertest'; +import { FtrProviderContext } from '../../ftr_provider_context'; + +export default function ({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + + describe('msearch', () => { + describe('post', () => { + it('should return 200 when correctly formatted searches are provided', async () => + await supertest + .post(`/internal/_msearch`) + .send({ + searches: [ + { + header: { index: 'foo' }, + body: { + query: { + match_all: {}, + }, + }, + }, + ], + }) + .expect(200)); + + it('should return 400 if you provide malformed content', async () => + await supertest + .post(`/internal/_msearch`) + .send({ + foo: false, + }) + .expect(400)); + + it('should require you to provide an index for each request', async () => + await supertest + .post(`/internal/_msearch`) + .send({ + searches: [ + { header: { index: 'foo' }, body: {} }, + { header: {}, body: {} }, + ], + }) + .expect(400)); + + it('should not require optional params', async () => + await supertest + .post(`/internal/_msearch`) + .send({ + searches: [{ header: { index: 'foo' }, body: {} }], + }) + .expect(200)); + + it('should allow passing preference as a string', async () => + await supertest + .post(`/internal/_msearch`) + .send({ + searches: [{ header: { index: 'foo', preference: '_custom' }, body: {} }], + }) + .expect(200)); + + it('should allow passing preference as a number', async () => + await supertest + .post(`/internal/_msearch`) + .send({ + searches: [{ header: { index: 'foo', preference: 123 }, body: {} }], + }) + .expect(200)); + }); + }); +} From e607f5efca66982bac07e1699f0c36121161bc1d Mon Sep 17 00:00:00 2001 From: Luke Elmers Date: Wed, 2 Sep 2020 13:38:42 -0600 Subject: [PATCH 15/15] Fix TS failures. --- test/api_integration/apis/search/index.ts | 4 +++- test/api_integration/apis/search/search.ts | 2 -- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/api_integration/apis/search/index.ts b/test/api_integration/apis/search/index.ts index bf7ebeeccd62e..ee3baf23f0f6f 100644 --- a/test/api_integration/apis/search/index.ts +++ b/test/api_integration/apis/search/index.ts @@ -17,7 +17,9 @@ * under the License. */ -export default function ({ loadTestFile }) { +import { FtrProviderContext } from '../../ftr_provider_context'; + +export default function ({ loadTestFile }: FtrProviderContext) { describe('search', () => { loadTestFile(require.resolve('./search')); }); diff --git a/test/api_integration/apis/search/search.ts b/test/api_integration/apis/search/search.ts index 0e2f5e565d87a..bcf76bfb4eaa0 100644 --- a/test/api_integration/apis/search/search.ts +++ b/test/api_integration/apis/search/search.ts @@ -17,8 +17,6 @@ * under the License. */ -import expect from '@kbn/expect'; -import { Response } from 'supertest'; import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ getService }: FtrProviderContext) {