From c22024f38e221d8c11eefd0f6c153abb02495a53 Mon Sep 17 00:00:00 2001 From: Lukas Olson Date: Mon, 11 Jan 2021 20:39:39 -0700 Subject: [PATCH 01/20] [data.search] Add search session methods to search service contract --- .../public/search/session/sessions_client.ts | 6 + src/plugins/data/server/index.ts | 4 +- .../data/server/search/search_service.ts | 144 +++++++---- .../search/session/session_service.test.ts | 20 +- .../server/search/session/session_service.ts | 45 ++-- .../data/server/search/session/types.ts | 37 ++- src/plugins/data/server/search/types.ts | 16 +- .../server/routes/session.test.ts | 20 +- .../data_enhanced/server/routes/session.ts | 45 +++- .../search/session/session_service.test.ts | 235 +++++++++--------- .../server/search/session/session_service.ts | 120 +++++---- 11 files changed, 400 insertions(+), 292 deletions(-) diff --git a/src/plugins/data/public/search/session/sessions_client.ts b/src/plugins/data/public/search/session/sessions_client.ts index a8031e4e467e7..17afca2c15734 100644 --- a/src/plugins/data/public/search/session/sessions_client.ts +++ b/src/plugins/data/public/search/session/sessions_client.ts @@ -79,6 +79,12 @@ export class SessionsClient { }); } + public extend(sessionId: string, keepAlive: string): Promise { + return this.http!.post(`/internal/session/${encodeURIComponent(sessionId)}/_extend`, { + body: JSON.stringify({ keepAlive }), + }); + } + public delete(sessionId: string): Promise { return this.http!.delete(`/internal/session/${encodeURIComponent(sessionId)}`); } diff --git a/src/plugins/data/server/index.ts b/src/plugins/data/server/index.ts index b42619500525b..3ce7e786fb2c2 100644 --- a/src/plugins/data/server/index.ts +++ b/src/plugins/data/server/index.ts @@ -244,8 +244,8 @@ export { searchUsageObserver, shimAbortSignal, SearchUsage, - SessionService, - ISessionService, + SearchSessionService, + ISearchSessionService, } from './search'; // Search namespace diff --git a/src/plugins/data/server/search/search_service.ts b/src/plugins/data/server/search/search_service.ts index d26c099b23f39..56a8b7eeffb4b 100644 --- a/src/plugins/data/server/search/search_service.ts +++ b/src/plugins/data/server/search/search_service.ts @@ -17,7 +17,7 @@ * under the License. */ -import { BehaviorSubject, Observable } from 'rxjs'; +import { BehaviorSubject, from, Observable } from 'rxjs'; import { pick } from 'lodash'; import { CoreSetup, @@ -29,10 +29,11 @@ import { SharedGlobalConfig, StartServicesAccessor, } from 'src/core/server'; -import { catchError, first, map } from 'rxjs/operators'; +import { catchError, first, map, switchMap } from 'rxjs/operators'; import { BfetchServerSetup } from 'src/plugins/bfetch/server'; import { ExpressionsServerSetup } from 'src/plugins/expressions/server'; import { + IScopedSearchClient, ISearchSetup, ISearchStart, ISearchStrategy, @@ -56,7 +57,6 @@ import { IEsSearchResponse, IKibanaSearchRequest, IKibanaSearchResponse, - ISearchClient, ISearchOptions, kibana, kibanaContext, @@ -72,12 +72,13 @@ import { } from '../../common/search/aggs/buckets/shard_delay'; import { aggShardDelay } from '../../common/search/aggs/buckets/shard_delay_fn'; import { ConfigSchema } from '../../config'; -import { SessionService, IScopedSessionService, ISessionService } from './session'; +import { ISearchSessionService, SearchSessionService } from './session'; import { KbnServerError } from '../../../kibana_utils/server'; +import { tapFirst } from '../../common'; declare module 'src/core/server' { interface RequestHandlerContext { - search?: ISearchClient & { session: IScopedSessionService }; + search?: IScopedSearchClient; } } @@ -107,14 +108,14 @@ export class SearchService implements Plugin { private readonly searchSourceService = new SearchSourceService(); private defaultSearchStrategyName: string = ES_SEARCH_STRATEGY; private searchStrategies: StrategyMap = {}; - private sessionService: ISessionService; - private coreStart?: CoreStart; + private sessionService: ISearchSessionService; + private asScoped!: (request: KibanaRequest) => IScopedSearchClient; constructor( private initializerContext: PluginInitializerContext, private readonly logger: Logger ) { - this.sessionService = new SessionService(); + this.sessionService = new SearchSessionService(); } public setup( @@ -131,14 +132,8 @@ export class SearchService implements Plugin { registerSearchRoute(router); registerMsearchRoute(router, routeDependencies); - core.getStartServices().then(([coreStart]) => { - this.coreStart = coreStart; - }); - core.http.registerRouteHandlerContext('search', async (context, request) => { - const search = this.asScopedProvider(this.coreStart!)(request); - const session = this.sessionService.asScopedProvider(this.coreStart!)(request); - return { ...search, session }; + return this.asScoped(request); }); this.registerSearchStrategy( @@ -154,7 +149,7 @@ export class SearchService implements Plugin { { request: IKibanaSearchResponse; options?: ISearchOptions }, any >('/internal/bsearch', (request) => { - const search = this.asScopedProvider(this.coreStart!)(request); + const search = this.asScoped(request); return { onBatchItem: async ({ request: requestData, options }) => { @@ -229,7 +224,7 @@ export class SearchService implements Plugin { { fieldFormats, indexPatterns }: SearchServiceStartDependencies ): ISearchStart { const { elasticsearch, savedObjects, uiSettings } = core; - const asScoped = this.asScopedProvider(core); + this.asScoped = this.asScopedProvider(core); return { aggs: this.aggsService.start({ fieldFormats, @@ -237,7 +232,7 @@ export class SearchService implements Plugin { indexPatterns, }), getSearchStrategy: this.getSearchStrategy, - asScoped, + asScoped: this.asScoped, searchSource: { asScoped: async (request: KibanaRequest) => { const esClient = elasticsearch.client.asScoped(request); @@ -256,7 +251,7 @@ export class SearchService implements Plugin { const searchSourceDependencies: SearchSourceDependencies = { getConfig: (key: string): T => uiSettingsCache[key], - search: asScoped(request).search, + search: this.asScoped(request).search, onResponse: (req, res) => shimHitsTotal(res), legacy: { callMsearch: getCallMsearch({ @@ -289,22 +284,50 @@ export class SearchService implements Plugin { this.searchStrategies[name] = strategy; }; - private search = < + private getSearchStrategy = < SearchStrategyRequest extends IKibanaSearchRequest = IEsSearchRequest, SearchStrategyResponse extends IKibanaSearchResponse = IEsSearchResponse >( - session: IScopedSessionService, + name: string = this.defaultSearchStrategyName + ): ISearchStrategy => { + this.logger.debug(`Get strategy ${name}`); + const strategy = this.searchStrategies[name]; + if (!strategy) { + throw new KbnServerError(`Search strategy ${name} not found`, 404); + } + return strategy; + }; + + private search = < + SearchStrategyRequest extends IKibanaSearchRequest, + SearchStrategyResponse extends IKibanaSearchResponse + >( + deps: SearchStrategyDependencies, request: SearchStrategyRequest, - options: ISearchOptions, - deps: SearchStrategyDependencies + options: ISearchOptions ) => { const strategy = this.getSearchStrategy( options.strategy ); - return session.search(strategy, request, options, deps); + + const getSearchRequest = async () => + !options.sessionId || !options.isRestore || request.id + ? request + : { + ...request, + id: await deps.searchSessionsClient.getId(request, options), + }; + + return from(getSearchRequest()).pipe( + switchMap((searchRequest) => strategy.search(searchRequest, options, deps)), + tapFirst((response) => { + if (request.id || !options.sessionId || !response.id || options.isRestore) return; + deps.searchSessionsClient.trackId(request, response.id, options); + }) + ); }; - private cancel = (id: string, options: ISearchOptions, deps: SearchStrategyDependencies) => { + private cancel = (deps: SearchStrategyDependencies, id: string, options: ISearchOptions = {}) => { const strategy = this.getSearchStrategy(options.strategy); if (!strategy.cancel) { throw new KbnServerError( @@ -316,10 +339,10 @@ export class SearchService implements Plugin { }; private extend = ( + deps: SearchStrategyDependencies, id: string, keepAlive: string, - options: ISearchOptions, - deps: SearchStrategyDependencies + options: ISearchOptions = {} ) => { const strategy = this.getSearchStrategy(options.strategy); if (!strategy.extend) { @@ -328,36 +351,69 @@ export class SearchService implements Plugin { return strategy.extend(id, keepAlive, options, deps); }; - private getSearchStrategy = < - SearchStrategyRequest extends IKibanaSearchRequest = IEsSearchRequest, - SearchStrategyResponse extends IKibanaSearchResponse = IEsSearchResponse - >( - name: string = this.defaultSearchStrategyName - ): ISearchStrategy => { - this.logger.debug(`Get strategy ${name}`); - const strategy = this.searchStrategies[name]; - if (!strategy) { - throw new KbnServerError(`Search strategy ${name} not found`, 404); + private deleteSession = async (deps: SearchStrategyDependencies, sessionId: string) => { + const searchIdMapping = await deps.searchSessionsClient.getSearchIdMapping(sessionId); + + for (const [searchId, strategyName] of searchIdMapping.entries()) { + const searchOptions = { + sessionId, + strategy: strategyName, + isStored: true, + }; + await this.cancel(deps, searchId, searchOptions); } - return strategy; + + return deps.searchSessionsClient.delete(sessionId); + }; + + private extendSession = async ( + deps: SearchStrategyDependencies, + sessionId: string, + keepAlive: string + ) => { + const searchIdMapping = await deps.searchSessionsClient.getSearchIdMapping(sessionId); + + for (const [searchId, strategyName] of searchIdMapping.entries()) { + const searchOptions = { + sessionId, + strategy: strategyName, + isStored: true, + }; + await this.extend(deps, searchId, keepAlive, searchOptions); + } + + return deps.searchSessionsClient.extend(sessionId, keepAlive); }; private asScopedProvider = (core: CoreStart) => { const { elasticsearch, savedObjects, uiSettings } = core; const getSessionAsScoped = this.sessionService.asScopedProvider(core); - return (request: KibanaRequest): ISearchClient => { - const scopedSession = getSessionAsScoped(request); + return (request: KibanaRequest): IScopedSearchClient => { const savedObjectsClient = savedObjects.getScopedClient(request); + const searchSessionsClient = getSessionAsScoped(request); const deps = { + searchSessionsClient, savedObjectsClient, esClient: elasticsearch.client.asScoped(request), uiSettingsClient: uiSettings.asScopedToClient(savedObjectsClient), }; return { - search: (searchRequest, options = {}) => - this.search(scopedSession, searchRequest, options, deps), - cancel: (id, options = {}) => this.cancel(id, options, deps), - extend: (id, keepAlive, options = {}) => this.extend(id, keepAlive, options, deps), + search: < + SearchStrategyRequest extends IKibanaSearchRequest = IEsSearchRequest, + SearchStrategyResponse extends IKibanaSearchResponse = IEsSearchResponse + >( + searchRequest: SearchStrategyRequest, + options: ISearchOptions = {} + ) => + this.search(deps, searchRequest, options), + cancel: this.cancel.bind(this, deps), + extend: this.extend.bind(this, deps), + saveSession: searchSessionsClient.save, + getSession: searchSessionsClient.get, + findSessions: searchSessionsClient.find, + updateSession: searchSessionsClient.update, + extendSession: this.extendSession.bind(this, deps), + deleteSession: this.deleteSession.bind(this, deps), }; }; }; diff --git a/src/plugins/data/server/search/session/session_service.test.ts b/src/plugins/data/server/search/session/session_service.test.ts index 3dbe01105aca4..943b90b29b417 100644 --- a/src/plugins/data/server/search/session/session_service.test.ts +++ b/src/plugins/data/server/search/session/session_service.test.ts @@ -17,22 +17,6 @@ * under the License. */ -import { of } from 'rxjs'; -import { SearchStrategyDependencies } from '../types'; -import { SessionService } from './session_service'; +// import { SearchSessionService } from './session_service'; -describe('SessionService', () => { - it('search invokes `strategy.search`', async () => { - const service = new SessionService(); - const mockSearch = jest.fn().mockReturnValue(of({})); - const mockStrategy = { search: mockSearch }; - const mockRequest = { id: 'bar' }; - const mockOptions = { sessionId: '1234' }; - const mockDeps = { savedObjectsClient: {} } as SearchStrategyDependencies; - - await service.search(mockStrategy, mockRequest, mockOptions, mockDeps); - - expect(mockSearch).toHaveBeenCalled(); - expect(mockSearch).toHaveBeenCalledWith(mockRequest, mockOptions, mockDeps); - }); -}); +describe('SearchSessionService', () => {}); diff --git a/src/plugins/data/server/search/session/session_service.ts b/src/plugins/data/server/search/session/session_service.ts index 37484185cb779..c27a4c335d9b4 100644 --- a/src/plugins/data/server/search/session/session_service.ts +++ b/src/plugins/data/server/search/session/session_service.ts @@ -17,27 +17,40 @@ * under the License. */ -import { CoreStart, KibanaRequest } from 'kibana/server'; -import { IKibanaSearchRequest, IKibanaSearchResponse } from '../../../common'; -import { ISearchStrategy } from '../types'; -import { ISessionService } from './types'; +import { ISearchSessionService } from './types'; /** - * The OSS session service. See data_enhanced in X-Pack for the search session service. + * The OSS session service, which leaves most search session-related logic unimplemented. + * @see x-pack/plugins/data_enhanced/server/search/session/session_service.ts */ -export class SessionService implements ISessionService { +export class SearchSessionService implements ISearchSessionService { constructor() {} - public search( - strategy: ISearchStrategy, - ...args: Parameters['search']> - ) { - return strategy.search(...args); - } - - public asScopedProvider(core: CoreStart) { - return (request: KibanaRequest) => ({ - search: this.search, + public asScopedProvider() { + return () => ({ + getId: () => { + throw new Error('getId not implemented in OSS search session service'); + }, + trackId: async () => {}, + getSearchIdMapping: async () => new Map(), + save: async () => { + throw new Error('save not implemented in OSS search session service'); + }, + get: async () => { + throw new Error('get not implemented in OSS search session service'); + }, + find: async () => { + throw new Error('find not implemented in OSS search session service'); + }, + update: async () => { + throw new Error('update not implemented in OSS search session service'); + }, + extend: async () => { + throw new Error('extend not implemented in OSS search session service'); + }, + delete: async () => { + throw new Error('delete not implemented in OSS search session service'); + }, }); } } diff --git a/src/plugins/data/server/search/session/types.ts b/src/plugins/data/server/search/session/types.ts index 5e179b99952fe..ea591dbe78282 100644 --- a/src/plugins/data/server/search/session/types.ts +++ b/src/plugins/data/server/search/session/types.ts @@ -17,19 +17,32 @@ * under the License. */ -import { Observable } from 'rxjs'; -import { CoreStart, KibanaRequest } from 'kibana/server'; -import { ISearchStrategy } from '../types'; -import { IKibanaSearchRequest, IKibanaSearchResponse } from '../../../common/search'; +import { + CoreStart, + KibanaRequest, + SavedObject, + SavedObjectsFindOptions, + SavedObjectsFindResponse, + SavedObjectsUpdateResponse, +} from 'kibana/server'; +import { IKibanaSearchRequest, ISearchOptions } from '../../../common/search'; -export interface IScopedSessionService { - search: ( - strategy: ISearchStrategy, - ...args: Parameters['search']> - ) => Observable; - [prop: string]: any; +export interface IScopedSearchSessionsClient { + getId: (request: IKibanaSearchRequest, options: ISearchOptions) => Promise; + trackId: ( + request: IKibanaSearchRequest, + searchId: string, + options: ISearchOptions + ) => Promise; + getSearchIdMapping: (sessionId: string) => Promise>; + save: (sessionId: string, attributes: Partial) => Promise>; + get: (sessionId: string) => Promise>; + find: (options: Omit) => Promise>; + update: (sessionId: string, attributes: Partial) => Promise>; + delete: (sessionId: string) => Promise<{}>; + extend: (sessionId: string, keepAlive: string) => Promise>; } -export interface ISessionService { - asScopedProvider: (core: CoreStart) => (request: KibanaRequest) => IScopedSessionService; +export interface ISearchSessionService { + asScopedProvider: (core: CoreStart) => (request: KibanaRequest) => IScopedSearchSessionsClient; } diff --git a/src/plugins/data/server/search/types.ts b/src/plugins/data/server/search/types.ts index fb00f86464e4e..988fb00f53fb0 100644 --- a/src/plugins/data/server/search/types.ts +++ b/src/plugins/data/server/search/types.ts @@ -34,17 +34,18 @@ import { import { AggsSetup, AggsStart } from './aggs'; import { SearchUsage } from './collectors'; import { IEsSearchRequest, IEsSearchResponse } from './es_search'; -import { ISessionService } from './session'; +import { IScopedSearchSessionsClient, ISearchSessionService } from './session'; export interface SearchEnhancements { defaultStrategy: string; - sessionService: ISessionService; + sessionService: ISearchSessionService; } export interface SearchStrategyDependencies { savedObjectsClient: SavedObjectsClientContract; esClient: IScopedClusterClient; uiSettingsClient: IUiSettingsClient; + searchSessionsClient: IScopedSearchSessionsClient; } export interface ISearchSetup { @@ -94,6 +95,15 @@ export interface ISearchStrategy< ) => Promise; } +export interface IScopedSearchClient extends ISearchClient { + saveSession: IScopedSearchSessionsClient['save']; + getSession: IScopedSearchSessionsClient['get']; + findSessions: IScopedSearchSessionsClient['find']; + updateSession: IScopedSearchSessionsClient['update']; + deleteSession: IScopedSearchSessionsClient['delete']; + extendSession: IScopedSearchSessionsClient['extend']; +} + export interface ISearchStart< SearchStrategyRequest extends IKibanaSearchRequest = IEsSearchRequest, SearchStrategyResponse extends IKibanaSearchResponse = IEsSearchResponse @@ -107,7 +117,7 @@ export interface ISearchStart< getSearchStrategy: ( name?: string // Name of the search strategy (defaults to the Elasticsearch strategy) ) => ISearchStrategy; - asScoped: (request: KibanaRequest) => ISearchClient; + asScoped: (request: KibanaRequest) => IScopedSearchClient; searchSource: { asScoped: (request: KibanaRequest) => Promise; }; diff --git a/x-pack/plugins/data_enhanced/server/routes/session.test.ts b/x-pack/plugins/data_enhanced/server/routes/session.test.ts index 313dfb1e0f1f0..5683b4c99ff96 100644 --- a/x-pack/plugins/data_enhanced/server/routes/session.test.ts +++ b/x-pack/plugins/data_enhanced/server/routes/session.test.ts @@ -21,7 +21,7 @@ describe('registerSessionRoutes', () => { registerSessionRoutes(mockCoreSetup.http.createRouter()); }); - it('save calls session.save with sessionId and attributes', async () => { + it('save calls saveSession with sessionId and attributes', async () => { const sessionId = 'd7170a35-7e2c-48d6-8dec-9a056721b489'; const name = 'my saved background search session'; const body = { sessionId, name }; @@ -34,10 +34,10 @@ describe('registerSessionRoutes', () => { saveHandler(mockContext, mockRequest, mockResponse); - expect(mockContext.search!.session.save).toHaveBeenCalledWith(sessionId, { name }); + expect(mockContext.search!.saveSession).toHaveBeenCalledWith(sessionId, { name }); }); - it('get calls session.get with sessionId', async () => { + it('get calls getSession with sessionId', async () => { const id = 'd7170a35-7e2c-48d6-8dec-9a056721b489'; const params = { id }; @@ -49,10 +49,10 @@ describe('registerSessionRoutes', () => { getHandler(mockContext, mockRequest, mockResponse); - expect(mockContext.search!.session.get).toHaveBeenCalledWith(id); + expect(mockContext.search!.getSession).toHaveBeenCalledWith(id); }); - it('find calls session.find with options', async () => { + it('find calls findSession with options', async () => { const page = 1; const perPage = 5; const sortField = 'my_field'; @@ -68,10 +68,10 @@ describe('registerSessionRoutes', () => { findHandler(mockContext, mockRequest, mockResponse); - expect(mockContext.search!.session.find).toHaveBeenCalledWith(body); + expect(mockContext.search!.findSessions).toHaveBeenCalledWith(body); }); - it('update calls session.update with id and attributes', async () => { + it('update calls updateSession with id and attributes', async () => { const id = 'd7170a35-7e2c-48d6-8dec-9a056721b489'; const name = 'my saved background search session'; const expires = new Date().toISOString(); @@ -86,10 +86,10 @@ describe('registerSessionRoutes', () => { updateHandler(mockContext, mockRequest, mockResponse); - expect(mockContext.search!.session.update).toHaveBeenCalledWith(id, body); + expect(mockContext.search!.updateSession).toHaveBeenCalledWith(id, body); }); - it('delete calls session.delete with id', async () => { + it('delete calls deleteSession with id', async () => { const id = 'd7170a35-7e2c-48d6-8dec-9a056721b489'; const params = { id }; @@ -101,6 +101,6 @@ describe('registerSessionRoutes', () => { deleteHandler(mockContext, mockRequest, mockResponse); - expect(mockContext.search!.session.delete).toHaveBeenCalledWith(id); + expect(mockContext.search!.deleteSession).toHaveBeenCalledWith(id); }); }); diff --git a/x-pack/plugins/data_enhanced/server/routes/session.ts b/x-pack/plugins/data_enhanced/server/routes/session.ts index b056513f1d2f5..0683679eea95f 100644 --- a/x-pack/plugins/data_enhanced/server/routes/session.ts +++ b/x-pack/plugins/data_enhanced/server/routes/session.ts @@ -36,7 +36,7 @@ export function registerSessionRoutes(router: IRouter): void { } = request.body; try { - const response = await context.search!.session.save(sessionId, { + const response = await context.search!.saveSession(sessionId, { name, appId, expires, @@ -66,7 +66,7 @@ export function registerSessionRoutes(router: IRouter): void { async (context, request, res) => { const { id } = request.params; try { - const response = await context.search!.session.get(id); + const response = await context.search!.getSession(id); return res.ok({ body: response, @@ -94,7 +94,7 @@ export function registerSessionRoutes(router: IRouter): void { async (context, request, res) => { const { page, perPage, sortField, sortOrder, filter } = request.body; try { - const response = await context.search!.session.find({ + const response = await context.search!.findSessions({ page, perPage, sortField, @@ -123,7 +123,7 @@ export function registerSessionRoutes(router: IRouter): void { async (context, request, res) => { const { id } = request.params; try { - await context.search!.session.delete(id); + await context.search!.deleteSession(id); return res.ok(); } catch (e) { @@ -150,7 +150,7 @@ export function registerSessionRoutes(router: IRouter): void { const { id } = request.params; const { name, expires } = request.body; try { - const response = await context.search!.session.update(id, { name, expires }); + const response = await context.search!.updateSession(id, { name, expires }); return res.ok({ body: response, @@ -160,4 +160,39 @@ export function registerSessionRoutes(router: IRouter): void { } } ); + + router.post( + { + path: '/internal/session/{id}/_extend', + validate: { + params: schema.object({ + id: schema.string(), + }), + body: schema.object({ + keepAlive: schema.string(), + }), + }, + }, + async (context, request, res) => { + const { id } = request.params; + const { keepAlive } = request.body; + try { + const response = await context.search!.extendSession(id, keepAlive); + + 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/x-pack/plugins/data_enhanced/server/search/session/session_service.test.ts b/x-pack/plugins/data_enhanced/server/search/session/session_service.test.ts index 3114e746d0453..14ba634423222 100644 --- a/x-pack/plugins/data_enhanced/server/search/session/session_service.test.ts +++ b/x-pack/plugins/data_enhanced/server/search/session/session_service.test.ts @@ -4,13 +4,12 @@ * you may not use this file except in compliance with the Elastic License. */ -import { BehaviorSubject, of } from 'rxjs'; +import { BehaviorSubject } from 'rxjs'; import type { SavedObject, SavedObjectsClientContract } from 'kibana/server'; -import type { SearchStrategyDependencies } from '../../../../../../src/plugins/data/server'; import { savedObjectsClientMock } from '../../../../../../src/core/server/mocks'; import { SearchSessionStatus } from '../../../common'; import { SEARCH_SESSION_TYPE } from '../../saved_objects'; -import { SearchSessionDependencies, SearchSessionService, SessionInfo } from './session_service'; +import { SearchSessionService, SessionInfo } from './session_service'; import { createRequestHash } from './utils'; import moment from 'moment'; import { coreMock } from 'src/core/server/mocks'; @@ -112,13 +111,13 @@ describe('SearchSessionService', () => { }); it('search throws if `name` is not provided', () => { - expect(() => service.save(sessionId, {}, { savedObjectsClient })).rejects.toMatchInlineSnapshot( + expect(() => service.save({ savedObjectsClient }, sessionId, {})).rejects.toMatchInlineSnapshot( `[Error: Name is required]` ); }); it('save throws if `name` is not provided', () => { - expect(() => service.save(sessionId, {}, { savedObjectsClient })).rejects.toMatchInlineSnapshot( + expect(() => service.save({ savedObjectsClient }, sessionId, {})).rejects.toMatchInlineSnapshot( `[Error: Name is required]` ); }); @@ -126,7 +125,7 @@ describe('SearchSessionService', () => { it('get calls saved objects client', async () => { savedObjectsClient.get.mockResolvedValue(mockSavedObject); - const response = await service.get(sessionId, { savedObjectsClient }); + const response = await service.get({ savedObjectsClient }, sessionId); expect(response).toBe(mockSavedObject); expect(savedObjectsClient.get).toHaveBeenCalledWith(SEARCH_SESSION_TYPE, sessionId); @@ -146,7 +145,7 @@ describe('SearchSessionService', () => { savedObjectsClient.find.mockResolvedValue(mockResponse); const options = { page: 0, perPage: 5 }; - const response = await service.find(options, { savedObjectsClient }); + const response = await service.find({ savedObjectsClient }, options); expect(response).toBe(mockResponse); expect(savedObjectsClient.find).toHaveBeenCalledWith({ @@ -163,7 +162,7 @@ describe('SearchSessionService', () => { savedObjectsClient.update.mockResolvedValue(mockUpdateSavedObject); const attributes = { name: 'new_name' }; - const response = await service.update(sessionId, attributes, { savedObjectsClient }); + const response = await service.update({ savedObjectsClient }, sessionId, attributes); expect(response).toBe(mockUpdateSavedObject); expect(savedObjectsClient.update).toHaveBeenCalledWith( @@ -176,92 +175,92 @@ describe('SearchSessionService', () => { it('delete calls saved objects client', async () => { savedObjectsClient.delete.mockResolvedValue({}); - const response = await service.delete(sessionId, { savedObjectsClient }); + const response = await service.delete({ savedObjectsClient }, sessionId); expect(response).toEqual({}); expect(savedObjectsClient.delete).toHaveBeenCalledWith(SEARCH_SESSION_TYPE, sessionId); }); - describe('search', () => { - const mockSearch = jest.fn().mockReturnValue(of({})); - const mockStrategy = { search: mockSearch }; - const mockSearchDeps = {} as SearchStrategyDependencies; - const mockDeps = {} as SearchSessionDependencies; - - beforeEach(() => { - mockSearch.mockClear(); - }); - - it('searches using the original request if not restoring', async () => { - const searchRequest = { params: {} }; - const options = { sessionId, isStored: false, isRestore: false }; - - await service - .search(mockStrategy, searchRequest, options, mockSearchDeps, mockDeps) - .toPromise(); - - expect(mockSearch).toBeCalledWith(searchRequest, options, mockSearchDeps); - }); - - it('searches using the original request if `id` is provided', async () => { - const searchId = 'FnpFYlBpeXdCUTMyZXhCLTc1TWFKX0EbdDFDTzJzTE1Sck9PVTBIcW1iU05CZzo4MDA0'; - const searchRequest = { id: searchId, params: {} }; - const options = { sessionId, isStored: true, isRestore: true }; - - await service - .search(mockStrategy, searchRequest, options, mockSearchDeps, mockDeps) - .toPromise(); - - expect(mockSearch).toBeCalledWith(searchRequest, options, mockSearchDeps); - }); - - it('searches by looking up an `id` if restoring and `id` is not provided', async () => { - const searchRequest = { params: {} }; - const options = { sessionId, isStored: true, isRestore: true }; - const spyGetId = jest.spyOn(service, 'getId').mockResolvedValueOnce('my_id'); - - await service - .search(mockStrategy, searchRequest, options, mockSearchDeps, mockDeps) - .toPromise(); - - expect(mockSearch).toBeCalledWith({ ...searchRequest, id: 'my_id' }, options, mockSearchDeps); - - spyGetId.mockRestore(); - }); - - it('calls `trackId` once if the response contains an `id` and not restoring', async () => { - const searchRequest = { params: {} }; - const options = { sessionId, isStored: false, isRestore: false }; - const spyTrackId = jest.spyOn(service, 'trackId').mockResolvedValue(); - mockSearch.mockReturnValueOnce(of({ id: 'my_id' }, { id: 'my_id' })); - - await service - .search(mockStrategy, searchRequest, options, mockSearchDeps, mockDeps) - .toPromise(); - - expect(spyTrackId).toBeCalledTimes(1); - expect(spyTrackId).toBeCalledWith(searchRequest, 'my_id', options, {}); - - spyTrackId.mockRestore(); - }); - - it('does not call `trackId` if restoring', async () => { - const searchRequest = { params: {} }; - const options = { sessionId, isStored: true, isRestore: true }; - const spyGetId = jest.spyOn(service, 'getId').mockResolvedValueOnce('my_id'); - const spyTrackId = jest.spyOn(service, 'trackId').mockResolvedValue(); - mockSearch.mockReturnValueOnce(of({ id: 'my_id' })); - - await service - .search(mockStrategy, searchRequest, options, mockSearchDeps, mockDeps) - .toPromise(); - - expect(spyTrackId).not.toBeCalled(); - - spyGetId.mockRestore(); - spyTrackId.mockRestore(); - }); - }); + // describe('search', () => { + // const mockSearch = jest.fn().mockReturnValue(of({})); + // const mockStrategy = { search: mockSearch }; + // const mockSearchDeps = {} as SearchStrategyDependencies; + // const mockDeps = {} as SearchSessionDependencies; + // + // beforeEach(() => { + // mockSearch.mockClear(); + // }); + // + // it('searches using the original request if not restoring', async () => { + // const searchRequest = { params: {} }; + // const options = { sessionId, isStored: false, isRestore: false }; + // + // await service + // .search(mockStrategy, searchRequest, options, mockSearchDeps, mockDeps) + // .toPromise(); + // + // expect(mockSearch).toBeCalledWith(searchRequest, options, mockSearchDeps); + // }); + // + // it('searches using the original request if `id` is provided', async () => { + // const searchId = 'FnpFYlBpeXdCUTMyZXhCLTc1TWFKX0EbdDFDTzJzTE1Sck9PVTBIcW1iU05CZzo4MDA0'; + // const searchRequest = { id: searchId, params: {} }; + // const options = { sessionId, isStored: true, isRestore: true }; + // + // await service + // .search(mockStrategy, searchRequest, options, mockSearchDeps, mockDeps) + // .toPromise(); + // + // expect(mockSearch).toBeCalledWith(searchRequest, options, mockSearchDeps); + // }); + // + // it('searches by looking up an `id` if restoring and `id` is not provided', async () => { + // const searchRequest = { params: {} }; + // const options = { sessionId, isStored: true, isRestore: true }; + // const spyGetId = jest.spyOn(service, 'getId').mockResolvedValueOnce('my_id'); + // + // await service + // .search(mockStrategy, searchRequest, options, mockSearchDeps, mockDeps) + // .toPromise(); + // + // expect(mockSearch).toBeCalledWith({ ...searchRequest, id: 'my_id' }, options, mockSearchDeps); + // + // spyGetId.mockRestore(); + // }); + // + // it('calls `trackId` once if the response contains an `id` and not restoring', async () => { + // const searchRequest = { params: {} }; + // const options = { sessionId, isStored: false, isRestore: false }; + // const spyTrackId = jest.spyOn(service, 'trackId').mockResolvedValue(); + // mockSearch.mockReturnValueOnce(of({ id: 'my_id' }, { id: 'my_id' })); + // + // await service + // .search(mockStrategy, searchRequest, options, mockSearchDeps, mockDeps) + // .toPromise(); + // + // expect(spyTrackId).toBeCalledTimes(1); + // expect(spyTrackId).toBeCalledWith(searchRequest, 'my_id', options, {}); + // + // spyTrackId.mockRestore(); + // }); + // + // it('does not call `trackId` if restoring', async () => { + // const searchRequest = { params: {} }; + // const options = { sessionId, isStored: true, isRestore: true }; + // const spyGetId = jest.spyOn(service, 'getId').mockResolvedValueOnce('my_id'); + // const spyTrackId = jest.spyOn(service, 'trackId').mockResolvedValue(); + // mockSearch.mockReturnValueOnce(of({ id: 'my_id' })); + // + // await service + // .search(mockStrategy, searchRequest, options, mockSearchDeps, mockDeps) + // .toPromise(); + // + // expect(spyTrackId).not.toBeCalled(); + // + // spyGetId.mockRestore(); + // spyTrackId.mockRestore(); + // }); + // }); describe('trackId', () => { it('stores hash in memory when `isStored` is `false` for when `save` is called', async () => { @@ -282,20 +281,21 @@ describe('SearchSessionService', () => { get: () => mockIdMapping, }); - await service.trackId( - searchRequest, - searchId, - { sessionId, isStored, strategy: MOCK_STRATEGY }, - { savedObjectsClient } - ); + await service.trackId({ savedObjectsClient }, searchRequest, searchId, { + sessionId, + isStored, + strategy: MOCK_STRATEGY, + }); expect(savedObjectsClient.update).not.toHaveBeenCalled(); - await service.save( - sessionId, - { name, created, expires, appId, urlGeneratorId }, - { savedObjectsClient } - ); + await service.save({ savedObjectsClient }, sessionId, { + name, + created, + expires, + appId, + urlGeneratorId, + }); expect(savedObjectsClient.create).toHaveBeenCalledWith( SEARCH_SESSION_TYPE, @@ -326,12 +326,11 @@ describe('SearchSessionService', () => { const searchId = 'FnpFYlBpeXdCUTMyZXhCLTc1TWFKX0EbdDFDTzJzTE1Sck9PVTBIcW1iU05CZzo4MDA0'; const isStored = true; - await service.trackId( - searchRequest, - searchId, - { sessionId, isStored, strategy: MOCK_STRATEGY }, - { savedObjectsClient } - ); + await service.trackId({ savedObjectsClient }, searchRequest, searchId, { + sessionId, + isStored, + strategy: MOCK_STRATEGY, + }); expect(savedObjectsClient.update).toHaveBeenCalledWith(SEARCH_SESSION_TYPE, sessionId, { idMapping: { @@ -350,7 +349,7 @@ describe('SearchSessionService', () => { const searchRequest = { params: {} }; expect(() => - service.getId(searchRequest, {}, { savedObjectsClient }) + service.getId({ savedObjectsClient }, searchRequest, {}) ).rejects.toMatchInlineSnapshot(`[Error: Session ID is required]`); }); @@ -358,7 +357,7 @@ describe('SearchSessionService', () => { const searchRequest = { params: {} }; expect(() => - service.getId(searchRequest, { sessionId, isStored: false }, { savedObjectsClient }) + service.getId({ savedObjectsClient }, searchRequest, { sessionId, isStored: false }) ).rejects.toMatchInlineSnapshot( `[Error: Cannot get search ID from a session that is not stored]` ); @@ -368,11 +367,11 @@ describe('SearchSessionService', () => { const searchRequest = { params: {} }; expect(() => - service.getId( - searchRequest, - { sessionId, isStored: true, isRestore: false }, - { savedObjectsClient } - ) + service.getId({ savedObjectsClient }, searchRequest, { + sessionId, + isStored: true, + isRestore: false, + }) ).rejects.toMatchInlineSnapshot( `[Error: Get search ID is only supported when restoring a session]` ); @@ -400,11 +399,11 @@ describe('SearchSessionService', () => { }; savedObjectsClient.get.mockResolvedValue(mockSession); - const id = await service.getId( - searchRequest, - { sessionId, isStored: true, isRestore: true }, - { savedObjectsClient } - ); + const id = await service.getId({ savedObjectsClient }, searchRequest, { + sessionId, + isStored: true, + isRestore: true, + }); expect(id).toBe(searchId); }); diff --git a/x-pack/plugins/data_enhanced/server/search/session/session_service.ts b/x-pack/plugins/data_enhanced/server/search/session/session_service.ts index 8c9e0dad4957e..5f48c8d9c1586 100644 --- a/x-pack/plugins/data_enhanced/server/search/session/session_service.ts +++ b/x-pack/plugins/data_enhanced/server/search/session/session_service.ts @@ -5,39 +5,34 @@ */ import moment, { Moment } from 'moment'; -import { from, Observable } from 'rxjs'; -import { first, switchMap } from 'rxjs/operators'; +import { Observable } from 'rxjs'; +import { first } from 'rxjs/operators'; +import dateMath from '@elastic/datemath'; import { + CoreSetup, CoreStart, KibanaRequest, - SavedObjectsClient, - SavedObjectsClientContract, Logger, SavedObject, - CoreSetup, SavedObjectsBulkUpdateObject, + SavedObjectsClient, + SavedObjectsClientContract, SavedObjectsFindOptions, } from '../../../../../../src/core/server'; import { IKibanaSearchRequest, - IKibanaSearchResponse, ISearchOptions, KueryNode, nodeBuilder, - tapFirst, } from '../../../../../../src/plugins/data/common'; -import { - ISearchStrategy, - ISessionService, - SearchStrategyDependencies, -} from '../../../../../../src/plugins/data/server'; +import { ISearchSessionService } from '../../../../../../src/plugins/data/server'; import { TaskManagerSetupContract, TaskManagerStartContract, } from '../../../../task_manager/server'; import { - SearchSessionSavedObjectAttributes, SearchSessionRequestInfo, + SearchSessionSavedObjectAttributes, SearchSessionStatus, } from '../../../common'; import { SEARCH_SESSION_TYPE } from '../../saved_objects'; @@ -71,7 +66,8 @@ interface StartDependencies { taskManager: TaskManagerStartContract; config$: Observable; } -export class SearchSessionService implements ISessionService { +export class SearchSessionService + implements ISearchSessionService { /** * Map of sessionId to { [requestHash]: searchId } * @private @@ -224,33 +220,9 @@ export class SearchSessionService implements ISessionService { return updateResults.saved_objects; } - public search( - strategy: ISearchStrategy, - searchRequest: Request, - options: ISearchOptions, - searchDeps: SearchStrategyDependencies, - deps: SearchSessionDependencies - ): Observable { - // If this is a restored background search session, look up the ID using the provided sessionId - const getSearchRequest = async () => - !options.isRestore || searchRequest.id - ? searchRequest - : { - ...searchRequest, - id: await this.getId(searchRequest, options, deps), - }; - - return from(getSearchRequest()).pipe( - switchMap((request) => strategy.search(request, options, searchDeps)), - tapFirst((response) => { - if (searchRequest.id || !options.sessionId || !response.id || options.isRestore) return; - this.trackId(searchRequest, response.id, options, deps); - }) - ); - } - // TODO: Generate the `userId` from the realm type/realm name/username public save = async ( + { savedObjectsClient }: SearchSessionDependencies, sessionId: string, { name, @@ -261,8 +233,7 @@ export class SearchSessionService implements ISessionService { urlGeneratorId, initialState = {}, restoreState = {}, - }: Partial, - { savedObjectsClient }: SearchSessionDependencies + }: Partial ) => { if (!name) throw new Error('Name is required'); if (!appId) throw new Error('AppId is required'); @@ -292,7 +263,7 @@ export class SearchSessionService implements ISessionService { }; // TODO: Throw an error if this session doesn't belong to this user - public get = (sessionId: string, { savedObjectsClient }: SearchSessionDependencies) => { + public get = ({ savedObjectsClient }: SearchSessionDependencies, sessionId: string) => { this.logger.debug(`get | ${sessionId}`); return savedObjectsClient.get( SEARCH_SESSION_TYPE, @@ -302,8 +273,8 @@ export class SearchSessionService implements ISessionService { // TODO: Throw an error if this session doesn't belong to this user public find = ( - options: Omit, - { savedObjectsClient }: SearchSessionDependencies + { savedObjectsClient }: SearchSessionDependencies, + options: Omit ) => { return savedObjectsClient.find({ ...options, @@ -313,9 +284,9 @@ export class SearchSessionService implements ISessionService { // TODO: Throw an error if this session doesn't belong to this user public update = ( + { savedObjectsClient }: SearchSessionDependencies, sessionId: string, - attributes: Partial, - { savedObjectsClient }: SearchSessionDependencies + attributes: Partial ) => { this.logger.debug(`update | ${sessionId}`); return savedObjectsClient.update( @@ -325,8 +296,22 @@ export class SearchSessionService implements ISessionService { ); }; + public extend(deps: SearchSessionDependencies, sessionId: string, keepAlive: string) { + this.logger.debug(`extend | ${sessionId}`); + + // Calculate the new `expires` value given the `keepAlive` + const expiresMoment = dateMath.parse(`now+${keepAlive}`); + if (!expiresMoment || isNaN(expiresMoment.date())) { + throw new Error(`"${keepAlive}" is not a valid value for keepAlive`); + } + const expires = expiresMoment.toISOString(); + + // Update the `expires` value in the search session saved object + return this.update(deps, sessionId, { expires }); + } + // TODO: Throw an error if this session doesn't belong to this user - public delete = (sessionId: string, { savedObjectsClient }: SearchSessionDependencies) => { + public delete = ({ savedObjectsClient }: SearchSessionDependencies, sessionId: string) => { return savedObjectsClient.delete(SEARCH_SESSION_TYPE, sessionId); }; @@ -336,10 +321,10 @@ export class SearchSessionService implements ISessionService { * @internal */ public trackId = async ( + deps: SearchSessionDependencies, searchRequest: IKibanaSearchRequest, searchId: string, - { sessionId, isStored, strategy }: ISearchOptions, - deps: SearchSessionDependencies + { sessionId, isStored, strategy }: ISearchOptions ) => { if (!sessionId || !searchId) return; this.logger.debug(`trackId | ${sessionId} | ${searchId}`); @@ -356,7 +341,7 @@ export class SearchSessionService implements ISessionService { const attributes = { idMapping: { [requestHash]: searchInfo }, }; - await this.update(sessionId, attributes, deps); + await this.update(deps, sessionId, attributes); } else { const map = this.sessionSearchMap.get(sessionId) ?? { insertTime: moment(), @@ -368,15 +353,24 @@ export class SearchSessionService implements ISessionService { } }; + public async getSearchIdMapping(deps: SearchSessionDependencies, sessionId: string) { + const searchSession = await this.get(deps, sessionId); + const searchIdMapping = new Map(); + Object.values(searchSession.attributes.idMapping).forEach((requestInfo) => { + searchIdMapping.set(requestInfo.id, requestInfo.strategy); + }); + return searchIdMapping; + } + /** * Look up an existing search ID that matches the given request in the given session so that the * request can continue rather than restart. * @internal */ public getId = async ( + deps: SearchSessionDependencies, searchRequest: IKibanaSearchRequest, - { sessionId, isStored, isRestore }: ISearchOptions, - deps: SearchSessionDependencies + { sessionId, isStored, isRestore }: ISearchOptions ) => { if (!sessionId) { throw new Error('Session ID is required'); @@ -386,7 +380,7 @@ export class SearchSessionService implements ISessionService { throw new Error('Get search ID is only supported when restoring a session'); } - const session = await this.get(sessionId, deps); + const session = await this.get(deps, sessionId); const requestHash = createRequestHash(searchRequest.params); if (!session.attributes.idMapping.hasOwnProperty(requestHash)) { throw new Error('No search ID in this session matching the given search request'); @@ -402,17 +396,15 @@ export class SearchSessionService implements ISessionService { }); const deps = { savedObjectsClient }; return { - search: ( - strategy: ISearchStrategy, - ...args: Parameters['search']> - ) => this.search(strategy, ...args, deps), - save: (sessionId: string, attributes: Partial) => - this.save(sessionId, attributes, deps), - get: (sessionId: string) => this.get(sessionId, deps), - find: (options: SavedObjectsFindOptions) => this.find(options, deps), - update: (sessionId: string, attributes: Partial) => - this.update(sessionId, attributes, deps), - delete: (sessionId: string) => this.delete(sessionId, deps), + getId: this.getId.bind(this, deps), + trackId: this.trackId.bind(this, deps), + getSearchIdMapping: this.getSearchIdMapping.bind(this, deps), + save: this.save.bind(this, deps), + get: this.get.bind(this, deps), + find: this.find.bind(this, deps), + update: this.update.bind(this, deps), + extend: this.extend.bind(this, deps), + delete: this.delete.bind(this, deps), }; }; }; From 70407160a32e69ae0327e695bf5808b6ec864c87 Mon Sep 17 00:00:00 2001 From: Lukas Olson Date: Fri, 15 Jan 2021 14:10:18 -0700 Subject: [PATCH 02/20] Fix types --- .../data/public/search/session/mocks.ts | 1 + src/plugins/data/server/search/mocks.ts | 9 +++++ .../data/server/search/session/mocks.ts | 36 +++++++++++++++++++ .../log_entry_search_strategy.test.ts | 2 ++ 4 files changed, 48 insertions(+) create mode 100644 src/plugins/data/server/search/session/mocks.ts diff --git a/src/plugins/data/public/search/session/mocks.ts b/src/plugins/data/public/search/session/mocks.ts index 13dd054c122d5..69157a6b3b87a 100644 --- a/src/plugins/data/public/search/session/mocks.ts +++ b/src/plugins/data/public/search/session/mocks.ts @@ -28,6 +28,7 @@ export function getSessionsClientMock(): jest.Mocked { create: jest.fn(), find: jest.fn(), update: jest.fn(), + extend: jest.fn(), delete: jest.fn(), }; } diff --git a/src/plugins/data/server/search/mocks.ts b/src/plugins/data/server/search/mocks.ts index 4914726c85ef8..efa12f6efa915 100644 --- a/src/plugins/data/server/search/mocks.ts +++ b/src/plugins/data/server/search/mocks.ts @@ -21,6 +21,8 @@ import { ISearchSetup, ISearchStart } from './types'; import { searchAggsSetupMock, searchAggsStartMock } from './aggs/mocks'; import { searchSourceMock } from './search_source/mocks'; +export { createSearchSessionsClientMock } from './session/mocks'; + export function createSearchSetupMock(): jest.Mocked { return { aggs: searchAggsSetupMock(), @@ -36,6 +38,13 @@ export function createSearchStartMock(): jest.Mocked { asScoped: jest.fn().mockReturnValue({ search: jest.fn(), cancel: jest.fn(), + extend: jest.fn(), + saveSession: jest.fn(), + getSession: jest.fn(), + findSessions: jest.fn(), + updateSession: jest.fn(), + extendSession: jest.fn(), + deleteSession: jest.fn(), }), searchSource: searchSourceMock.createStartContract(), }; diff --git a/src/plugins/data/server/search/session/mocks.ts b/src/plugins/data/server/search/session/mocks.ts new file mode 100644 index 0000000000000..52742d955d221 --- /dev/null +++ b/src/plugins/data/server/search/session/mocks.ts @@ -0,0 +1,36 @@ +/* + * 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 { IScopedSearchSessionsClient } from './types'; + +export function createSearchSessionsClientMock(): jest.Mocked< + IScopedSearchSessionsClient +> { + return { + getId: jest.fn(), + trackId: jest.fn(), + getSearchIdMapping: jest.fn(), + save: jest.fn(), + get: jest.fn(), + find: jest.fn(), + update: jest.fn(), + delete: jest.fn(), + extend: jest.fn(), + }; +} diff --git a/x-pack/plugins/infra/server/services/log_entries/log_entry_search_strategy.test.ts b/x-pack/plugins/infra/server/services/log_entries/log_entry_search_strategy.test.ts index 38626675f5ae7..69bbca9fd8259 100644 --- a/x-pack/plugins/infra/server/services/log_entries/log_entry_search_strategy.test.ts +++ b/x-pack/plugins/infra/server/services/log_entries/log_entry_search_strategy.test.ts @@ -22,6 +22,7 @@ import { logEntrySearchRequestStateRT, logEntrySearchStrategyProvider, } from './log_entry_search_strategy'; +import { createSearchSessionsClientMock } from '../../../../../../src/plugins/data/server/search/mocks'; describe('LogEntry search strategy', () => { it('handles initial search requests', async () => { @@ -244,6 +245,7 @@ const createSearchStrategyDependenciesMock = (): SearchStrategyDependencies => ( uiSettingsClient: uiSettingsServiceMock.createClient(), esClient: elasticsearchServiceMock.createScopedClusterClient(), savedObjectsClient: savedObjectsClientMock.create(), + searchSessionsClient: createSearchSessionsClientMock(), }); // using the official data mock from within x-pack doesn't type-check successfully, From eeddf84146af66df8c630fcb29ddf6a1f66c734d Mon Sep 17 00:00:00 2001 From: Lukas Olson Date: Fri, 15 Jan 2021 14:57:47 -0700 Subject: [PATCH 03/20] Fix tests and switch to cancel --- src/plugins/data/server/search/mocks.ts | 2 +- .../data/server/search/search_service.ts | 6 +- .../data/server/search/session/mocks.ts | 2 +- .../server/search/session/session_service.ts | 4 +- .../data/server/search/session/types.ts | 2 +- src/plugins/data/server/search/types.ts | 2 +- .../server/routes/session.test.ts | 4 +- .../data_enhanced/server/routes/session.ts | 2 +- .../search/session/session_service.test.ts | 123 +++++------------- .../server/search/session/session_service.ts | 8 +- 10 files changed, 53 insertions(+), 102 deletions(-) diff --git a/src/plugins/data/server/search/mocks.ts b/src/plugins/data/server/search/mocks.ts index efa12f6efa915..a244185d21dcc 100644 --- a/src/plugins/data/server/search/mocks.ts +++ b/src/plugins/data/server/search/mocks.ts @@ -44,7 +44,7 @@ export function createSearchStartMock(): jest.Mocked { findSessions: jest.fn(), updateSession: jest.fn(), extendSession: jest.fn(), - deleteSession: jest.fn(), + cancelSession: jest.fn(), }), searchSource: searchSourceMock.createStartContract(), }; diff --git a/src/plugins/data/server/search/search_service.ts b/src/plugins/data/server/search/search_service.ts index 56a8b7eeffb4b..c8306a3534c00 100644 --- a/src/plugins/data/server/search/search_service.ts +++ b/src/plugins/data/server/search/search_service.ts @@ -351,7 +351,7 @@ export class SearchService implements Plugin { return strategy.extend(id, keepAlive, options, deps); }; - private deleteSession = async (deps: SearchStrategyDependencies, sessionId: string) => { + private cancelSession = async (deps: SearchStrategyDependencies, sessionId: string) => { const searchIdMapping = await deps.searchSessionsClient.getSearchIdMapping(sessionId); for (const [searchId, strategyName] of searchIdMapping.entries()) { @@ -363,7 +363,7 @@ export class SearchService implements Plugin { await this.cancel(deps, searchId, searchOptions); } - return deps.searchSessionsClient.delete(sessionId); + return deps.searchSessionsClient.cancel(sessionId); }; private extendSession = async ( @@ -413,7 +413,7 @@ export class SearchService implements Plugin { findSessions: searchSessionsClient.find, updateSession: searchSessionsClient.update, extendSession: this.extendSession.bind(this, deps), - deleteSession: this.deleteSession.bind(this, deps), + cancelSession: this.cancelSession.bind(this, deps), }; }; }; diff --git a/src/plugins/data/server/search/session/mocks.ts b/src/plugins/data/server/search/session/mocks.ts index 52742d955d221..6f317876cb0ec 100644 --- a/src/plugins/data/server/search/session/mocks.ts +++ b/src/plugins/data/server/search/session/mocks.ts @@ -30,7 +30,7 @@ export function createSearchSessionsClientMock(): jest.Mocked< get: jest.fn(), find: jest.fn(), update: jest.fn(), - delete: jest.fn(), + cancel: jest.fn(), extend: jest.fn(), }; } diff --git a/src/plugins/data/server/search/session/session_service.ts b/src/plugins/data/server/search/session/session_service.ts index c27a4c335d9b4..36eb7bea0e2f6 100644 --- a/src/plugins/data/server/search/session/session_service.ts +++ b/src/plugins/data/server/search/session/session_service.ts @@ -48,8 +48,8 @@ export class SearchSessionService implements ISearchSessionService { extend: async () => { throw new Error('extend not implemented in OSS search session service'); }, - delete: async () => { - throw new Error('delete not implemented in OSS search session service'); + cancel: async () => { + throw new Error('cancel not implemented in OSS search session service'); }, }); } diff --git a/src/plugins/data/server/search/session/types.ts b/src/plugins/data/server/search/session/types.ts index ea591dbe78282..188a32482e8c8 100644 --- a/src/plugins/data/server/search/session/types.ts +++ b/src/plugins/data/server/search/session/types.ts @@ -39,7 +39,7 @@ export interface IScopedSearchSessionsClient { get: (sessionId: string) => Promise>; find: (options: Omit) => Promise>; update: (sessionId: string, attributes: Partial) => Promise>; - delete: (sessionId: string) => Promise<{}>; + cancel: (sessionId: string) => Promise<{}>; extend: (sessionId: string, keepAlive: string) => Promise>; } diff --git a/src/plugins/data/server/search/types.ts b/src/plugins/data/server/search/types.ts index 988fb00f53fb0..50fdd9a6fe818 100644 --- a/src/plugins/data/server/search/types.ts +++ b/src/plugins/data/server/search/types.ts @@ -100,7 +100,7 @@ export interface IScopedSearchClient extends ISearchClient { getSession: IScopedSearchSessionsClient['get']; findSessions: IScopedSearchSessionsClient['find']; updateSession: IScopedSearchSessionsClient['update']; - deleteSession: IScopedSearchSessionsClient['delete']; + cancelSession: IScopedSearchSessionsClient['cancel']; extendSession: IScopedSearchSessionsClient['extend']; } diff --git a/x-pack/plugins/data_enhanced/server/routes/session.test.ts b/x-pack/plugins/data_enhanced/server/routes/session.test.ts index 5683b4c99ff96..b8d8d3c8da557 100644 --- a/x-pack/plugins/data_enhanced/server/routes/session.test.ts +++ b/x-pack/plugins/data_enhanced/server/routes/session.test.ts @@ -89,7 +89,7 @@ describe('registerSessionRoutes', () => { expect(mockContext.search!.updateSession).toHaveBeenCalledWith(id, body); }); - it('delete calls deleteSession with id', async () => { + it('delete calls cancelSession with id', async () => { const id = 'd7170a35-7e2c-48d6-8dec-9a056721b489'; const params = { id }; @@ -101,6 +101,6 @@ describe('registerSessionRoutes', () => { deleteHandler(mockContext, mockRequest, mockResponse); - expect(mockContext.search!.deleteSession).toHaveBeenCalledWith(id); + expect(mockContext.search!.cancelSession).toHaveBeenCalledWith(id); }); }); diff --git a/x-pack/plugins/data_enhanced/server/routes/session.ts b/x-pack/plugins/data_enhanced/server/routes/session.ts index 0683679eea95f..37d7cdacec7e2 100644 --- a/x-pack/plugins/data_enhanced/server/routes/session.ts +++ b/x-pack/plugins/data_enhanced/server/routes/session.ts @@ -123,7 +123,7 @@ export function registerSessionRoutes(router: IRouter): void { async (context, request, res) => { const { id } = request.params; try { - await context.search!.deleteSession(id); + await context.search!.cancelSession(id); return res.ok(); } catch (e) { diff --git a/x-pack/plugins/data_enhanced/server/search/session/session_service.test.ts b/x-pack/plugins/data_enhanced/server/search/session/session_service.test.ts index 6aca8aa728c6d..6ace3cc11b8d7 100644 --- a/x-pack/plugins/data_enhanced/server/search/session/session_service.test.ts +++ b/x-pack/plugins/data_enhanced/server/search/session/session_service.test.ts @@ -198,96 +198,14 @@ describe('SearchSessionService', () => { ); }); - it('delete calls saved objects client', async () => { - savedObjectsClient.delete.mockResolvedValue({}); + it('cancel updates object status', async () => { + await service.cancel({ savedObjectsClient }, sessionId); - const response = await service.delete({ savedObjectsClient }, sessionId); - - expect(response).toEqual({}); - expect(savedObjectsClient.delete).toHaveBeenCalledWith(SEARCH_SESSION_TYPE, sessionId); + expect(savedObjectsClient.update).toHaveBeenCalledWith(SEARCH_SESSION_TYPE, sessionId, { + status: SearchSessionStatus.CANCELLED, + }); }); - // describe('search', () => { - // const mockSearch = jest.fn().mockReturnValue(of({})); - // const mockStrategy = { search: mockSearch }; - // const mockSearchDeps = {} as SearchStrategyDependencies; - // const mockDeps = {} as SearchSessionDependencies; - // - // beforeEach(() => { - // mockSearch.mockClear(); - // }); - // - // it('searches using the original request if not restoring', async () => { - // const searchRequest = { params: {} }; - // const options = { sessionId, isStored: false, isRestore: false }; - // - // await service - // .search(mockStrategy, searchRequest, options, mockSearchDeps, mockDeps) - // .toPromise(); - // - // expect(mockSearch).toBeCalledWith(searchRequest, options, mockSearchDeps); - // }); - // - // it('searches using the original request if `id` is provided', async () => { - // const searchId = 'FnpFYlBpeXdCUTMyZXhCLTc1TWFKX0EbdDFDTzJzTE1Sck9PVTBIcW1iU05CZzo4MDA0'; - // const searchRequest = { id: searchId, params: {} }; - // const options = { sessionId, isStored: true, isRestore: true }; - // - // await service - // .search(mockStrategy, searchRequest, options, mockSearchDeps, mockDeps) - // .toPromise(); - // - // expect(mockSearch).toBeCalledWith(searchRequest, options, mockSearchDeps); - // }); - // - // it('searches by looking up an `id` if restoring and `id` is not provided', async () => { - // const searchRequest = { params: {} }; - // const options = { sessionId, isStored: true, isRestore: true }; - // const spyGetId = jest.spyOn(service, 'getId').mockResolvedValueOnce('my_id'); - // - // await service - // .search(mockStrategy, searchRequest, options, mockSearchDeps, mockDeps) - // .toPromise(); - // - // expect(mockSearch).toBeCalledWith({ ...searchRequest, id: 'my_id' }, options, mockSearchDeps); - // - // spyGetId.mockRestore(); - // }); - // - // it('calls `trackId` once if the response contains an `id` and not restoring', async () => { - // const searchRequest = { params: {} }; - // const options = { sessionId, isStored: false, isRestore: false }; - // const spyTrackId = jest.spyOn(service, 'trackId').mockResolvedValue(); - // mockSearch.mockReturnValueOnce(of({ id: 'my_id' }, { id: 'my_id' })); - // - // await service - // .search(mockStrategy, searchRequest, options, mockSearchDeps, mockDeps) - // .toPromise(); - // - // expect(spyTrackId).toBeCalledTimes(1); - // expect(spyTrackId).toBeCalledWith(searchRequest, 'my_id', options, {}); - // - // spyTrackId.mockRestore(); - // }); - // - // it('does not call `trackId` if restoring', async () => { - // const searchRequest = { params: {} }; - // const options = { sessionId, isStored: true, isRestore: true }; - // const spyGetId = jest.spyOn(service, 'getId').mockResolvedValueOnce('my_id'); - // const spyTrackId = jest.spyOn(service, 'trackId').mockResolvedValue(); - // mockSearch.mockReturnValueOnce(of({ id: 'my_id' })); - // - // await service - // .search(mockStrategy, searchRequest, options, mockSearchDeps, mockDeps) - // .toPromise(); - // - // expect(spyTrackId).not.toBeCalled(); - // - // spyGetId.mockRestore(); - // spyTrackId.mockRestore(); - // }); - // }); - describe('trackId', () => { it('stores hash in memory when `isStored` is `false` for when `save` is called', async () => { const searchRequest = { params: {} }; @@ -435,6 +353,37 @@ describe('SearchSessionService', () => { }); }); + describe('getSearchIdMapping', () => { + it('retrieves the search IDs and strategies from the saved object', async () => { + const mockSession = { + id: 'd7170a35-7e2c-48d6-8dec-9a056721b489', + type: SEARCH_SESSION_TYPE, + attributes: { + name: 'my_name', + appId: 'my_app_id', + urlGeneratorId: 'my_url_generator_id', + idMapping: { + foo: { + id: 'FnpFYlBpeXdCUTMyZXhCLTc1TWFKX0EbdDFDTzJzTE1Sck9PVTBIcW1iU05CZzo4MDA0', + strategy: MOCK_STRATEGY, + }, + }, + }, + references: [], + }; + savedObjectsClient.get.mockResolvedValue(mockSession); + const searchIdMapping = await service.getSearchIdMapping( + { savedObjectsClient }, + mockSession.id + ); + expect(searchIdMapping).toMatchInlineSnapshot(` + Map { + "FnpFYlBpeXdCUTMyZXhCLTc1TWFKX0EbdDFDTzJzTE1Sck9PVTBIcW1iU05CZzo4MDA0" => "ese", + } + `); + }); + }); + describe('Monitor', () => { it('schedules the next iteration', async () => { const findSpy = jest.fn().mockResolvedValue({ saved_objects: [] }); diff --git a/x-pack/plugins/data_enhanced/server/search/session/session_service.ts b/x-pack/plugins/data_enhanced/server/search/session/session_service.ts index 59b36fc2626b5..cabfab83027d3 100644 --- a/x-pack/plugins/data_enhanced/server/search/session/session_service.ts +++ b/x-pack/plugins/data_enhanced/server/search/session/session_service.ts @@ -315,8 +315,10 @@ export class SearchSessionService } // TODO: Throw an error if this session doesn't belong to this user - public delete = ({ savedObjectsClient }: SearchSessionDependencies, sessionId: string) => { - return savedObjectsClient.delete(SEARCH_SESSION_TYPE, sessionId); + public cancel = (deps: SearchSessionDependencies, sessionId: string) => { + return this.update(deps, sessionId, { + status: SearchSessionStatus.CANCELLED, + }); }; /** @@ -408,7 +410,7 @@ export class SearchSessionService find: this.find.bind(this, deps), update: this.update.bind(this, deps), extend: this.extend.bind(this, deps), - delete: this.delete.bind(this, deps), + cancel: this.cancel.bind(this, deps), }; }; }; From f09eb386aa2b280089bd034b0862590e4371fa58 Mon Sep 17 00:00:00 2001 From: Lukas Olson Date: Fri, 15 Jan 2021 15:01:58 -0700 Subject: [PATCH 04/20] Update docs --- ....isearchsessionservice.asscopedprovider.md | 11 ++++ ...ugins-data-server.isearchsessionservice.md | 18 +++++ ...ugins-data-server.isearchstart.asscoped.md | 2 +- ...plugin-plugins-data-server.isearchstart.md | 2 +- ...server.isessionservice.asscopedprovider.md | 11 ---- ...gin-plugins-data-server.isessionservice.md | 18 ----- .../kibana-plugin-plugins-data-server.md | 4 +- ...rver.searchsessionservice._constructor_.md | 13 ++++ ...r.searchsessionservice.asscopedprovider.md | 35 ++++++++++ ...lugins-data-server.searchsessionservice.md | 26 ++++++++ ...-data-server.searchstrategydependencies.md | 1 + ...rategydependencies.searchsessionsclient.md | 11 ++++ ...ata-server.sessionservice._constructor_.md | 13 ---- ...-server.sessionservice.asscopedprovider.md | 26 -------- ...ugin-plugins-data-server.sessionservice.md | 27 -------- ...ugins-data-server.sessionservice.search.md | 23 ------- src/plugins/data/server/server.api.md | 66 +++++++++++-------- 17 files changed, 158 insertions(+), 149 deletions(-) create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchsessionservice.asscopedprovider.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchsessionservice.md delete mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isessionservice.asscopedprovider.md delete mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isessionservice.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.searchsessionservice._constructor_.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.searchsessionservice.asscopedprovider.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.searchsessionservice.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.searchstrategydependencies.searchsessionsclient.md delete mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.sessionservice._constructor_.md delete mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.sessionservice.asscopedprovider.md delete mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.sessionservice.md delete mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.sessionservice.search.md diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchsessionservice.asscopedprovider.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchsessionservice.asscopedprovider.md new file mode 100644 index 0000000000000..3f3d1a2429933 --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchsessionservice.asscopedprovider.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [ISearchSessionService](./kibana-plugin-plugins-data-server.isearchsessionservice.md) > [asScopedProvider](./kibana-plugin-plugins-data-server.isearchsessionservice.asscopedprovider.md) + +## ISearchSessionService.asScopedProvider property + +Signature: + +```typescript +asScopedProvider: (core: CoreStart) => (request: KibanaRequest) => IScopedSearchSessionsClient; +``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchsessionservice.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchsessionservice.md new file mode 100644 index 0000000000000..e7a92497308b9 --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchsessionservice.md @@ -0,0 +1,18 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [ISearchSessionService](./kibana-plugin-plugins-data-server.isearchsessionservice.md) + +## ISearchSessionService interface + +Signature: + +```typescript +export interface ISearchSessionService +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [asScopedProvider](./kibana-plugin-plugins-data-server.isearchsessionservice.asscopedprovider.md) | (core: CoreStart) => (request: KibanaRequest) => IScopedSearchSessionsClient<T> | | + diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstart.asscoped.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstart.asscoped.md index f97cc22a53001..1c65aeb8f137f 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstart.asscoped.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstart.asscoped.md @@ -7,5 +7,5 @@ Signature: ```typescript -asScoped: (request: KibanaRequest) => ISearchClient; +asScoped: (request: KibanaRequest) => IScopedSearchClient; ``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstart.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstart.md index 771b529f23824..52579a0a14b4d 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstart.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstart.md @@ -15,7 +15,7 @@ export interface ISearchStartAggsStart | | -| [asScoped](./kibana-plugin-plugins-data-server.isearchstart.asscoped.md) | (request: KibanaRequest) => ISearchClient | | +| [asScoped](./kibana-plugin-plugins-data-server.isearchstart.asscoped.md) | (request: KibanaRequest) => IScopedSearchClient | | | [getSearchStrategy](./kibana-plugin-plugins-data-server.isearchstart.getsearchstrategy.md) | (name?: string) => ISearchStrategy<SearchStrategyRequest, SearchStrategyResponse> | Get other registered search strategies by name (or, by default, the Elasticsearch strategy). For example, if a new strategy needs to use the already-registered ES search strategy, it can use this function to accomplish that. | | [searchSource](./kibana-plugin-plugins-data-server.isearchstart.searchsource.md) | {
asScoped: (request: KibanaRequest) => Promise<ISearchStartSearchSource>;
} | | diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isessionservice.asscopedprovider.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isessionservice.asscopedprovider.md deleted file mode 100644 index d52b9b783919b..0000000000000 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isessionservice.asscopedprovider.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [ISessionService](./kibana-plugin-plugins-data-server.isessionservice.md) > [asScopedProvider](./kibana-plugin-plugins-data-server.isessionservice.asscopedprovider.md) - -## ISessionService.asScopedProvider property - -Signature: - -```typescript -asScopedProvider: (core: CoreStart) => (request: KibanaRequest) => IScopedSessionService; -``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isessionservice.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isessionservice.md deleted file mode 100644 index dcc7dfc8bb946..0000000000000 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isessionservice.md +++ /dev/null @@ -1,18 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [ISessionService](./kibana-plugin-plugins-data-server.isessionservice.md) - -## ISessionService interface - -Signature: - -```typescript -export interface ISessionService -``` - -## Properties - -| Property | Type | Description | -| --- | --- | --- | -| [asScopedProvider](./kibana-plugin-plugins-data-server.isessionservice.asscopedprovider.md) | (core: CoreStart) => (request: KibanaRequest) => IScopedSessionService | | - diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.md index 75227575038ab..2d9f28c1effa1 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.md @@ -14,7 +14,7 @@ | [IndexPatternsService](./kibana-plugin-plugins-data-server.indexpatternsservice.md) | | | [OptionedParamType](./kibana-plugin-plugins-data-server.optionedparamtype.md) | | | [Plugin](./kibana-plugin-plugins-data-server.plugin.md) | | -| [SessionService](./kibana-plugin-plugins-data-server.sessionservice.md) | The OSS session service. See data\_enhanced in X-Pack for the background session service. | +| [SearchSessionService](./kibana-plugin-plugins-data-server.searchsessionservice.md) | The OSS session service, which leaves most search session-related logic unimplemented. x-pack/plugins/data\_enhanced/server/search/session/session\_service.ts | ## Enumerations @@ -53,10 +53,10 @@ | [IFieldType](./kibana-plugin-plugins-data-server.ifieldtype.md) | | | [IndexPatternAttributes](./kibana-plugin-plugins-data-server.indexpatternattributes.md) | | | [ISearchOptions](./kibana-plugin-plugins-data-server.isearchoptions.md) | | +| [ISearchSessionService](./kibana-plugin-plugins-data-server.isearchsessionservice.md) | | | [ISearchSetup](./kibana-plugin-plugins-data-server.isearchsetup.md) | | | [ISearchStart](./kibana-plugin-plugins-data-server.isearchstart.md) | | | [ISearchStrategy](./kibana-plugin-plugins-data-server.isearchstrategy.md) | Search strategy interface contains a search method that takes in a request and returns a promise that resolves to a response. | -| [ISessionService](./kibana-plugin-plugins-data-server.isessionservice.md) | | | [KueryNode](./kibana-plugin-plugins-data-server.kuerynode.md) | | | [OptionedValueProp](./kibana-plugin-plugins-data-server.optionedvalueprop.md) | | | [PluginSetup](./kibana-plugin-plugins-data-server.pluginsetup.md) | | diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.searchsessionservice._constructor_.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.searchsessionservice._constructor_.md new file mode 100644 index 0000000000000..c34d033d01973 --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.searchsessionservice._constructor_.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [SearchSessionService](./kibana-plugin-plugins-data-server.searchsessionservice.md) > [(constructor)](./kibana-plugin-plugins-data-server.searchsessionservice._constructor_.md) + +## SearchSessionService.(constructor) + +Constructs a new instance of the `SearchSessionService` class + +Signature: + +```typescript +constructor(); +``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.searchsessionservice.asscopedprovider.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.searchsessionservice.asscopedprovider.md new file mode 100644 index 0000000000000..4faa7b7663546 --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.searchsessionservice.asscopedprovider.md @@ -0,0 +1,35 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [SearchSessionService](./kibana-plugin-plugins-data-server.searchsessionservice.md) > [asScopedProvider](./kibana-plugin-plugins-data-server.searchsessionservice.asscopedprovider.md) + +## SearchSessionService.asScopedProvider() method + +Signature: + +```typescript +asScopedProvider(): () => { + getId: () => never; + trackId: () => Promise; + getSearchIdMapping: () => Promise>; + save: () => Promise; + get: () => Promise; + find: () => Promise; + update: () => Promise; + extend: () => Promise; + cancel: () => Promise; + }; +``` +Returns: + +`() => { + getId: () => never; + trackId: () => Promise; + getSearchIdMapping: () => Promise>; + save: () => Promise; + get: () => Promise; + find: () => Promise; + update: () => Promise; + extend: () => Promise; + cancel: () => Promise; + }` + diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.searchsessionservice.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.searchsessionservice.md new file mode 100644 index 0000000000000..2f12d2981b31c --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.searchsessionservice.md @@ -0,0 +1,26 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [SearchSessionService](./kibana-plugin-plugins-data-server.searchsessionservice.md) + +## SearchSessionService class + +The OSS session service, which leaves most search session-related logic unimplemented. x-pack/plugins/data\_enhanced/server/search/session/session\_service.ts + +Signature: + +```typescript +export declare class SearchSessionService implements ISearchSessionService +``` + +## Constructors + +| Constructor | Modifiers | Description | +| --- | --- | --- | +| [(constructor)()](./kibana-plugin-plugins-data-server.searchsessionservice._constructor_.md) | | Constructs a new instance of the SearchSessionService class | + +## Methods + +| Method | Modifiers | Description | +| --- | --- | --- | +| [asScopedProvider()](./kibana-plugin-plugins-data-server.searchsessionservice.asscopedprovider.md) | | | + diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.searchstrategydependencies.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.searchstrategydependencies.md index be95fb04a2c4f..b47e00542da97 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.searchstrategydependencies.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.searchstrategydependencies.md @@ -16,5 +16,6 @@ export interface SearchStrategyDependencies | --- | --- | --- | | [esClient](./kibana-plugin-plugins-data-server.searchstrategydependencies.esclient.md) | IScopedClusterClient | | | [savedObjectsClient](./kibana-plugin-plugins-data-server.searchstrategydependencies.savedobjectsclient.md) | SavedObjectsClientContract | | +| [searchSessionsClient](./kibana-plugin-plugins-data-server.searchstrategydependencies.searchsessionsclient.md) | IScopedSearchSessionsClient | | | [uiSettingsClient](./kibana-plugin-plugins-data-server.searchstrategydependencies.uisettingsclient.md) | IUiSettingsClient | | diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.searchstrategydependencies.searchsessionsclient.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.searchstrategydependencies.searchsessionsclient.md new file mode 100644 index 0000000000000..5340ed9673c02 --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.searchstrategydependencies.searchsessionsclient.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [SearchStrategyDependencies](./kibana-plugin-plugins-data-server.searchstrategydependencies.md) > [searchSessionsClient](./kibana-plugin-plugins-data-server.searchstrategydependencies.searchsessionsclient.md) + +## SearchStrategyDependencies.searchSessionsClient property + +Signature: + +```typescript +searchSessionsClient: IScopedSearchSessionsClient; +``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.sessionservice._constructor_.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.sessionservice._constructor_.md deleted file mode 100644 index 73d658455a66f..0000000000000 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.sessionservice._constructor_.md +++ /dev/null @@ -1,13 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [SessionService](./kibana-plugin-plugins-data-server.sessionservice.md) > [(constructor)](./kibana-plugin-plugins-data-server.sessionservice._constructor_.md) - -## SessionService.(constructor) - -Constructs a new instance of the `SessionService` class - -Signature: - -```typescript -constructor(); -``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.sessionservice.asscopedprovider.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.sessionservice.asscopedprovider.md deleted file mode 100644 index f3af7fb0f61d9..0000000000000 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.sessionservice.asscopedprovider.md +++ /dev/null @@ -1,26 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [SessionService](./kibana-plugin-plugins-data-server.sessionservice.md) > [asScopedProvider](./kibana-plugin-plugins-data-server.sessionservice.asscopedprovider.md) - -## SessionService.asScopedProvider() method - -Signature: - -```typescript -asScopedProvider(core: CoreStart): (request: KibanaRequest) => { - search: , Response_1 extends IKibanaSearchResponse>(strategy: ISearchStrategy, request: Request_1, options: import("../../../common").ISearchOptions, deps: import("../types").SearchStrategyDependencies) => import("rxjs").Observable; - }; -``` - -## Parameters - -| Parameter | Type | Description | -| --- | --- | --- | -| core | CoreStart | | - -Returns: - -`(request: KibanaRequest) => { - search: , Response_1 extends IKibanaSearchResponse>(strategy: ISearchStrategy, request: Request_1, options: import("../../../common").ISearchOptions, deps: import("../types").SearchStrategyDependencies) => import("rxjs").Observable; - }` - diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.sessionservice.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.sessionservice.md deleted file mode 100644 index 2369b00644548..0000000000000 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.sessionservice.md +++ /dev/null @@ -1,27 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [SessionService](./kibana-plugin-plugins-data-server.sessionservice.md) - -## SessionService class - -The OSS session service. See data\_enhanced in X-Pack for the background session service. - -Signature: - -```typescript -export declare class SessionService implements ISessionService -``` - -## Constructors - -| Constructor | Modifiers | Description | -| --- | --- | --- | -| [(constructor)()](./kibana-plugin-plugins-data-server.sessionservice._constructor_.md) | | Constructs a new instance of the SessionService class | - -## Methods - -| Method | Modifiers | Description | -| --- | --- | --- | -| [asScopedProvider(core)](./kibana-plugin-plugins-data-server.sessionservice.asscopedprovider.md) | | | -| [search(strategy, args)](./kibana-plugin-plugins-data-server.sessionservice.search.md) | | | - diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.sessionservice.search.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.sessionservice.search.md deleted file mode 100644 index 8f8620a6ed5ee..0000000000000 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.sessionservice.search.md +++ /dev/null @@ -1,23 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [SessionService](./kibana-plugin-plugins-data-server.sessionservice.md) > [search](./kibana-plugin-plugins-data-server.sessionservice.search.md) - -## SessionService.search() method - -Signature: - -```typescript -search(strategy: ISearchStrategy, ...args: Parameters['search']>): import("rxjs").Observable; -``` - -## Parameters - -| Parameter | Type | Description | -| --- | --- | --- | -| strategy | ISearchStrategy<Request, Response> | | -| args | Parameters<ISearchStrategy<Request, Response>['search']> | | - -Returns: - -`import("rxjs").Observable` - diff --git a/src/plugins/data/server/server.api.md b/src/plugins/data/server/server.api.md index c58cd11bbc5bc..df73149428cb0 100644 --- a/src/plugins/data/server/server.api.md +++ b/src/plugins/data/server/server.api.md @@ -54,9 +54,13 @@ import { PublicMethodsOf } from '@kbn/utility-types'; import { RecursiveReadonly } from '@kbn/utility-types'; import { RequestAdapter } from 'src/plugins/inspector/common'; import { RequestStatistics } from 'src/plugins/inspector/common'; -import { SavedObject } from 'src/core/server'; +import { SavedObject } from 'kibana/server'; +import { SavedObject as SavedObject_2 } from 'src/core/server'; import { SavedObjectsClientContract } from 'src/core/server'; import { SavedObjectsClientContract as SavedObjectsClientContract_2 } from 'kibana/server'; +import { SavedObjectsFindOptions } from 'kibana/server'; +import { SavedObjectsFindResponse } from 'kibana/server'; +import { SavedObjectsUpdateResponse } from 'kibana/server'; import { Search } from '@elastic/elasticsearch/api/requestParams'; import { SearchResponse } from 'elasticsearch'; import { SerializedFieldFormat as SerializedFieldFormat_2 } from 'src/plugins/expressions/common'; @@ -909,6 +913,16 @@ export interface ISearchOptions { strategy?: string; } +// Warning: (ae-missing-release-tag) "ISearchSessionService" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export interface ISearchSessionService { + // Warning: (ae-forgotten-export) The symbol "IScopedSearchSessionsClient" needs to be exported by the entry point index.d.ts + // + // (undocumented) + asScopedProvider: (core: CoreStart) => (request: KibanaRequest) => IScopedSearchSessionsClient; +} + // Warning: (ae-missing-release-tag) "ISearchSetup" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -933,10 +947,10 @@ export interface ISearchStart ISearchClient; + asScoped: (request: KibanaRequest_2) => IScopedSearchClient; getSearchStrategy: (name?: string) => ISearchStrategy; // (undocumented) searchSource: { @@ -956,16 +970,6 @@ export interface ISearchStrategy Observable; } -// Warning: (ae-missing-release-tag) "ISessionService" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export interface ISessionService { - // Warning: (ae-forgotten-export) The symbol "IScopedSessionService" needs to be exported by the entry point index.d.ts - // - // (undocumented) - asScopedProvider: (core: CoreStart) => (request: KibanaRequest) => IScopedSessionService; -} - // @public (undocumented) export enum KBN_FIELD_TYPES { // (undocumented) @@ -1227,6 +1231,25 @@ export const search: { tabifyGetColumns: typeof tabifyGetColumns; }; +// Warning: (ae-missing-release-tag) "SearchSessionService" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public +export class SearchSessionService implements ISearchSessionService { + constructor(); + // (undocumented) + asScopedProvider(): () => { + getId: () => never; + trackId: () => Promise; + getSearchIdMapping: () => Promise>; + save: () => Promise; + get: () => Promise; + find: () => Promise; + update: () => Promise; + extend: () => Promise; + cancel: () => Promise; + }; +} + // Warning: (ae-missing-release-tag) "SearchStrategyDependencies" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -1236,6 +1259,8 @@ export interface SearchStrategyDependencies { // (undocumented) savedObjectsClient: SavedObjectsClientContract; // (undocumented) + searchSessionsClient: IScopedSearchSessionsClient; + // (undocumented) uiSettingsClient: IUiSettingsClient; } @@ -1257,19 +1282,6 @@ export function searchUsageObserver(logger: Logger_2, usage?: SearchUsage): { error(): void; }; -// Warning: (ae-missing-release-tag) "SessionService" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public -export class SessionService implements ISessionService { - constructor(); - // (undocumented) - asScopedProvider(core: CoreStart): (request: KibanaRequest) => { - search: , Response_1 extends IKibanaSearchResponse>(strategy: ISearchStrategy, request: Request_1, options: import("../../../common").ISearchOptions, deps: import("../types").SearchStrategyDependencies) => import("rxjs").Observable; - }; - // (undocumented) - search(strategy: ISearchStrategy, ...args: Parameters['search']>): import("rxjs").Observable; -} - // @internal export const shimAbortSignal: (promise: TransportRequestPromise, signal?: AbortSignal | undefined) => TransportRequestPromise; @@ -1431,7 +1443,7 @@ export function usageProvider(core: CoreSetup_2): SearchUsage; // src/plugins/data/server/index.ts:279:1 - (ae-forgotten-export) The symbol "calcAutoIntervalLessThan" needs to be exported by the entry point index.d.ts // src/plugins/data/server/index_patterns/index_patterns_service.ts:70:14 - (ae-forgotten-export) The symbol "IndexPatternsService" needs to be exported by the entry point index.d.ts // src/plugins/data/server/plugin.ts:90:74 - (ae-forgotten-export) The symbol "DataEnhancements" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/search/types.ts:112:5 - (ae-forgotten-export) The symbol "ISearchStartSearchSource" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/search/types.ts:122:5 - (ae-forgotten-export) The symbol "ISearchStartSearchSource" needs to be exported by the entry point index.d.ts // (No @packageDocumentation comment for this package) From e1600197985989ad5f376a1b83ba34c0c191ba58 Mon Sep 17 00:00:00 2001 From: Lukas Olson Date: Tue, 19 Jan 2021 11:45:48 -0700 Subject: [PATCH 05/20] Fix types/tests --- src/plugins/data/server/mocks.ts | 14 +++++++++- src/plugins/data/server/search/mocks.ts | 26 +++++++++++-------- .../server/routes/session.test.ts | 4 +-- 3 files changed, 30 insertions(+), 14 deletions(-) diff --git a/src/plugins/data/server/mocks.ts b/src/plugins/data/server/mocks.ts index 785e4a1ec41ab..619a5a7ff5a01 100644 --- a/src/plugins/data/server/mocks.ts +++ b/src/plugins/data/server/mocks.ts @@ -17,7 +17,12 @@ * under the License. */ -import { createSearchSetupMock, createSearchStartMock } from './search/mocks'; +import { RequestHandlerContext } from 'kibana/server'; +import { + createSearchSetupMock, + createSearchStartMock, + createSearchRequestHandlerContext, +} from './search/mocks'; import { createFieldFormatsSetupMock, createFieldFormatsStartMock } from './field_formats/mocks'; import { createIndexPatternsStartMock } from './index_patterns/mocks'; @@ -36,7 +41,14 @@ function createStartContract() { }; } +function createRequestHandlerContext() { + return ({ + search: createSearchRequestHandlerContext(), + } as unknown) as jest.Mocked; +} + export const dataPluginMock = { createSetupContract, createStartContract, + createRequestHandlerContext, }; diff --git a/src/plugins/data/server/search/mocks.ts b/src/plugins/data/server/search/mocks.ts index a244185d21dcc..606756ff880f1 100644 --- a/src/plugins/data/server/search/mocks.ts +++ b/src/plugins/data/server/search/mocks.ts @@ -35,17 +35,21 @@ export function createSearchStartMock(): jest.Mocked { return { aggs: searchAggsStartMock(), getSearchStrategy: jest.fn(), - asScoped: jest.fn().mockReturnValue({ - search: jest.fn(), - cancel: jest.fn(), - extend: jest.fn(), - saveSession: jest.fn(), - getSession: jest.fn(), - findSessions: jest.fn(), - updateSession: jest.fn(), - extendSession: jest.fn(), - cancelSession: jest.fn(), - }), + asScoped: jest.fn().mockReturnValue(createSearchRequestHandlerContext()), searchSource: searchSourceMock.createStartContract(), }; } + +export function createSearchRequestHandlerContext() { + return { + search: jest.fn(), + cancel: jest.fn(), + extend: jest.fn(), + saveSession: jest.fn(), + getSession: jest.fn(), + findSessions: jest.fn(), + updateSession: jest.fn(), + extendSession: jest.fn(), + cancelSession: jest.fn(), + }; +} diff --git a/x-pack/plugins/data_enhanced/server/routes/session.test.ts b/x-pack/plugins/data_enhanced/server/routes/session.test.ts index b8d8d3c8da557..fda4288a926bd 100644 --- a/x-pack/plugins/data_enhanced/server/routes/session.test.ts +++ b/x-pack/plugins/data_enhanced/server/routes/session.test.ts @@ -8,7 +8,7 @@ import type { MockedKeys } from '@kbn/utility-types/jest'; import type { CoreSetup, RequestHandlerContext } from 'kibana/server'; import { coreMock, httpServerMock } from '../../../../../src/core/server/mocks'; import { PluginStart as DataPluginStart } from '../../../../../src/plugins/data/server'; -import { createSearchRequestHandlerContext } from './mocks'; +import { dataPluginMock } from '../../../../../src/plugins/data/server/mocks'; import { registerSessionRoutes } from './session'; describe('registerSessionRoutes', () => { @@ -17,7 +17,7 @@ describe('registerSessionRoutes', () => { beforeEach(() => { mockCoreSetup = coreMock.createSetup(); - mockContext = createSearchRequestHandlerContext(); + mockContext = dataPluginMock.createRequestHandlerContext(); registerSessionRoutes(mockCoreSetup.http.createRouter()); }); From 3c08c3df90572413a1224d941a3494d0df4027c8 Mon Sep 17 00:00:00 2001 From: Lukas Olson Date: Tue, 19 Jan 2021 14:41:10 -0700 Subject: [PATCH 06/20] Fix tests --- .../search/session/session_service.test.ts | 22 ------------------- .../api_integration/apis/search/session.ts | 2 -- 2 files changed, 24 deletions(-) delete mode 100644 src/plugins/data/server/search/session/session_service.test.ts diff --git a/src/plugins/data/server/search/session/session_service.test.ts b/src/plugins/data/server/search/session/session_service.test.ts deleted file mode 100644 index 943b90b29b417..0000000000000 --- a/src/plugins/data/server/search/session/session_service.test.ts +++ /dev/null @@ -1,22 +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 { SearchSessionService } from './session_service'; - -describe('SearchSessionService', () => {}); diff --git a/x-pack/test/api_integration/apis/search/session.ts b/x-pack/test/api_integration/apis/search/session.ts index ee2e4337adc95..de9c068f1a7a8 100644 --- a/x-pack/test/api_integration/apis/search/session.ts +++ b/x-pack/test/api_integration/apis/search/session.ts @@ -48,8 +48,6 @@ export default function ({ getService }: FtrProviderContext) { .expect(200); await supertest.delete(`/internal/session/${sessionId}`).set('kbn-xsrf', 'foo').expect(200); - - await supertest.get(`/internal/session/${sessionId}`).set('kbn-xsrf', 'foo').expect(404); }); it('should sync search ids into session', async () => { From 0cd92ed327481333861ce43ea5f4c8b45fc1f584 Mon Sep 17 00:00:00 2001 From: Lukas Olson Date: Tue, 19 Jan 2021 16:23:16 -0700 Subject: [PATCH 07/20] Update status of SO before cancelling search requests --- src/plugins/data/server/search/search_service.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/plugins/data/server/search/search_service.ts b/src/plugins/data/server/search/search_service.ts index c8306a3534c00..29afcaf4fbcad 100644 --- a/src/plugins/data/server/search/search_service.ts +++ b/src/plugins/data/server/search/search_service.ts @@ -353,6 +353,7 @@ export class SearchService implements Plugin { private cancelSession = async (deps: SearchStrategyDependencies, sessionId: string) => { const searchIdMapping = await deps.searchSessionsClient.getSearchIdMapping(sessionId); + const response = await deps.searchSessionsClient.cancel(sessionId); for (const [searchId, strategyName] of searchIdMapping.entries()) { const searchOptions = { @@ -360,10 +361,10 @@ export class SearchService implements Plugin { strategy: strategyName, isStored: true, }; - await this.cancel(deps, searchId, searchOptions); + this.cancel(deps, searchId, searchOptions); } - return deps.searchSessionsClient.cancel(sessionId); + return response; }; private extendSession = async ( From f1a1d0bb2e75aa0ef62503e3d9532c72bd941e87 Mon Sep 17 00:00:00 2001 From: Lukas Olson Date: Tue, 19 Jan 2021 16:39:50 -0700 Subject: [PATCH 08/20] Add API integration test --- .../api_integration/apis/search/session.ts | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/x-pack/test/api_integration/apis/search/session.ts b/x-pack/test/api_integration/apis/search/session.ts index de9c068f1a7a8..89946a331abd0 100644 --- a/x-pack/test/api_integration/apis/search/session.ts +++ b/x-pack/test/api_integration/apis/search/session.ts @@ -121,6 +121,29 @@ export default function ({ getService }: FtrProviderContext) { expect(idMappings).to.contain(id1); expect(idMappings).to.contain(id2); }); + + it('should create and extend a session', async () => { + const sessionId = `my-session-${Math.random()}`; + await supertest + .post(`/internal/session`) + .set('kbn-xsrf', 'foo') + .send({ + sessionId, + name: 'My Session', + appId: 'discover', + expires: '123', + urlGeneratorId: 'discover', + }) + .expect(200); + + await supertest + .post(`/internal/session/${sessionId}/_extend`) + .set('kbn-xsrf', 'foo') + .send({ + keepAlive: '5m', + }) + .expect(200); + }); }); }); } From 32315b74bec396223965f51e5d114717641160b2 Mon Sep 17 00:00:00 2001 From: Lukas Olson Date: Mon, 25 Jan 2021 14:34:53 -0700 Subject: [PATCH 09/20] Fix types --- examples/search_examples/server/plugin.ts | 7 ++----- .../search_examples/server/routes/register_routes.ts | 8 +++----- .../server/routes/server_search_route.ts | 8 +++----- src/plugins/data/server/index.ts | 1 + src/plugins/data/server/search/types.ts | 4 +++- src/plugins/vis_type_timelion/server/plugin.ts | 10 ++-------- .../vis_type_timelion/server/routes/validate_es.ts | 8 +++----- src/plugins/vis_type_timeseries/server/types.ts | 9 +++------ x-pack/plugins/infra/server/types.ts | 4 ++-- 9 files changed, 22 insertions(+), 37 deletions(-) diff --git a/examples/search_examples/server/plugin.ts b/examples/search_examples/server/plugin.ts index e7ee311c8d652..595af844b0997 100644 --- a/examples/search_examples/server/plugin.ts +++ b/examples/search_examples/server/plugin.ts @@ -12,10 +12,9 @@ import type { CoreStart, Plugin, Logger, - RequestHandlerContext, } from 'src/core/server'; -import type { DataApiRequestHandlerContext } from 'src/plugins/data/server'; +import type { DataRequestHandlerContext } from 'src/plugins/data/server'; import { SearchExamplesPluginSetup, @@ -45,9 +44,7 @@ export class SearchExamplesPlugin deps: SearchExamplesPluginSetupDeps ) { this.logger.debug('search_examples: Setup'); - const router = core.http.createRouter< - RequestHandlerContext & { search: DataApiRequestHandlerContext } - >(); + const router = core.http.createRouter(); core.getStartServices().then(([_, depsStart]) => { const myStrategy = mySearchStrategyProvider(depsStart.data); diff --git a/examples/search_examples/server/routes/register_routes.ts b/examples/search_examples/server/routes/register_routes.ts index d7a18509b9a79..1159864bed31a 100644 --- a/examples/search_examples/server/routes/register_routes.ts +++ b/examples/search_examples/server/routes/register_routes.ts @@ -6,12 +6,10 @@ * Public License, v 1. */ -import type { IRouter, RequestHandlerContext } from 'kibana/server'; -import { DataApiRequestHandlerContext } from 'src/plugins/data/server'; +import type { IRouter } from 'kibana/server'; +import { DataRequestHandlerContext } from 'src/plugins/data/server'; import { registerServerSearchRoute } from './server_search_route'; -export function registerRoutes( - router: IRouter -) { +export function registerRoutes(router: IRouter) { registerServerSearchRoute(router); } diff --git a/examples/search_examples/server/routes/server_search_route.ts b/examples/search_examples/server/routes/server_search_route.ts index 99a1aba99d8ec..b4805a8de0d3c 100644 --- a/examples/search_examples/server/routes/server_search_route.ts +++ b/examples/search_examples/server/routes/server_search_route.ts @@ -9,13 +9,11 @@ import { IEsSearchRequest } from 'src/plugins/data/server'; import { schema } from '@kbn/config-schema'; import { IEsSearchResponse } from 'src/plugins/data/common'; -import type { DataApiRequestHandlerContext } from 'src/plugins/data/server'; -import type { IRouter, RequestHandlerContext } from 'src/core/server'; +import type { DataRequestHandlerContext } from 'src/plugins/data/server'; +import type { IRouter } from 'src/core/server'; import { SERVER_SEARCH_ROUTE_PATH } from '../../common'; -export function registerServerSearchRoute( - router: IRouter -) { +export function registerServerSearchRoute(router: IRouter) { router.get( { path: SERVER_SEARCH_ROUTE_PATH, diff --git a/src/plugins/data/server/index.ts b/src/plugins/data/server/index.ts index f49181b90d4eb..c05606a1d1f0d 100644 --- a/src/plugins/data/server/index.ts +++ b/src/plugins/data/server/index.ts @@ -235,6 +235,7 @@ export { SearchUsage, SearchSessionService, ISearchSessionService, + SearchRequestHandlerContext, DataRequestHandlerContext, } from './search'; diff --git a/src/plugins/data/server/search/types.ts b/src/plugins/data/server/search/types.ts index dc86c1b5d9aff..ff3844c3d115e 100644 --- a/src/plugins/data/server/search/types.ts +++ b/src/plugins/data/server/search/types.ts @@ -114,11 +114,13 @@ export interface ISearchStart< }; } +export type SearchRequestHandlerContext = IScopedSearchClient; + /** * @internal */ export interface DataRequestHandlerContext extends RequestHandlerContext { - search: IScopedSearchClient; + search: SearchRequestHandlerContext; } export type DataPluginRouter = IRouter; diff --git a/src/plugins/vis_type_timelion/server/plugin.ts b/src/plugins/vis_type_timelion/server/plugin.ts index f999c1dfc773a..dc6f4f85df5a7 100644 --- a/src/plugins/vis_type_timelion/server/plugin.ts +++ b/src/plugins/vis_type_timelion/server/plugin.ts @@ -11,12 +11,8 @@ import { first } from 'rxjs/operators'; import { TypeOf, schema } from '@kbn/config-schema'; import { RecursiveReadonly } from '@kbn/utility-types'; import { deepFreeze } from '@kbn/std'; -import type { RequestHandlerContext } from 'src/core/server'; -import type { - PluginStart, - DataApiRequestHandlerContext, -} from '../../../../src/plugins/data/server'; +import type { PluginStart, DataRequestHandlerContext } from '../../../../src/plugins/data/server'; import { CoreSetup, PluginInitializerContext } from '../../../../src/core/server'; import { configSchema } from '../config'; import loadFunctions from './lib/load_functions'; @@ -71,9 +67,7 @@ export class Plugin { const logger = this.initializerContext.logger.get('timelion'); - const router = core.http.createRouter< - RequestHandlerContext & { search: DataApiRequestHandlerContext } - >(); + const router = core.http.createRouter(); const deps = { configManager, diff --git a/src/plugins/vis_type_timelion/server/routes/validate_es.ts b/src/plugins/vis_type_timelion/server/routes/validate_es.ts index 1637fcc464f46..e0e6270735440 100644 --- a/src/plugins/vis_type_timelion/server/routes/validate_es.ts +++ b/src/plugins/vis_type_timelion/server/routes/validate_es.ts @@ -7,12 +7,10 @@ */ import _ from 'lodash'; -import { IRouter, RequestHandlerContext } from 'kibana/server'; -import type { DataApiRequestHandlerContext } from '../../../data/server'; +import { IRouter } from 'kibana/server'; +import type { DataRequestHandlerContext } from '../../../data/server'; -export function validateEsRoute( - router: IRouter -) { +export function validateEsRoute(router: IRouter) { router.get( { path: '/api/timelion/validate/es', diff --git a/src/plugins/vis_type_timeseries/server/types.ts b/src/plugins/vis_type_timeseries/server/types.ts index 29cd33031c883..3ee052bb2bea2 100644 --- a/src/plugins/vis_type_timeseries/server/types.ts +++ b/src/plugins/vis_type_timeseries/server/types.ts @@ -6,11 +6,8 @@ * Public License, v 1. */ -import type { IRouter, RequestHandlerContext } from 'src/core/server'; -import type { DataApiRequestHandlerContext } from '../../data/server'; - -export interface VisTypeTimeseriesRequestHandlerContext extends RequestHandlerContext { - search: DataApiRequestHandlerContext; -} +import type { IRouter } from 'src/core/server'; +import type { DataRequestHandlerContext } from '../../data/server'; +export type VisTypeTimeseriesRequestHandlerContext = DataRequestHandlerContext; export type VisTypeTimeseriesRouter = IRouter; diff --git a/x-pack/plugins/infra/server/types.ts b/x-pack/plugins/infra/server/types.ts index 2a30bf7cf093d..8731067e73080 100644 --- a/x-pack/plugins/infra/server/types.ts +++ b/x-pack/plugins/infra/server/types.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ import type { RequestHandlerContext } from 'src/core/server'; -import type { DataApiRequestHandlerContext } from '../../../../src/plugins/data/server'; +import type { SearchRequestHandlerContext } from '../../../../src/plugins/data/server'; import { MlPluginSetup } from '../../ml/server'; export type MlSystem = ReturnType; @@ -27,5 +27,5 @@ export type InfraRequestHandlerContext = InfraMlRequestHandlerContext & */ export interface InfraPluginRequestHandlerContext extends RequestHandlerContext { infra: InfraRequestHandlerContext; - search: DataApiRequestHandlerContext; + search: SearchRequestHandlerContext; } From 542de957411fce5d2a5d5bb963c550660b257d8c Mon Sep 17 00:00:00 2001 From: Lukas Olson Date: Mon, 25 Jan 2021 15:35:59 -0700 Subject: [PATCH 10/20] Update expiration route to use config defaultExpiration --- x-pack/plugins/data_enhanced/server/plugin.ts | 9 +++---- .../data_enhanced/server/routes/session.ts | 27 ++++++++++++++----- 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/x-pack/plugins/data_enhanced/server/plugin.ts b/x-pack/plugins/data_enhanced/server/plugin.ts index cff0ee3efd738..95ddcf72fcfb3 100644 --- a/x-pack/plugins/data_enhanced/server/plugin.ts +++ b/x-pack/plugins/data_enhanced/server/plugin.ts @@ -22,6 +22,7 @@ import { } from './search'; import { getUiSettings } from './ui_settings'; import type { DataEnhancedRequestHandlerContext } from './type'; +import { ConfigSchema } from '../config'; interface SetupDependencies { data: DataPluginSetup; @@ -62,10 +63,8 @@ export class EnhancedDataServerPlugin eqlSearchStrategyProvider(this.logger) ); - this.sessionService = new SearchSessionService( - this.logger, - this.initializerContext.config.create() - ); + const config$ = this.initializerContext.config.create(); + this.sessionService = new SearchSessionService(this.logger, config$); deps.data.__enhance({ search: { @@ -75,7 +74,7 @@ export class EnhancedDataServerPlugin }); const router = core.http.createRouter(); - registerSessionRoutes(router, this.logger); + registerSessionRoutes(router, this.logger, config$); this.sessionService.setup(core, { taskManager: deps.taskManager, diff --git a/x-pack/plugins/data_enhanced/server/routes/session.ts b/x-pack/plugins/data_enhanced/server/routes/session.ts index 695fbb4ca68ac..b846a02b9c387 100644 --- a/x-pack/plugins/data_enhanced/server/routes/session.ts +++ b/x-pack/plugins/data_enhanced/server/routes/session.ts @@ -4,12 +4,21 @@ * you may not use this file except in compliance with the Elastic License. */ +import moment from 'moment'; import { schema } from '@kbn/config-schema'; -import { Logger } from 'src/core/server'; +import { Logger, SavedObject } from 'src/core/server'; +import { Observable } from 'rxjs'; +import { first } from 'rxjs/operators'; import { reportServerError } from '../../../../../src/plugins/kibana_utils/server'; import { DataEnhancedPluginRouter } from '../type'; +import { ConfigSchema } from '../../config'; +import { SearchSessionSavedObjectAttributes } from '../../common'; -export function registerSessionRoutes(router: DataEnhancedPluginRouter, logger: Logger): void { +export function registerSessionRoutes( + router: DataEnhancedPluginRouter, + logger: Logger, + config$: Observable +): void { router.post( { path: '/internal/session', @@ -174,16 +183,20 @@ export function registerSessionRoutes(router: DataEnhancedPluginRouter, logger: params: schema.object({ id: schema.string(), }), - body: schema.object({ - keepAlive: schema.string(), - }), }, }, async (context, request, res) => { const { id } = request.params; - const { keepAlive } = request.body; try { - const response = await context.search!.extendSession(id, keepAlive); + const config = await config$.pipe(first()).toPromise(); + const searchSession = (await context.search.getSession( + id + )) as SavedObject; + const expires = moment(searchSession.attributes.expires).add( + config.search.sessions.defaultExpiration + ); + const ttl = `${expires.diff(moment())}ms`; + const response = await context.search!.extendSession(id, ttl); return res.ok({ body: response, From 5b22249ce2c347931b20836bdca1f0f892c49c59 Mon Sep 17 00:00:00 2001 From: Lukas Olson Date: Mon, 25 Jan 2021 15:39:15 -0700 Subject: [PATCH 11/20] Fix test --- .../server/routes/session.test.ts | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/data_enhanced/server/routes/session.test.ts b/x-pack/plugins/data_enhanced/server/routes/session.test.ts index f4f2a972063e8..dea2e3d3649cc 100644 --- a/x-pack/plugins/data_enhanced/server/routes/session.test.ts +++ b/x-pack/plugins/data_enhanced/server/routes/session.test.ts @@ -14,17 +14,33 @@ import type { } from '../../../../../src/plugins/data/server'; import { dataPluginMock } from '../../../../../src/plugins/data/server/mocks'; import { registerSessionRoutes } from './session'; +import { BehaviorSubject } from 'rxjs'; +import { ConfigSchema } from '../../config'; +import moment from 'moment'; describe('registerSessionRoutes', () => { let mockCoreSetup: MockedKeys>; let mockContext: jest.Mocked; let mockLogger: Logger; + const mockConfig$ = new BehaviorSubject({ + search: { + sessions: { + enabled: true, + pageSize: 10000, + inMemTimeout: moment.duration(1, 'm'), + maxUpdateRetries: 3, + defaultExpiration: moment.duration(7, 'd'), + trackingInterval: moment.duration(10, 's'), + management: {} as any, + }, + }, + }); beforeEach(() => { mockCoreSetup = coreMock.createSetup(); mockLogger = coreMock.createPluginInitializerContext().logger.get(); mockContext = dataPluginMock.createRequestHandlerContext(); - registerSessionRoutes(mockCoreSetup.http.createRouter(), mockLogger); + registerSessionRoutes(mockCoreSetup.http.createRouter(), mockLogger, mockConfig$); }); it('save calls saveSession with sessionId and attributes', async () => { From 66420b41fe736ecada9f258c6a7a09778d959fb9 Mon Sep 17 00:00:00 2001 From: Lukas Olson Date: Mon, 25 Jan 2021 15:53:14 -0700 Subject: [PATCH 12/20] Update docs --- .../kibana-plugin-plugins-data-server.md | 1 + ...data-server.searchrequesthandlercontext.md | 11 ++++++ src/plugins/data/server/server.api.md | 39 +++++++++++-------- 3 files changed, 34 insertions(+), 17 deletions(-) create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.searchrequesthandlercontext.md diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.md index f1d0d4af58b02..1439f0554aaa2 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.md @@ -110,6 +110,7 @@ | [KibanaContext](./kibana-plugin-plugins-data-server.kibanacontext.md) | | | [ParsedInterval](./kibana-plugin-plugins-data-server.parsedinterval.md) | | | [Query](./kibana-plugin-plugins-data-server.query.md) | | +| [SearchRequestHandlerContext](./kibana-plugin-plugins-data-server.searchrequesthandlercontext.md) | | | [TabbedAggRow](./kibana-plugin-plugins-data-server.tabbedaggrow.md) | \* | | [TimeRange](./kibana-plugin-plugins-data-server.timerange.md) | | diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.searchrequesthandlercontext.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.searchrequesthandlercontext.md new file mode 100644 index 0000000000000..f031ddfbd09af --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.searchrequesthandlercontext.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [SearchRequestHandlerContext](./kibana-plugin-plugins-data-server.searchrequesthandlercontext.md) + +## SearchRequestHandlerContext type + +Signature: + +```typescript +export declare type SearchRequestHandlerContext = IScopedSearchClient; +``` diff --git a/src/plugins/data/server/server.api.md b/src/plugins/data/server/server.api.md index 0efd9be0966a4..e91f91f0309f0 100644 --- a/src/plugins/data/server/server.api.md +++ b/src/plugins/data/server/server.api.md @@ -311,10 +311,8 @@ export const config: PluginConfigDescriptor; // @internal (undocumented) export interface DataRequestHandlerContext extends RequestHandlerContext { - // Warning: (ae-forgotten-export) The symbol "IScopedSearchClient" needs to be exported by the entry point index.d.ts - // // (undocumented) - search: IScopedSearchClient; + search: SearchRequestHandlerContext; } // @public (undocumented) @@ -952,6 +950,8 @@ export interface ISearchStart IScopedSearchClient; getSearchStrategy: (name?: string) => ISearchStrategy; @@ -1234,6 +1234,11 @@ export const search: { tabifyGetColumns: typeof tabifyGetColumns; }; +// Warning: (ae-missing-release-tag) "SearchRequestHandlerContext" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type SearchRequestHandlerContext = IScopedSearchClient; + // Warning: (ae-missing-release-tag) "SearchSessionService" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public @@ -1431,20 +1436,20 @@ export function usageProvider(core: CoreSetup_2): SearchUsage; // src/plugins/data/server/index.ts:100:26 - (ae-forgotten-export) The symbol "TruncateFormat" needs to be exported by the entry point index.d.ts // src/plugins/data/server/index.ts:126:27 - (ae-forgotten-export) The symbol "isFilterable" needs to be exported by the entry point index.d.ts // src/plugins/data/server/index.ts:126:27 - (ae-forgotten-export) The symbol "isNestedField" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:242:20 - (ae-forgotten-export) The symbol "getRequestInspectorStats" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:242:20 - (ae-forgotten-export) The symbol "getResponseInspectorStats" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:242:20 - (ae-forgotten-export) The symbol "tabifyAggResponse" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:242:20 - (ae-forgotten-export) The symbol "tabifyGetColumns" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:244:1 - (ae-forgotten-export) The symbol "CidrMask" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:245:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:254:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:255:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:256:1 - (ae-forgotten-export) The symbol "Ipv4Address" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:260:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:261:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:265:1 - (ae-forgotten-export) The symbol "propFilter" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:268:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:269:1 - (ae-forgotten-export) The symbol "calcAutoIntervalLessThan" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:243:20 - (ae-forgotten-export) The symbol "getRequestInspectorStats" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:243:20 - (ae-forgotten-export) The symbol "getResponseInspectorStats" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:243:20 - (ae-forgotten-export) The symbol "tabifyAggResponse" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:243:20 - (ae-forgotten-export) The symbol "tabifyGetColumns" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:245:1 - (ae-forgotten-export) The symbol "CidrMask" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:246:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:255:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:256:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:257:1 - (ae-forgotten-export) The symbol "Ipv4Address" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:261:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:262:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:266:1 - (ae-forgotten-export) The symbol "propFilter" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:269:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:270:1 - (ae-forgotten-export) The symbol "calcAutoIntervalLessThan" needs to be exported by the entry point index.d.ts // src/plugins/data/server/index_patterns/index_patterns_service.ts:59:14 - (ae-forgotten-export) The symbol "IndexPatternsService" needs to be exported by the entry point index.d.ts // src/plugins/data/server/plugin.ts:79:74 - (ae-forgotten-export) The symbol "DataEnhancements" needs to be exported by the entry point index.d.ts // src/plugins/data/server/search/types.ts:113:5 - (ae-forgotten-export) The symbol "ISearchStartSearchSource" needs to be exported by the entry point index.d.ts From 8a5e3d3aabfcc363aa4ea7a54ebb1c3b140aca79 Mon Sep 17 00:00:00 2001 From: Lukas Olson Date: Tue, 26 Jan 2021 14:18:34 -0700 Subject: [PATCH 13/20] New logic for extend --- .../data/server/search/search_service.ts | 6 +++-- .../data/server/search/session/types.ts | 2 +- x-pack/plugins/data_enhanced/server/plugin.ts | 9 ++++--- .../server/routes/session.test.ts | 17 ++++++++++++ .../data_enhanced/server/routes/session.ts | 27 +++++-------------- .../server/search/session/session_service.ts | 13 ++------- 6 files changed, 36 insertions(+), 38 deletions(-) diff --git a/src/plugins/data/server/search/search_service.ts b/src/plugins/data/server/search/search_service.ts index 22a0b31f87e66..1ce9411b666b0 100644 --- a/src/plugins/data/server/search/search_service.ts +++ b/src/plugins/data/server/search/search_service.ts @@ -8,6 +8,7 @@ import { BehaviorSubject, from, Observable } from 'rxjs'; import { pick } from 'lodash'; +import moment from 'moment'; import { CoreSetup, CoreStart, @@ -363,9 +364,10 @@ export class SearchService implements Plugin { private extendSession = async ( deps: SearchStrategyDependencies, sessionId: string, - keepAlive: string + expires: Date ) => { const searchIdMapping = await deps.searchSessionsClient.getSearchIdMapping(sessionId); + const keepAlive = `${moment(expires).diff(moment())}ms`; for (const [searchId, strategyName] of searchIdMapping.entries()) { const searchOptions = { @@ -376,7 +378,7 @@ export class SearchService implements Plugin { await this.extend(deps, searchId, keepAlive, searchOptions); } - return deps.searchSessionsClient.extend(sessionId, keepAlive); + return deps.searchSessionsClient.extend(sessionId, expires); }; private asScopedProvider = (core: CoreStart) => { diff --git a/src/plugins/data/server/search/session/types.ts b/src/plugins/data/server/search/session/types.ts index 4df076f356c71..3c074955a108e 100644 --- a/src/plugins/data/server/search/session/types.ts +++ b/src/plugins/data/server/search/session/types.ts @@ -29,7 +29,7 @@ export interface IScopedSearchSessionsClient { find: (options: Omit) => Promise>; update: (sessionId: string, attributes: Partial) => Promise>; cancel: (sessionId: string) => Promise<{}>; - extend: (sessionId: string, keepAlive: string) => Promise>; + extend: (sessionId: string, expires: Date) => Promise>; } export interface ISearchSessionService { diff --git a/x-pack/plugins/data_enhanced/server/plugin.ts b/x-pack/plugins/data_enhanced/server/plugin.ts index 95ddcf72fcfb3..cff0ee3efd738 100644 --- a/x-pack/plugins/data_enhanced/server/plugin.ts +++ b/x-pack/plugins/data_enhanced/server/plugin.ts @@ -22,7 +22,6 @@ import { } from './search'; import { getUiSettings } from './ui_settings'; import type { DataEnhancedRequestHandlerContext } from './type'; -import { ConfigSchema } from '../config'; interface SetupDependencies { data: DataPluginSetup; @@ -63,8 +62,10 @@ export class EnhancedDataServerPlugin eqlSearchStrategyProvider(this.logger) ); - const config$ = this.initializerContext.config.create(); - this.sessionService = new SearchSessionService(this.logger, config$); + this.sessionService = new SearchSessionService( + this.logger, + this.initializerContext.config.create() + ); deps.data.__enhance({ search: { @@ -74,7 +75,7 @@ export class EnhancedDataServerPlugin }); const router = core.http.createRouter(); - registerSessionRoutes(router, this.logger, config$); + registerSessionRoutes(router, this.logger); this.sessionService.setup(core, { taskManager: deps.taskManager, diff --git a/x-pack/plugins/data_enhanced/server/routes/session.test.ts b/x-pack/plugins/data_enhanced/server/routes/session.test.ts index dea2e3d3649cc..6b571e7321b06 100644 --- a/x-pack/plugins/data_enhanced/server/routes/session.test.ts +++ b/x-pack/plugins/data_enhanced/server/routes/session.test.ts @@ -125,4 +125,21 @@ describe('registerSessionRoutes', () => { expect(mockContext.search!.cancelSession).toHaveBeenCalledWith(id); }); + + it('extend calls extendSession with id', async () => { + const id = 'd7170a35-7e2c-48d6-8dec-9a056721b489'; + const expires = new Date().toISOString(); + const params = { id }; + const body = { expires }; + + const mockRequest = httpServerMock.createKibanaRequest({ params, body }); + const mockResponse = httpServerMock.createResponseFactory(); + + const mockRouter = mockCoreSetup.http.createRouter.mock.results[0].value; + const [, , [, extendHandler]] = mockRouter.post.mock.calls; + + extendHandler(mockContext, mockRequest, mockResponse); + + expect(mockContext.search.extendSession).toHaveBeenCalledWith(id, new Date(expires)); + }); }); diff --git a/x-pack/plugins/data_enhanced/server/routes/session.ts b/x-pack/plugins/data_enhanced/server/routes/session.ts index b846a02b9c387..ff0f47c90582c 100644 --- a/x-pack/plugins/data_enhanced/server/routes/session.ts +++ b/x-pack/plugins/data_enhanced/server/routes/session.ts @@ -4,21 +4,12 @@ * you may not use this file except in compliance with the Elastic License. */ -import moment from 'moment'; import { schema } from '@kbn/config-schema'; -import { Logger, SavedObject } from 'src/core/server'; -import { Observable } from 'rxjs'; -import { first } from 'rxjs/operators'; +import { Logger } from 'src/core/server'; import { reportServerError } from '../../../../../src/plugins/kibana_utils/server'; import { DataEnhancedPluginRouter } from '../type'; -import { ConfigSchema } from '../../config'; -import { SearchSessionSavedObjectAttributes } from '../../common'; -export function registerSessionRoutes( - router: DataEnhancedPluginRouter, - logger: Logger, - config$: Observable -): void { +export function registerSessionRoutes(router: DataEnhancedPluginRouter, logger: Logger): void { router.post( { path: '/internal/session', @@ -183,20 +174,16 @@ export function registerSessionRoutes( params: schema.object({ id: schema.string(), }), + body: schema.object({ + expires: schema.string(), + }), }, }, async (context, request, res) => { const { id } = request.params; + const { expires } = request.body; try { - const config = await config$.pipe(first()).toPromise(); - const searchSession = (await context.search.getSession( - id - )) as SavedObject; - const expires = moment(searchSession.attributes.expires).add( - config.search.sessions.defaultExpiration - ); - const ttl = `${expires.diff(moment())}ms`; - const response = await context.search!.extendSession(id, ttl); + const response = await context.search!.extendSession(id, new Date(expires)); return res.ok({ body: response, diff --git a/x-pack/plugins/data_enhanced/server/search/session/session_service.ts b/x-pack/plugins/data_enhanced/server/search/session/session_service.ts index 13134f612c9cb..dcc52d0e5973d 100644 --- a/x-pack/plugins/data_enhanced/server/search/session/session_service.ts +++ b/x-pack/plugins/data_enhanced/server/search/session/session_service.ts @@ -7,7 +7,6 @@ import moment, { Moment } from 'moment'; import { Observable } from 'rxjs'; import { first } from 'rxjs/operators'; -import dateMath from '@elastic/datemath'; import { CoreSetup, CoreStart, @@ -300,18 +299,10 @@ export class SearchSessionService ); }; - public extend(deps: SearchSessionDependencies, sessionId: string, keepAlive: string) { + public extend(deps: SearchSessionDependencies, sessionId: string, expires: Date) { this.logger.debug(`extend | ${sessionId}`); - // Calculate the new `expires` value given the `keepAlive` - const expiresMoment = dateMath.parse(`now+${keepAlive}`); - if (!expiresMoment || isNaN(expiresMoment.date())) { - throw new Error(`"${keepAlive}" is not a valid value for keepAlive`); - } - const expires = expiresMoment.toISOString(); - - // Update the `expires` value in the search session saved object - return this.update(deps, sessionId, { expires }); + return this.update(deps, sessionId, { expires: expires.toISOString() }); } // TODO: Throw an error if this session doesn't belong to this user From 71582c7cfe9446bf97bb900463f01df48ee7f918 Mon Sep 17 00:00:00 2001 From: Lukas Olson Date: Tue, 26 Jan 2021 14:41:41 -0700 Subject: [PATCH 14/20] Remove declare module --- src/plugins/data/server/search/search_service.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/plugins/data/server/search/search_service.ts b/src/plugins/data/server/search/search_service.ts index 1ce9411b666b0..753bd3c16a49c 100644 --- a/src/plugins/data/server/search/search_service.ts +++ b/src/plugins/data/server/search/search_service.ts @@ -67,12 +67,6 @@ import { ISearchSessionService, SearchSessionService } from './session'; import { KbnServerError } from '../../../kibana_utils/server'; import { tapFirst } from '../../common'; -declare module 'src/core/server' { - interface RequestHandlerContext { - search?: IScopedSearchClient; - } -} - type StrategyMap = Record>; /** @internal */ From 65840b359826f0a969249d49f79bf423bbd07c3e Mon Sep 17 00:00:00 2001 From: Lukas Olson Date: Tue, 26 Jan 2021 16:01:22 -0700 Subject: [PATCH 15/20] Review feedback --- ...gins-data-public.searchsource.serialize.md | 4 +-- .../kibana-plugin-plugins-data-server.md | 1 - ...plugin-plugins-data-server.plugin.start.md | 8 ++--- ...rver.searchsessionservice._constructor_.md | 13 ------- ...r.searchsessionservice.asscopedprovider.md | 35 ------------------- ...lugins-data-server.searchsessionservice.md | 26 -------------- src/plugins/data/public/public.api.md | 2 +- .../server/search/session/session_service.ts | 1 + src/plugins/data/server/server.api.md | 8 ++--- .../data_enhanced/server/routes/session.ts | 14 +++----- .../server/search/session/session_service.ts | 29 +++++++-------- .../api_integration/apis/search/session.ts | 25 +++++++++++-- 12 files changed, 49 insertions(+), 117 deletions(-) delete mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.searchsessionservice._constructor_.md delete mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.searchsessionservice.asscopedprovider.md delete mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.searchsessionservice.md diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchsource.serialize.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchsource.serialize.md index 3bc2a20541777..496e1ae9677d8 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchsource.serialize.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchsource.serialize.md @@ -15,13 +15,13 @@ Using `createSearchSource`, the instance can be re-created. ```typescript serialize(): { searchSourceJSON: string; - references: import("src/core/server").SavedObjectReference[]; + references: import("../../../../../core/types").SavedObjectReference[]; }; ``` Returns: `{ searchSourceJSON: string; - references: import("src/core/server").SavedObjectReference[]; + references: import("../../../../../core/types").SavedObjectReference[]; }` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.md index 1439f0554aaa2..5a45ee19d058a 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.md @@ -14,7 +14,6 @@ | [IndexPatternsService](./kibana-plugin-plugins-data-server.indexpatternsservice.md) | | | [OptionedParamType](./kibana-plugin-plugins-data-server.optionedparamtype.md) | | | [Plugin](./kibana-plugin-plugins-data-server.plugin.md) | | -| [SearchSessionService](./kibana-plugin-plugins-data-server.searchsessionservice.md) | The OSS session service, which leaves most search session-related logic unimplemented. x-pack/plugins/data\_enhanced/server/search/session/session\_service.ts | ## Enumerations diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.plugin.start.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.plugin.start.md index 8f1ea7b95a5f9..af7abb076d7ef 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.plugin.start.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.plugin.start.md @@ -9,10 +9,10 @@ ```typescript start(core: CoreStart): { fieldFormats: { - fieldFormatServiceFactory: (uiSettings: import("src/core/server").IUiSettingsClient) => Promise; + fieldFormatServiceFactory: (uiSettings: import("../../../core/server").IUiSettingsClient) => Promise; }; indexPatterns: { - indexPatternsServiceFactory: (savedObjectsClient: Pick, elasticsearchClient: import("src/core/server").ElasticsearchClient) => Promise; + indexPatternsServiceFactory: (savedObjectsClient: Pick, elasticsearchClient: import("../../../core/server").ElasticsearchClient) => Promise; }; search: ISearchStart>; }; @@ -28,10 +28,10 @@ start(core: CoreStart): { `{ fieldFormats: { - fieldFormatServiceFactory: (uiSettings: import("src/core/server").IUiSettingsClient) => Promise; + fieldFormatServiceFactory: (uiSettings: import("../../../core/server").IUiSettingsClient) => Promise; }; indexPatterns: { - indexPatternsServiceFactory: (savedObjectsClient: Pick, elasticsearchClient: import("src/core/server").ElasticsearchClient) => Promise; + indexPatternsServiceFactory: (savedObjectsClient: Pick, elasticsearchClient: import("../../../core/server").ElasticsearchClient) => Promise; }; search: ISearchStart>; }` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.searchsessionservice._constructor_.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.searchsessionservice._constructor_.md deleted file mode 100644 index c34d033d01973..0000000000000 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.searchsessionservice._constructor_.md +++ /dev/null @@ -1,13 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [SearchSessionService](./kibana-plugin-plugins-data-server.searchsessionservice.md) > [(constructor)](./kibana-plugin-plugins-data-server.searchsessionservice._constructor_.md) - -## SearchSessionService.(constructor) - -Constructs a new instance of the `SearchSessionService` class - -Signature: - -```typescript -constructor(); -``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.searchsessionservice.asscopedprovider.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.searchsessionservice.asscopedprovider.md deleted file mode 100644 index 4faa7b7663546..0000000000000 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.searchsessionservice.asscopedprovider.md +++ /dev/null @@ -1,35 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [SearchSessionService](./kibana-plugin-plugins-data-server.searchsessionservice.md) > [asScopedProvider](./kibana-plugin-plugins-data-server.searchsessionservice.asscopedprovider.md) - -## SearchSessionService.asScopedProvider() method - -Signature: - -```typescript -asScopedProvider(): () => { - getId: () => never; - trackId: () => Promise; - getSearchIdMapping: () => Promise>; - save: () => Promise; - get: () => Promise; - find: () => Promise; - update: () => Promise; - extend: () => Promise; - cancel: () => Promise; - }; -``` -Returns: - -`() => { - getId: () => never; - trackId: () => Promise; - getSearchIdMapping: () => Promise>; - save: () => Promise; - get: () => Promise; - find: () => Promise; - update: () => Promise; - extend: () => Promise; - cancel: () => Promise; - }` - diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.searchsessionservice.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.searchsessionservice.md deleted file mode 100644 index 2f12d2981b31c..0000000000000 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.searchsessionservice.md +++ /dev/null @@ -1,26 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [SearchSessionService](./kibana-plugin-plugins-data-server.searchsessionservice.md) - -## SearchSessionService class - -The OSS session service, which leaves most search session-related logic unimplemented. x-pack/plugins/data\_enhanced/server/search/session/session\_service.ts - -Signature: - -```typescript -export declare class SearchSessionService implements ISearchSessionService -``` - -## Constructors - -| Constructor | Modifiers | Description | -| --- | --- | --- | -| [(constructor)()](./kibana-plugin-plugins-data-server.searchsessionservice._constructor_.md) | | Constructs a new instance of the SearchSessionService class | - -## Methods - -| Method | Modifiers | Description | -| --- | --- | --- | -| [asScopedProvider()](./kibana-plugin-plugins-data-server.searchsessionservice.asscopedprovider.md) | | | - diff --git a/src/plugins/data/public/public.api.md b/src/plugins/data/public/public.api.md index 9aedfcc27c693..28997de4517e7 100644 --- a/src/plugins/data/public/public.api.md +++ b/src/plugins/data/public/public.api.md @@ -2389,7 +2389,7 @@ export class SearchSource { removeField(field: K): this; serialize(): { searchSourceJSON: string; - references: import("src/core/server").SavedObjectReference[]; + references: import("../../../../../core/types").SavedObjectReference[]; }; setField(field: K, value: SearchSourceFields[K]): this; setFields(newFields: SearchSourceFields): this; diff --git a/src/plugins/data/server/search/session/session_service.ts b/src/plugins/data/server/search/session/session_service.ts index a98ae9a09fe19..dc4f19f126882 100644 --- a/src/plugins/data/server/search/session/session_service.ts +++ b/src/plugins/data/server/search/session/session_service.ts @@ -11,6 +11,7 @@ import { ISearchSessionService } from './types'; /** * The OSS session service, which leaves most search session-related logic unimplemented. * @see x-pack/plugins/data_enhanced/server/search/session/session_service.ts + * @internal */ export class SearchSessionService implements ISearchSessionService { constructor() {} diff --git a/src/plugins/data/server/server.api.md b/src/plugins/data/server/server.api.md index e91f91f0309f0..da407a28811e0 100644 --- a/src/plugins/data/server/server.api.md +++ b/src/plugins/data/server/server.api.md @@ -1132,10 +1132,10 @@ export class Plugin implements Plugin_2 Promise; + fieldFormatServiceFactory: (uiSettings: import("../../../core/server").IUiSettingsClient) => Promise; }; indexPatterns: { - indexPatternsServiceFactory: (savedObjectsClient: Pick, elasticsearchClient: import("src/core/server").ElasticsearchClient) => Promise; + indexPatternsServiceFactory: (savedObjectsClient: Pick, elasticsearchClient: import("../../../core/server").ElasticsearchClient) => Promise; }; search: ISearchStart>; }; @@ -1239,9 +1239,7 @@ export const search: { // @public (undocumented) export type SearchRequestHandlerContext = IScopedSearchClient; -// Warning: (ae-missing-release-tag) "SearchSessionService" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public +// @internal export class SearchSessionService implements ISearchSessionService { constructor(); // (undocumented) diff --git a/x-pack/plugins/data_enhanced/server/routes/session.ts b/x-pack/plugins/data_enhanced/server/routes/session.ts index ff0f47c90582c..b39ffd41f33c8 100644 --- a/x-pack/plugins/data_enhanced/server/routes/session.ts +++ b/x-pack/plugins/data_enhanced/server/routes/session.ts @@ -188,16 +188,10 @@ export function registerSessionRoutes(router: DataEnhancedPluginRouter, logger: 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, - }, - }, - }); + } catch (e) { + const err = e.output?.payload || e; + logger.error(err); + return reportServerError(res, err); } } ); diff --git a/x-pack/plugins/data_enhanced/server/search/session/session_service.ts b/x-pack/plugins/data_enhanced/server/search/session/session_service.ts index dcc52d0e5973d..03466c769d9be 100644 --- a/x-pack/plugins/data_enhanced/server/search/session/session_service.ts +++ b/x-pack/plugins/data_enhanced/server/search/session/session_service.ts @@ -60,6 +60,9 @@ interface StartDependencies { type SearchSessionsConfig = ConfigSchema['search']['sessions']; +/** + * @internal + */ export class SearchSessionService implements ISearchSessionService { /** @@ -321,7 +324,7 @@ export class SearchSessionService deps: SearchSessionDependencies, searchRequest: IKibanaSearchRequest, searchId: string, - { sessionId, isStored, strategy }: ISearchOptions + { sessionId, strategy }: ISearchOptions ) => { if (!sessionId || !searchId) return; this.logger.debug(`trackId | ${sessionId} | ${searchId}`); @@ -332,22 +335,14 @@ export class SearchSessionService status: SearchStatus.IN_PROGRESS, }; - // If there is already a saved object for this session, update it to include this request/ID. - // Otherwise, just update the in-memory mapping for this session for when the session is saved. - if (isStored) { - const attributes = { - idMapping: { [requestHash]: searchInfo }, - }; - await this.update(deps, sessionId, attributes); - } else { - const map = this.sessionSearchMap.get(sessionId) ?? { - insertTime: moment(), - retryCount: 0, - ids: new Map(), - }; - map.ids.set(requestHash, searchInfo); - this.sessionSearchMap.set(sessionId, map); - } + // Update the in-memory mapping for this session for when the session is saved. + const map = this.sessionSearchMap.get(sessionId) ?? { + insertTime: moment(), + retryCount: 0, + ids: new Map(), + }; + map.ids.set(requestHash, searchInfo); + this.sessionSearchMap.set(sessionId, map); }; public async getSearchIdMapping(deps: SearchSessionDependencies, sessionId: string) { diff --git a/x-pack/test/api_integration/apis/search/session.ts b/x-pack/test/api_integration/apis/search/session.ts index 89946a331abd0..96d601a00ff36 100644 --- a/x-pack/test/api_integration/apis/search/session.ts +++ b/x-pack/test/api_integration/apis/search/session.ts @@ -6,6 +6,7 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../ftr_provider_context'; +import { SearchSessionStatus } from '../../../../plugins/data_enhanced/common'; export default function ({ getService }: FtrProviderContext) { const supertest = getService('supertest'); @@ -29,11 +30,11 @@ export default function ({ getService }: FtrProviderContext) { await supertest.get(`/internal/session/${sessionId}`).set('kbn-xsrf', 'foo').expect(200); }); - it('should fail to delete an unknown session', async () => { + it('should fail to cancel an unknown session', async () => { await supertest.delete(`/internal/session/123`).set('kbn-xsrf', 'foo').expect(404); }); - it('should create and delete a session', async () => { + it('should create and cancel a session', async () => { const sessionId = `my-session-${Math.random()}`; await supertest .post(`/internal/session`) @@ -48,6 +49,14 @@ export default function ({ getService }: FtrProviderContext) { .expect(200); await supertest.delete(`/internal/session/${sessionId}`).set('kbn-xsrf', 'foo').expect(200); + + const resp = await supertest + .get(`/internal/session/${sessionId}`) + .set('kbn-xsrf', 'foo') + .expect(200); + + const { status } = resp.body.attributes; + expect(status).to.equal(SearchSessionStatus.CANCELLED); }); it('should sync search ids into session', async () => { @@ -140,10 +149,20 @@ export default function ({ getService }: FtrProviderContext) { .post(`/internal/session/${sessionId}/_extend`) .set('kbn-xsrf', 'foo') .send({ - keepAlive: '5m', + expires: '2021-02-26T21:02:43.742Z', }) .expect(200); }); }); + + it('should fail to extend a nonexistent session', async () => { + await supertest + .post(`/internal/session/123/_extend`) + .set('kbn-xsrf', 'foo') + .send({ + expires: '2021-02-26T21:02:43.742Z', + }) + .expect(404); + }); }); } From b2bce4b10cfdfaee76d01780a18e8ff184f61535 Mon Sep 17 00:00:00 2001 From: Liza K Date: Wed, 27 Jan 2021 11:58:35 +0200 Subject: [PATCH 16/20] fix ts --- .../server/routes/session.test.ts | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/x-pack/plugins/data_enhanced/server/routes/session.test.ts b/x-pack/plugins/data_enhanced/server/routes/session.test.ts index 6b571e7321b06..6af7618e43d9b 100644 --- a/x-pack/plugins/data_enhanced/server/routes/session.test.ts +++ b/x-pack/plugins/data_enhanced/server/routes/session.test.ts @@ -14,33 +14,17 @@ import type { } from '../../../../../src/plugins/data/server'; import { dataPluginMock } from '../../../../../src/plugins/data/server/mocks'; import { registerSessionRoutes } from './session'; -import { BehaviorSubject } from 'rxjs'; -import { ConfigSchema } from '../../config'; -import moment from 'moment'; describe('registerSessionRoutes', () => { let mockCoreSetup: MockedKeys>; let mockContext: jest.Mocked; let mockLogger: Logger; - const mockConfig$ = new BehaviorSubject({ - search: { - sessions: { - enabled: true, - pageSize: 10000, - inMemTimeout: moment.duration(1, 'm'), - maxUpdateRetries: 3, - defaultExpiration: moment.duration(7, 'd'), - trackingInterval: moment.duration(10, 's'), - management: {} as any, - }, - }, - }); beforeEach(() => { mockCoreSetup = coreMock.createSetup(); mockLogger = coreMock.createPluginInitializerContext().logger.get(); mockContext = dataPluginMock.createRequestHandlerContext(); - registerSessionRoutes(mockCoreSetup.http.createRouter(), mockLogger, mockConfig$); + registerSessionRoutes(mockCoreSetup.http.createRouter(), mockLogger); }); it('save calls saveSession with sessionId and attributes', async () => { From e24181cef4ac55ceedf63a118ea85e7ce1399f65 Mon Sep 17 00:00:00 2001 From: Lukas Olson Date: Thu, 28 Jan 2021 08:49:36 -0700 Subject: [PATCH 17/20] Remove test that is no longer valid --- .../search/session/session_service.test.ts | 24 ------------------- 1 file changed, 24 deletions(-) diff --git a/x-pack/plugins/data_enhanced/server/search/session/session_service.test.ts b/x-pack/plugins/data_enhanced/server/search/session/session_service.test.ts index 08d79f38dd5f1..38661ff352ffe 100644 --- a/x-pack/plugins/data_enhanced/server/search/session/session_service.test.ts +++ b/x-pack/plugins/data_enhanced/server/search/session/session_service.test.ts @@ -16,7 +16,6 @@ import { coreMock } from 'src/core/server/mocks'; import { ConfigSchema } from '../../../config'; // @ts-ignore import { taskManagerMock } from '../../../../task_manager/server/mocks'; -import { SearchStatus } from './types'; const INMEM_TRACKING_INTERVAL = 10000; const MAX_UPDATE_RETRIES = 3; @@ -264,29 +263,6 @@ describe('SearchSessionService', () => { expect(setParams.ids.get(requestHash).strategy).toBe(MOCK_STRATEGY); expect(setSessionId).toBe(sessionId); }); - - it('updates saved object when `isStored` is `true`', async () => { - const searchRequest = { params: {} }; - const requestHash = createRequestHash(searchRequest.params); - const searchId = 'FnpFYlBpeXdCUTMyZXhCLTc1TWFKX0EbdDFDTzJzTE1Sck9PVTBIcW1iU05CZzo4MDA0'; - const isStored = true; - - await service.trackId({ savedObjectsClient }, searchRequest, searchId, { - sessionId, - isStored, - strategy: MOCK_STRATEGY, - }); - - expect(savedObjectsClient.update).toHaveBeenCalledWith(SEARCH_SESSION_TYPE, sessionId, { - idMapping: { - [requestHash]: { - id: searchId, - strategy: MOCK_STRATEGY, - status: SearchStatus.IN_PROGRESS, - }, - }, - }); - }); }); describe('getId', () => { From 99dc3472854daab1486503a3613f4757be100e12 Mon Sep 17 00:00:00 2001 From: Lukas Olson Date: Mon, 1 Feb 2021 15:09:30 -0700 Subject: [PATCH 18/20] Fix undefined bug --- src/plugins/data/server/search/search_service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/data/server/search/search_service.ts b/src/plugins/data/server/search/search_service.ts index 1df8973b3abbd..24e604b3a92e0 100644 --- a/src/plugins/data/server/search/search_service.ts +++ b/src/plugins/data/server/search/search_service.ts @@ -134,7 +134,7 @@ export class SearchService implements Plugin { ) ); - registerBsearchRoute(bfetch, this.asScoped); + registerBsearchRoute(bfetch, (request: KibanaRequest) => this.asScoped(request)); core.savedObjects.registerType(searchTelemetry); if (usageCollection) { From 3eb8f010994ac5a29a3047f19730234fb605e456 Mon Sep 17 00:00:00 2001 From: Liza K Date: Wed, 3 Feb 2021 14:23:04 +0200 Subject: [PATCH 19/20] Use DataRequestHandlerContext in maps --- x-pack/plugins/maps/server/mvt/get_tile.ts | 8 ++++---- x-pack/plugins/maps/server/mvt/mvt_routes.ts | 9 ++++----- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/x-pack/plugins/maps/server/mvt/get_tile.ts b/x-pack/plugins/maps/server/mvt/get_tile.ts index fb2b1b675dde0..30a22bfb6164a 100644 --- a/x-pack/plugins/maps/server/mvt/get_tile.ts +++ b/x-pack/plugins/maps/server/mvt/get_tile.ts @@ -8,8 +8,8 @@ import geojsonvt from 'geojson-vt'; // @ts-expect-error import vtpbf from 'vt-pbf'; -import { Logger, RequestHandlerContext } from 'src/core/server'; -import type { DataApiRequestHandlerContext } from 'src/plugins/data/server'; +import { Logger } from 'src/core/server'; +import type { DataRequestHandlerContext } from 'src/plugins/data/server'; import { Feature, FeatureCollection, Polygon } from 'geojson'; import { ES_GEO_FIELD_TYPE, @@ -45,7 +45,7 @@ export async function getGridTile({ z: number; geometryFieldName: string; index: string; - context: RequestHandlerContext & { search: DataApiRequestHandlerContext }; + context: DataRequestHandlerContext; logger: Logger; requestBody: any; requestType: RENDER_AS; @@ -125,7 +125,7 @@ export async function getTile({ z: number; geometryFieldName: string; index: string; - context: RequestHandlerContext & { search: DataApiRequestHandlerContext }; + context: DataRequestHandlerContext; logger: Logger; requestBody: any; geoFieldType: ES_GEO_FIELD_TYPE; diff --git a/x-pack/plugins/maps/server/mvt/mvt_routes.ts b/x-pack/plugins/maps/server/mvt/mvt_routes.ts index 65692619b333a..b974757ece671 100644 --- a/x-pack/plugins/maps/server/mvt/mvt_routes.ts +++ b/x-pack/plugins/maps/server/mvt/mvt_routes.ts @@ -10,10 +10,9 @@ import { KibanaRequest, KibanaResponseFactory, Logger, - RequestHandlerContext, } from 'src/core/server'; import { IRouter } from 'src/core/server'; -import type { DataApiRequestHandlerContext } from 'src/plugins/data/server'; +import type { DataRequestHandlerContext } from 'src/plugins/data/server'; import { MVT_GETTILE_API_PATH, API_ROOT_PATH, @@ -29,7 +28,7 @@ export function initMVTRoutes({ router, logger, }: { - router: IRouter; + router: IRouter; logger: Logger; }) { router.get( @@ -49,7 +48,7 @@ export function initMVTRoutes({ }, }, async ( - context: RequestHandlerContext & { search: DataApiRequestHandlerContext }, + context: DataRequestHandlerContext, request: KibanaRequest, unknown>, response: KibanaResponseFactory ) => { @@ -91,7 +90,7 @@ export function initMVTRoutes({ }, }, async ( - context: RequestHandlerContext & { search: DataApiRequestHandlerContext }, + context: DataRequestHandlerContext, request: KibanaRequest, unknown>, response: KibanaResponseFactory ) => { From 6462da691cc636c8421041bdda3520c3b8e8a620 Mon Sep 17 00:00:00 2001 From: Liza K Date: Wed, 3 Feb 2021 14:24:25 +0200 Subject: [PATCH 20/20] ts --- x-pack/plugins/maps/server/mvt/mvt_routes.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/x-pack/plugins/maps/server/mvt/mvt_routes.ts b/x-pack/plugins/maps/server/mvt/mvt_routes.ts index b974757ece671..cf56000d61451 100644 --- a/x-pack/plugins/maps/server/mvt/mvt_routes.ts +++ b/x-pack/plugins/maps/server/mvt/mvt_routes.ts @@ -6,11 +6,7 @@ import rison from 'rison-node'; import { schema } from '@kbn/config-schema'; -import { - KibanaRequest, - KibanaResponseFactory, - Logger, -} from 'src/core/server'; +import { KibanaRequest, KibanaResponseFactory, Logger } from 'src/core/server'; import { IRouter } from 'src/core/server'; import type { DataRequestHandlerContext } from 'src/plugins/data/server'; import {