From bd1cf6e074863b43473b11ac643cbe9974470ec2 Mon Sep 17 00:00:00 2001 From: Lukas Olson Date: Fri, 18 Oct 2024 14:53:11 -0700 Subject: [PATCH 01/13] Move consumers off bsearch endpoint --- .../index.ts | 2 +- .../services/all.ts | 4 +- .../services/{bsearch.ts => search.ts} | 48 +--- test/common/services/index.ts | 4 +- .../configurations.handlers.mock.ts | 56 ++-- .../configurations/configurations.test.tsx | 20 +- .../public/test/mock_server/mock_server.ts | 4 +- .../public/hooks/use_es_search.ts | 4 +- .../synthetics/state/elasticsearch/api.ts | 4 +- x-pack/test/common/services/index.ts | 4 +- .../{bsearch_secure.ts => search_secure.ts} | 18 +- .../tests/basic/search_strategy.ts | 28 +- .../config/serverless/services.ts | 4 +- .../services/security_solution_ess_utils.ts | 4 +- ...ity_solution_serverless_bsearch_creator.ts | 6 +- .../security_solution_serverless_utils.ts | 16 +- .../config/services/types.ts | 10 +- .../tests/host_details.ts | 8 +- .../tests/hosts.ts | 16 +- .../tests/uncommon_processes.ts | 12 +- .../tests/network_details.ts | 12 +- .../tests/network_dns.ts | 10 +- .../tests/network_top_n_flow.ts | 14 +- .../trial_license_complete_tier/tests/tls.ts | 16 +- .../tests/overview_host.ts | 8 +- .../tests/overview_network.ts | 16 +- .../tests/authentications.ts | 10 +- .../tests/users.ts | 8 +- .../investigation/timeline/tests/events.ts | 10 +- .../timeline/tests/timeline_details.ts | 10 +- .../cypress/tasks/create_new_rule.ts | 2 +- .../test_suites/common/search_oss/bsearch.ts | 247 ------------------ .../test_suites/common/search_oss/index.ts | 1 - .../{bsearch_secure.ts => search_secure.ts} | 21 +- 34 files changed, 177 insertions(+), 480 deletions(-) rename packages/kbn-ftr-common-functional-services/services/{bsearch.ts => search.ts} (63%) rename x-pack/test/common/services/{bsearch_secure.ts => search_secure.ts} (91%) delete mode 100644 x-pack/test_serverless/api_integration/test_suites/common/search_oss/bsearch.ts rename x-pack/test_serverless/shared/services/{bsearch_secure.ts => search_secure.ts} (87%) diff --git a/packages/kbn-ftr-common-functional-services/index.ts b/packages/kbn-ftr-common-functional-services/index.ts index a975c175c5837..10ded3da0d352 100644 --- a/packages/kbn-ftr-common-functional-services/index.ts +++ b/packages/kbn-ftr-common-functional-services/index.ts @@ -39,7 +39,7 @@ export type SamlAuthProviderType = ProvidedType; export type { FtrProviderContext } from './services/ftr_provider_context'; export { runSavedObjInfoSvc } from './services/saved_object_info'; -export type { BsearchService, SendOptions } from './services/bsearch'; +export type { SearchService, SendOptions } from './services/search'; export { SavedObjectInfoService } from './services/saved_object_info'; export { DeploymentService } from './services/deployment'; export { IndexPatternsService } from './services/index_patterns'; diff --git a/packages/kbn-ftr-common-functional-services/services/all.ts b/packages/kbn-ftr-common-functional-services/services/all.ts index 2caec10c10eb8..dd11b2b914b08 100644 --- a/packages/kbn-ftr-common-functional-services/services/all.ts +++ b/packages/kbn-ftr-common-functional-services/services/all.ts @@ -11,7 +11,7 @@ import { EsArchiverProvider } from './es_archiver'; import { EsProvider } from './es'; import { KibanaServerProvider } from './kibana_server'; import { RetryService } from './retry'; -import { BsearchService } from './bsearch'; +import { SearchService } from './search'; import { ConsoleProvider } from './console'; import { DeploymentService } from './deployment'; import { EsDeleteAllIndicesProvider } from './es_delete_all_indices'; @@ -27,7 +27,7 @@ export const services = { kibanaServer: KibanaServerProvider, esArchiver: EsArchiverProvider, retry: RetryService, - bsearch: BsearchService, + search: SearchService, console: ConsoleProvider, deployment: DeploymentService, esDeleteAllIndices: EsDeleteAllIndicesProvider, diff --git a/packages/kbn-ftr-common-functional-services/services/bsearch.ts b/packages/kbn-ftr-common-functional-services/services/search.ts similarity index 63% rename from packages/kbn-ftr-common-functional-services/services/bsearch.ts rename to packages/kbn-ftr-common-functional-services/services/search.ts index 0fc39cb87cd8e..c087f1d8bb913 100644 --- a/packages/kbn-ftr-common-functional-services/services/bsearch.ts +++ b/packages/kbn-ftr-common-functional-services/services/search.ts @@ -8,26 +8,11 @@ */ import expect from '@kbn/expect'; -import request from 'superagent'; import type SuperTest from 'supertest'; import type { IEsSearchResponse } from '@kbn/search-types'; import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; -import { BFETCH_ROUTE_VERSION_LATEST } from '@kbn/bfetch-plugin/common'; import { FtrService } from './ftr_provider_context'; -/** - * Function copied from here: - * test/api_integration/apis/search/bsearch.ts without the compress - * - * Splits the JSON lines from bsearch - */ -const parseBfetchResponse = (resp: request.Response): Array> => { - return resp.text - .trim() - .split('\n') - .map((item) => JSON.parse(item)); -}; - /** * Function copied from here: * x-pack/test/rule_registry/common/lib/authentication/spaces.ts @@ -48,13 +33,13 @@ export interface SendOptions { } /** - * Bsearch Service that can reduce flake on the CI systems when they are under - * pressure and bsearch returns an async search response or a sync response. + * Search Service that can reduce flake on the CI systems when they are under + * pressure and search returns an async search response or a sync response. * * @example * const supertest = getService('supertest'); - * const bsearch = getService('bsearch'); - * const response = await bsearch.send({ + * const search = getService('search'); + * const response = await search.send({ * supertest, * options: { * defaultIndex: ['large_volume_dns_data'], @@ -64,7 +49,7 @@ export interface SendOptions { * expect(response).eql({ ... your value ... }); */ -export class BsearchService extends FtrService { +export class SearchService extends FtrService { private readonly retry = this.ctx.getService('retry'); /** Send method to send in your supertest, url, options, and strategy name */ @@ -85,26 +70,13 @@ export class BsearchService extends FtrService { const result = await this.retry.try(async () => { const resp = await supertest - .post(`${spaceUrl}/internal/bsearch`) + .post(`${spaceUrl}/internal/search/${strategy}/${body.id}`) .set('kbn-xsrf', 'true') - .set(ELASTIC_HTTP_VERSION_HEADER, BFETCH_ROUTE_VERSION_LATEST) - .send({ - batch: [ - { - request: { - id: body.id, - ...options, - }, - options: { - strategy, - }, - }, - ], - }) + .set(ELASTIC_HTTP_VERSION_HEADER, '1') + .send() .expect(200); - const [parsedResponse] = parseBfetchResponse(resp); - expect(parsedResponse.result.isRunning).equal(false); - return parsedResponse.result as T; + expect(resp.body.isRunning).equal(false); + return resp.body as T; }); return result; } diff --git a/test/common/services/index.ts b/test/common/services/index.ts index a2b80c01a18b0..c3fcdda2cf937 100644 --- a/test/common/services/index.ts +++ b/test/common/services/index.ts @@ -21,7 +21,7 @@ const { esDeleteAllIndices, savedObjectInfo, indexPatterns, - bsearch, + search, console, supertest, esSupertest, @@ -42,7 +42,7 @@ export const services = { esDeleteAllIndices, savedObjectInfo, indexPatterns, - bsearch, + search, console, supertest, esSupertest, diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/configurations.handlers.mock.ts b/x-pack/plugins/cloud_security_posture/public/pages/configurations/configurations.handlers.mock.ts index be08984c16dbe..e31ce74ee945b 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/configurations.handlers.mock.ts +++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/configurations.handlers.mock.ts @@ -151,7 +151,7 @@ export const generateFindingHit = (finding: CspFinding) => { }; }; -const getFindingsBsearchResponse = (findings: CspFinding[]) => { +const getFindingsSearchResponse = (findings: CspFinding[]) => { const buckets = findings.reduce( (acc, finding) => { if (finding.result.evaluation === 'failed') { @@ -174,28 +174,26 @@ const getFindingsBsearchResponse = (findings: CspFinding[]) => { ); return { - id: 0, - result: { - rawResponse: { - took: 1, - timed_out: false, - _shards: { - total: 1, - successful: 1, - skipped: 0, - failed: 0, - }, - hits: { - total: findings.length, - max_score: null, - hits: findings.map(generateFindingHit), - }, - aggregations: { - count: { - doc_count_error_upper_bound: 0, - sum_other_doc_count: 0, - buckets, - }, + id: '1', + rawResponse: { + took: 1, + timed_out: false, + _shards: { + total: 1, + successful: 1, + skipped: 0, + failed: 0, + }, + hits: { + total: findings.length, + max_score: null, + hits: findings.map(generateFindingHit), + }, + aggregations: { + count: { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 0, + buckets, }, }, isPartial: false, @@ -214,8 +212,8 @@ export const rulesGetStatesHandler = http.get( } ); -export const bsearchFindingsHandler = (findings: CspFinding[]) => - http.post('internal/bsearch', async ({ request }) => { +export const searchFindingsHandler = (findings: CspFinding[]) => + http.post('internal/search', async ({ request }) => { const jsonRequest = (await request.json()) as Partial; const filter = jsonRequest?.query?.bool?.filter; @@ -233,7 +231,7 @@ export const bsearchFindingsHandler = (findings: CspFinding[]) => return finding.rule.section === termValue; }); - return HttpResponse.json(getFindingsBsearchResponse(filteredFindings)); + return HttpResponse.json(getFindingsSearchResponse(filteredFindings)); } const hasRuleSectionFilter = @@ -244,7 +242,7 @@ export const bsearchFindingsHandler = (findings: CspFinding[]) => return finding.rule.section === filter?.[0]?.match_phrase?.['rule.section']; }); - return HttpResponse.json(getFindingsBsearchResponse(filteredFindings)); + return HttpResponse.json(getFindingsSearchResponse(filteredFindings)); } const hasResultEvaluationFilter = @@ -255,8 +253,8 @@ export const bsearchFindingsHandler = (findings: CspFinding[]) => return finding.result.evaluation === filter?.[0]?.match_phrase?.['result.evaluation']; }); - return HttpResponse.json(getFindingsBsearchResponse(filteredFindings)); + return HttpResponse.json(getFindingsSearchResponse(filteredFindings)); } - return HttpResponse.json(getFindingsBsearchResponse(findings)); + return HttpResponse.json(getFindingsSearchResponse(findings)); }); diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/configurations.test.tsx b/x-pack/plugins/cloud_security_posture/public/pages/configurations/configurations.test.tsx index 8f1a8f159ced5..cd834f4606356 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/configurations.test.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/configurations.test.tsx @@ -20,7 +20,7 @@ import { FilterManager } from '@kbn/data-plugin/public'; import { CspClientPluginStartDeps } from '@kbn/cloud-security-posture'; import * as statusHandlers from '../../../server/routes/status/status.handlers.mock'; import { - bsearchFindingsHandler, + searchFindingsHandler, generateCspFinding, generateMultipleCspFindings, rulesGetStatesHandler, @@ -58,7 +58,7 @@ describe('', () => { const finding2 = generateCspFinding('0004', 'passed'); server.use(statusHandlers.notInstalledHasMisconfigurationsFindingsHandler); - server.use(bsearchFindingsHandler([finding1, finding2])); + server.use(searchFindingsHandler([finding1, finding2])); renderFindingsPage(); // Loading while checking the status API and fetching the findings @@ -89,7 +89,7 @@ describe('', () => { const finding2 = generateCspFinding('0002', 'passed'); server.use(statusHandlers.indexedHandler); - server.use(bsearchFindingsHandler([finding1, finding2])); + server.use(searchFindingsHandler([finding1, finding2])); renderFindingsPage(); // Loading while checking the status API @@ -118,7 +118,7 @@ describe('', () => { const finding2 = generateCspFinding('0002', 'passed'); server.use(statusHandlers.indexedHandler); - server.use(bsearchFindingsHandler([finding1, finding2])); + server.use(searchFindingsHandler([finding1, finding2])); renderFindingsPage(); @@ -148,7 +148,7 @@ describe('', () => { const finding2 = generateCspFinding('0002', 'passed'); server.use(statusHandlers.indexedHandler); - server.use(bsearchFindingsHandler([finding1, finding2])); + server.use(searchFindingsHandler([finding1, finding2])); renderFindingsPage(); @@ -180,7 +180,7 @@ describe('', () => { const finding2 = generateCspFinding('0002', 'passed'); server.use(statusHandlers.indexedHandler); - server.use(bsearchFindingsHandler([finding1, finding2])); + server.use(searchFindingsHandler([finding1, finding2])); renderFindingsPage(); @@ -259,7 +259,7 @@ describe('', () => { }; server.use(statusHandlers.indexedHandler); - server.use(bsearchFindingsHandler([finding1, finding2])); + server.use(searchFindingsHandler([finding1, finding2])); renderFindingsPage(mockDependenciesWithFilter); @@ -286,7 +286,7 @@ describe('', () => { it('renders the distribution bar', async () => { server.use(statusHandlers.indexedHandler); server.use( - bsearchFindingsHandler( + searchFindingsHandler( generateMultipleCspFindings({ count: 10, failedCount: 3, @@ -316,7 +316,7 @@ describe('', () => { it('filters by passed findings when clicking on the passed findings button', async () => { server.use(statusHandlers.indexedHandler); server.use( - bsearchFindingsHandler( + searchFindingsHandler( generateMultipleCspFindings({ count: 2, failedCount: 1, @@ -352,7 +352,7 @@ describe('', () => { it('filters by failed findings when clicking on the failed findings button', async () => { server.use(statusHandlers.indexedHandler); server.use( - bsearchFindingsHandler( + searchFindingsHandler( generateMultipleCspFindings({ count: 2, failedCount: 1, diff --git a/x-pack/plugins/cloud_security_posture/public/test/mock_server/mock_server.ts b/x-pack/plugins/cloud_security_posture/public/test/mock_server/mock_server.ts index 86ec3e3108f27..1c5480f339a64 100644 --- a/x-pack/plugins/cloud_security_posture/public/test/mock_server/mock_server.ts +++ b/x-pack/plugins/cloud_security_posture/public/test/mock_server/mock_server.ts @@ -28,7 +28,7 @@ jest.mock('rxjs', () => { ...actual, lastValueFrom: async (source: Promise) => { const value = await source; - return value.result; + return value; }, }; }); @@ -97,7 +97,7 @@ export const getMockServerDependencies = () => { search: { ...getMockDependencies().data.search, search: async ({ params }: { params: any }) => { - const response = await fetch(`${MOCK_SERVER_BASE_URL}/internal/bsearch`, { + const response = await fetch(`${MOCK_SERVER_BASE_URL}/internal/search`, { method: 'POST', headers: { 'Content-Type': 'application/json', diff --git a/x-pack/plugins/observability_solution/observability_shared/public/hooks/use_es_search.ts b/x-pack/plugins/observability_solution/observability_shared/public/hooks/use_es_search.ts index ef38cf13a8c2a..1560df88c7873 100644 --- a/x-pack/plugins/observability_solution/observability_shared/public/hooks/use_es_search.ts +++ b/x-pack/plugins/observability_solution/observability_shared/public/hooks/use_es_search.ts @@ -64,7 +64,7 @@ export const useEsSearch = ({ @@ -109,24 +109,12 @@ export class BsearchSecureService extends FtrService { const result = await this.retry.try(async () => { const resp = await supertestWithoutAuth - .post(`${spaceUrl}/internal/bsearch`) + .post(`${spaceUrl}/internal/search/${strategy}/${body.id}`) .auth(auth.username, auth.password) .set('kbn-xsrf', 'true') .set('x-elastic-internal-origin', 'Kibana') .set(ELASTIC_HTTP_VERSION_HEADER, BFETCH_ROUTE_VERSION_LATEST) - .send({ - batch: [ - { - request: { - id: body.id, - ...options, - }, - options: { - strategy, - }, - }, - ], - }) + .send() .expect(200); const [parsedResponse] = parseBfetchResponse(resp); expect(parsedResponse.result.isRunning).equal(false); diff --git a/x-pack/test/rule_registry/security_and_spaces/tests/basic/search_strategy.ts b/x-pack/test/rule_registry/security_and_spaces/tests/basic/search_strategy.ts index 289fe4347e8f6..ffcd6fee5cf85 100644 --- a/x-pack/test/rule_registry/security_and_spaces/tests/basic/search_strategy.ts +++ b/x-pack/test/rule_registry/security_and_spaces/tests/basic/search_strategy.ts @@ -26,7 +26,7 @@ type RuleRegistrySearchResponseWithErrors = RuleRegistrySearchResponse & { export default ({ getService }: FtrProviderContext) => { const esArchiver = getService('esArchiver'); const supertestWithoutAuth = getService('supertestWithoutAuth'); - const secureBsearch = getService('secureBsearch'); + const secureSearch = getService('secureSearch'); const kbnClient = getService('kibanaServer'); describe('ruleRegistryAlertsSearchStrategy', () => { @@ -44,7 +44,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should return alerts from log rules', async () => { - const result = await secureBsearch.send({ + const result = await secureSearch.send({ supertestWithoutAuth, auth: { username: logsOnlySpacesAll.username, @@ -66,7 +66,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should support pagination and sorting', async () => { - const result = await secureBsearch.send({ + const result = await secureSearch.send({ supertestWithoutAuth, auth: { username: logsOnlySpacesAll.username, @@ -113,7 +113,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should return alerts from siem rules', async () => { - const result = await secureBsearch.send({ + const result = await secureSearch.send({ supertestWithoutAuth, auth: { username: secOnlySpacesAllEsReadAll.username, @@ -135,7 +135,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should throw an error when trying to to search for more than just siem', async () => { - const result = await secureBsearch.send({ + const result = await secureSearch.send({ supertestWithoutAuth, auth: { username: secOnlySpacesAllEsReadAll.username, @@ -158,7 +158,7 @@ export default ({ getService }: FtrProviderContext) => { it('should be able to handle runtime fields on alerts from siem rules', async () => { const runtimeFieldValue = 'hello world'; const runtimeFieldKey = 'hello_world'; - const result = await secureBsearch.send({ + const result = await secureSearch.send({ supertestWithoutAuth, auth: { username: secOnlySpacesAllEsReadAll.username, @@ -197,7 +197,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should return alerts from apm rules', async () => { - const result = await secureBsearch.send({ + const result = await secureSearch.send({ supertestWithoutAuth, auth: { username: obsOnlySpacesAll.username, @@ -220,7 +220,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should not by pass our RBAC authz filter with a should filter', async () => { - const result = await secureBsearch.send({ + const result = await secureSearch.send({ supertestWithoutAuth, auth: { username: obsOnlySpacesAll.username, @@ -264,7 +264,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should return an empty response with must filter and our RBAC authz filter', async () => { - const result = await secureBsearch.send({ + const result = await secureSearch.send({ supertestWithoutAuth, auth: { username: obsOnlySpacesAll.username, @@ -304,7 +304,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should not by pass our RBAC authz filter with must_not filter', async () => { - const result = await secureBsearch.send({ + const result = await secureSearch.send({ supertestWithoutAuth, auth: { username: obsOnlySpacesAll.username, @@ -357,7 +357,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should return alerts from .es-query rule type with consumer discover with access only to stack rules', async () => { - const result = await secureBsearch.send({ + const result = await secureSearch.send({ supertestWithoutAuth, auth: { username: stackAlertsOnlyAllSpacesAll.username, @@ -382,7 +382,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should return alerts from .es-query rule type with consumer discover as superuser', async () => { - const result = await secureBsearch.send({ + const result = await secureSearch.send({ supertestWithoutAuth, auth: { username: superUser.username, @@ -407,7 +407,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should not return alerts from .es-query rule type with consumer discover without access to stack rules', async () => { - const result = await secureBsearch.send({ + const result = await secureSearch.send({ supertestWithoutAuth, auth: { username: logsOnlySpacesAll.username, @@ -429,7 +429,7 @@ export default ({ getService }: FtrProviderContext) => { describe('empty response', () => { it('should return an empty response', async () => { - const result = await secureBsearch.send({ + const result = await secureSearch.send({ supertestWithoutAuth, auth: { username: obsOnlySpacesAll.username, diff --git a/x-pack/test/security_solution_api_integration/config/serverless/services.ts b/x-pack/test/security_solution_api_integration/config/serverless/services.ts index 61b6c484ced3d..a7e9be3588842 100644 --- a/x-pack/test/security_solution_api_integration/config/serverless/services.ts +++ b/x-pack/test/security_solution_api_integration/config/serverless/services.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { BsearchSecureService } from '@kbn/test-suites-serverless/shared/services/bsearch_secure'; +import { SearchSecureService } from '@kbn/test-suites-serverless/shared/services/search_secure'; import { services as serverlessServices } from '@kbn/test-suites-serverless/api_integration/services'; import { SpacesServiceProvider } from '../../../common/services/spaces'; import { SecuritySolutionServerlessUtils } from '../services/security_solution_serverless_utils'; @@ -14,7 +14,7 @@ import { SecuritySolutionServerlessSuperTest } from '../services/security_soluti export const services = { ...serverlessServices, spaces: SpacesServiceProvider, - secureBsearch: BsearchSecureService, + secureSearch: SearchSecureService, securitySolutionUtils: SecuritySolutionServerlessUtils, supertest: SecuritySolutionServerlessSuperTest, }; diff --git a/x-pack/test/security_solution_api_integration/config/services/security_solution_ess_utils.ts b/x-pack/test/security_solution_api_integration/config/services/security_solution_ess_utils.ts index 158ef1e3756b3..971fe91ea8d74 100644 --- a/x-pack/test/security_solution_api_integration/config/services/security_solution_ess_utils.ts +++ b/x-pack/test/security_solution_api_integration/config/services/security_solution_ess_utils.ts @@ -14,13 +14,13 @@ export function SecuritySolutionESSUtils({ getService, }: FtrProviderContextWithSpaces): SecuritySolutionESSUtilsInterface { const config = getService('config'); - const bsearch = getService('bsearch'); + const search = getService('search'); const supertestWithoutAuth = getService('supertest'); return { getUsername: (_role?: string) => Promise.resolve(config.get('servers.kibana.username') as string), - createBsearch: (_role?: string) => Promise.resolve(bsearch), + createSearch: (_role?: string) => Promise.resolve(search), createSuperTest: async (role?: string, password: string = 'changeme') => { if (!role) { return supertestWithoutAuth; diff --git a/x-pack/test/security_solution_api_integration/config/services/security_solution_serverless_bsearch_creator.ts b/x-pack/test/security_solution_api_integration/config/services/security_solution_serverless_bsearch_creator.ts index 3a0f7391c1ff7..b8e2c13f54be6 100644 --- a/x-pack/test/security_solution_api_integration/config/services/security_solution_serverless_bsearch_creator.ts +++ b/x-pack/test/security_solution_api_integration/config/services/security_solution_serverless_bsearch_creator.ts @@ -7,8 +7,8 @@ import { FtrProviderContext } from '../../ftr_provider_context'; -export async function SecuritySolutionServerlessBsearchCreator({ getService }: FtrProviderContext) { - const { createBsearch } = getService('securitySolutionUtils'); +export async function SecuritySolutionServerlessSearchCreator({ getService }: FtrProviderContext) { + const { createSearch } = getService('securitySolutionUtils'); - return await createBsearch('admin'); + return await createSearch('admin'); } diff --git a/x-pack/test/security_solution_api_integration/config/services/security_solution_serverless_utils.ts b/x-pack/test/security_solution_api_integration/config/services/security_solution_serverless_utils.ts index 00df4f0374c27..1c41ba20bb6f7 100644 --- a/x-pack/test/security_solution_api_integration/config/services/security_solution_serverless_utils.ts +++ b/x-pack/test/security_solution_api_integration/config/services/security_solution_serverless_utils.ts @@ -10,7 +10,7 @@ import { format as formatUrl } from 'url'; import { IEsSearchResponse } from '@kbn/search-types'; import { RoleCredentials } from '@kbn/test-suites-serverless/shared/services'; import type { SendOptions } from '@kbn/ftr-common-functional-services'; -import type { SendOptions as SecureBsearchSendOptions } from '@kbn/test-suites-serverless/shared/services/bsearch_secure'; +import type { SendOptions as SecureSearchSendOptions } from '@kbn/test-suites-serverless/shared/services/search_secure'; import type { FtrProviderContext } from '../../ftr_provider_context'; import type { SecuritySolutionUtilsInterface } from './types'; @@ -22,7 +22,7 @@ export function SecuritySolutionServerlessUtils({ const svlCommonApi = getService('svlCommonApi'); const config = getService('config'); const log = getService('log'); - const SecureBsearch = getService('secureBsearch'); + const SecureSearch = getService('secureSearch'); const rolesCredentials = new Map(); const commonRequestHeader = svlCommonApi.getCommonRequestHeader(); @@ -71,16 +71,16 @@ export function SecuritySolutionServerlessUtils({ */ createSuperTest, - createBsearch: async (role = 'admin') => { + createSearch: async (role = 'admin') => { const apiKeyHeader = rolesCredentials.get(role)?.apiKeyHeader; if (!apiKeyHeader) { - log.error(`API key for role [${role}] is not available, SecureBsearch cannot be created`); + log.error(`API key for role [${role}] is not available, SecureSearch cannot be created`); } const send = (sendOptions: SendOptions): Promise => { const { supertest: _, ...rest } = sendOptions; - const serverlessSendOptions: SecureBsearchSendOptions = { + const serverlessSendOptions: SecureSearchSendOptions = { ...rest, // We need super test WITHOUT auth to make the request here, as we are setting the auth header in bsearch `apiKeyHeader` supertestWithoutAuth: supertest.agent(kbnUrl), @@ -89,12 +89,12 @@ export function SecuritySolutionServerlessUtils({ }; log.debug( - `Sending request to SecureBsearch with options: ${JSON.stringify(serverlessSendOptions)}` + `Sending request to SecureSearch with options: ${JSON.stringify(serverlessSendOptions)}` ); - return SecureBsearch.send(serverlessSendOptions); + return SecureSearch.send(serverlessSendOptions); }; - return { ...SecureBsearch, send }; + return { ...SecureSearch, send }; }, }; } diff --git a/x-pack/test/security_solution_api_integration/config/services/types.ts b/x-pack/test/security_solution_api_integration/config/services/types.ts index 838f31e69412e..d173ffb6181fb 100644 --- a/x-pack/test/security_solution_api_integration/config/services/types.ts +++ b/x-pack/test/security_solution_api_integration/config/services/types.ts @@ -8,21 +8,21 @@ import TestAgent from 'supertest/lib/agent'; import type { IEsSearchResponse } from '@kbn/search-types'; -import type { BsearchSecureService } from '@kbn/test-suites-serverless/shared/services/bsearch_secure'; -import type { BsearchService, SendOptions } from '@kbn/ftr-common-functional-services'; +import type { SearchSecureService } from '@kbn/test-suites-serverless/shared/services/search_secure'; +import type { SearchService, SendOptions } from '@kbn/ftr-common-functional-services'; -export interface SecuritySolutionServerlessBsearch extends Omit { +export interface SecuritySolutionServerlessSearch extends Omit { send: (options: SendOptions) => Promise; } export interface SecuritySolutionUtilsInterface { getUsername: (role?: string) => Promise; createSuperTest: (role?: string) => Promise>; - createBsearch: (role?: string) => Promise; + createSearch: (role?: string) => Promise; } export interface SecuritySolutionESSUtilsInterface { getUsername: (role?: string) => Promise; - createBsearch: (role?: string) => Promise; + createSearch: (role?: string) => Promise; createSuperTest: (role?: string, password?: string) => Promise>; } diff --git a/x-pack/test/security_solution_api_integration/test_suites/explore/hosts/trial_license_complete_tier/tests/host_details.ts b/x-pack/test/security_solution_api_integration/test_suites/explore/hosts/trial_license_complete_tier/tests/host_details.ts index cf2ac65f1086b..51f046781268a 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/explore/hosts/trial_license_complete_tier/tests/host_details.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/explore/hosts/trial_license_complete_tier/tests/host_details.ts @@ -11,7 +11,7 @@ import { HostsQueries, } from '@kbn/security-solution-plugin/common/search_strategy'; import TestAgent from 'supertest/lib/agent'; -import { BsearchService } from '@kbn/ftr-common-functional-services'; +import { SearchService } from '@kbn/ftr-common-functional-services'; import { FtrProviderContextWithSpaces } from '../../../../../ftr_provider_context_with_spaces'; import { hostDetailsFilebeatExpectedResult } from '../mocks/host_details'; @@ -21,11 +21,11 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { describe('Host Details', () => { let supertest: TestAgent; - let bsearch: BsearchService; + let search: SearchService; describe('With filebeat', () => { before(async () => { supertest = await utils.createSuperTest(); - bsearch = await utils.createBsearch(); + search = await utils.createSearch(); await esArchiver.load('x-pack/test/functional/es_archives/filebeat/default'); }); after( @@ -36,7 +36,7 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { const TO = '3000-01-01T00:00:00.000Z'; it('Make sure that we get HostDetails data', async () => { - const { hostDetails } = await bsearch.send({ + const { hostDetails } = await search.send({ supertest, options: { factoryQueryType: HostsQueries.details, diff --git a/x-pack/test/security_solution_api_integration/test_suites/explore/hosts/trial_license_complete_tier/tests/hosts.ts b/x-pack/test/security_solution_api_integration/test_suites/explore/hosts/trial_license_complete_tier/tests/hosts.ts index 6fdbfec48f161..fc16158729bf7 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/explore/hosts/trial_license_complete_tier/tests/hosts.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/explore/hosts/trial_license_complete_tier/tests/hosts.ts @@ -16,7 +16,7 @@ import { FirstLastSeenStrategyResponse, } from '@kbn/security-solution-plugin/common/search_strategy'; import TestAgent from 'supertest/lib/agent'; -import { BsearchService } from '@kbn/ftr-common-functional-services'; +import { SearchService } from '@kbn/ftr-common-functional-services'; import { FtrProviderContextWithSpaces } from '../../../../../ftr_provider_context_with_spaces'; @@ -35,10 +35,10 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { describe('hosts', () => { let supertest: TestAgent; - let bsearch: BsearchService; + let search: SearchService; before(async () => { supertest = await utils.createSuperTest(); - bsearch = await utils.createBsearch(); + search = await utils.createSearch(); await esArchiver.load('x-pack/test/functional/es_archives/auditbeat/hosts'); }); @@ -47,7 +47,7 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { ); it('Make sure that we get Hosts Table data', async () => { - const hosts = await bsearch.send({ + const hosts = await search.send({ supertest, options: { factoryQueryType: HostsQueries.hosts, @@ -77,7 +77,7 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { }); it('Make sure that pagination is working in Hosts Table query', async () => { - const hosts = await bsearch.send({ + const hosts = await search.send({ supertest, options: { factoryQueryType: HostsQueries.hosts, @@ -107,7 +107,7 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { }); it('Make sure that we get Host details data', async () => { - const { hostDetails } = await bsearch.send({ + const { hostDetails } = await search.send({ supertest, options: { factoryQueryType: HostsQueries.details, @@ -146,7 +146,7 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { }); it('Make sure that we get First Seen for a Host', async () => { - const firstLastSeenHost = await bsearch.send({ + const firstLastSeenHost = await search.send({ supertest, options: { factoryQueryType: FirstLastSeenQuery, @@ -161,7 +161,7 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { }); it('Make sure that we get Last Seen for a Host', async () => { - const firstLastSeenHost = await bsearch.send({ + const firstLastSeenHost = await search.send({ supertest, options: { factoryQueryType: FirstLastSeenQuery, diff --git a/x-pack/test/security_solution_api_integration/test_suites/explore/hosts/trial_license_complete_tier/tests/uncommon_processes.ts b/x-pack/test/security_solution_api_integration/test_suites/explore/hosts/trial_license_complete_tier/tests/uncommon_processes.ts index 22001c26b66b5..958ac9289b5ef 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/explore/hosts/trial_license_complete_tier/tests/uncommon_processes.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/explore/hosts/trial_license_complete_tier/tests/uncommon_processes.ts @@ -12,7 +12,7 @@ import { HostsUncommonProcessesStrategyResponse, } from '@kbn/security-solution-plugin/common/search_strategy'; import TestAgent from 'supertest/lib/agent'; -import { BsearchService } from '@kbn/ftr-common-functional-services'; +import { SearchService } from '@kbn/ftr-common-functional-services'; import { FtrProviderContextWithSpaces } from '../../../../../ftr_provider_context_with_spaces'; const FROM = '2000-01-01T00:00:00.000Z'; @@ -27,10 +27,10 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { describe('hosts', () => { let supertest: TestAgent; - let bsearch: BsearchService; + let search: SearchService; before(async () => { supertest = await utils.createSuperTest(); - bsearch = await utils.createBsearch(); + search = await utils.createSearch(); await esArchiver.load('x-pack/test/functional/es_archives/auditbeat/uncommon_processes'); }); after(async () => { @@ -38,7 +38,7 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { }); it('should return an edge of length 1 when given a pagination of length 1', async () => { - const response = await bsearch.send({ + const response = await search.send({ supertest, options: { factoryQueryType: HostsQueries.uncommonProcesses, @@ -65,7 +65,7 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { describe('when given a pagination of length 2', () => { it('should return an edge of length 2 ', async () => { - const response = await bsearch.send({ + const response = await search.send({ supertest, options: { factoryQueryType: HostsQueries.uncommonProcesses, @@ -93,7 +93,7 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { describe('when given a pagination of length 1', () => { let response: HostsUncommonProcessesStrategyResponse | null = null; before(async () => { - response = await bsearch.send({ + response = await search.send({ supertest, options: { factoryQueryType: HostsQueries.uncommonProcesses, diff --git a/x-pack/test/security_solution_api_integration/test_suites/explore/network/trial_license_complete_tier/tests/network_details.ts b/x-pack/test/security_solution_api_integration/test_suites/explore/network/trial_license_complete_tier/tests/network_details.ts index 166af42ba5702..6fec2ab95f1fe 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/explore/network/trial_license_complete_tier/tests/network_details.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/explore/network/trial_license_complete_tier/tests/network_details.ts @@ -11,7 +11,7 @@ import { NetworkQueries, } from '@kbn/security-solution-plugin/common/search_strategy'; import TestAgent from 'supertest/lib/agent'; -import { BsearchService } from '@kbn/ftr-common-functional-services'; +import { SearchService } from '@kbn/ftr-common-functional-services'; import { FtrProviderContextWithSpaces } from '../../../../../ftr_provider_context_with_spaces'; @@ -21,11 +21,11 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { describe('Network details', () => { let supertest: TestAgent; - let bsearch: BsearchService; + let search: SearchService; describe('With filebeat', () => { before(async () => { supertest = await utils.createSuperTest(); - bsearch = await utils.createBsearch(); + search = await utils.createSearch(); await esArchiver.load('x-pack/test/functional/es_archives/filebeat/default'); }); after( @@ -33,7 +33,7 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { ); it('Make sure that we get Network details data', async () => { - const body = await bsearch.send({ + const body = await search.send({ supertest, options: { ip: '151.205.0.17', @@ -53,7 +53,7 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { describe('With packetbeat', () => { before(async () => { supertest = await utils.createSuperTest(); - bsearch = await utils.createBsearch(); + search = await utils.createSearch(); await esArchiver.load('x-pack/test/functional/es_archives/packetbeat/default'); }); after( @@ -61,7 +61,7 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { ); it('Make sure that we get Network details data', async () => { - const body = await bsearch.send({ + const body = await search.send({ supertest, options: { ip: '185.53.91.88', diff --git a/x-pack/test/security_solution_api_integration/test_suites/explore/network/trial_license_complete_tier/tests/network_dns.ts b/x-pack/test/security_solution_api_integration/test_suites/explore/network/trial_license_complete_tier/tests/network_dns.ts index 22edc8cff64de..cab4ee31744f6 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/explore/network/trial_license_complete_tier/tests/network_dns.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/explore/network/trial_license_complete_tier/tests/network_dns.ts @@ -14,7 +14,7 @@ import { NetworkDnsStrategyResponse, } from '@kbn/security-solution-plugin/common/search_strategy'; import TestAgent from 'supertest/lib/agent'; -import { BsearchService } from '@kbn/ftr-common-functional-services'; +import { SearchService } from '@kbn/ftr-common-functional-services'; import { FtrProviderContextWithSpaces } from '../../../../../ftr_provider_context_with_spaces'; export default function ({ getService }: FtrProviderContextWithSpaces) { @@ -23,11 +23,11 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { describe('Network DNS', () => { let supertest: TestAgent; - let bsearch: BsearchService; + let search: SearchService; describe('With packetbeat', () => { before(async () => { supertest = await utils.createSuperTest(); - bsearch = await utils.createBsearch(); + search = await utils.createSearch(); await esArchiver.load('x-pack/test/functional/es_archives/packetbeat/dns'); }); after( @@ -38,7 +38,7 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { const TO = '3000-01-01T00:00:00.000Z'; it('Make sure that we get Dns data and sorting by uniqueDomains ascending', async () => { - const networkDns = await bsearch.send({ + const networkDns = await search.send({ supertest, options: { defaultIndex: ['packetbeat-*'], @@ -66,7 +66,7 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { }); it('Make sure that we get Dns data and sorting by uniqueDomains descending', async () => { - const networkDns = await bsearch.send({ + const networkDns = await search.send({ supertest, options: { ip: '151.205.0.17', diff --git a/x-pack/test/security_solution_api_integration/test_suites/explore/network/trial_license_complete_tier/tests/network_top_n_flow.ts b/x-pack/test/security_solution_api_integration/test_suites/explore/network/trial_license_complete_tier/tests/network_top_n_flow.ts index 8b1adb16975f6..31eabe76ee0e1 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/explore/network/trial_license_complete_tier/tests/network_top_n_flow.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/explore/network/trial_license_complete_tier/tests/network_top_n_flow.ts @@ -15,7 +15,7 @@ import { NetworkTopNFlowStrategyResponse, } from '@kbn/security-solution-plugin/common/search_strategy'; import TestAgent from 'supertest/lib/agent'; -import { BsearchService } from '@kbn/ftr-common-functional-services'; +import { SearchService } from '@kbn/ftr-common-functional-services'; import { FtrProviderContextWithSpaces } from '../../../../../ftr_provider_context_with_spaces'; @@ -27,11 +27,11 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { describe('Network Top N Flow', () => { let supertest: TestAgent; - let bsearch: BsearchService; + let search: SearchService; describe('With filebeat', () => { before(async () => { supertest = await utils.createSuperTest(); - bsearch = await utils.createBsearch(); + search = await utils.createSearch(); await esArchiver.load('x-pack/test/functional/es_archives/filebeat/default'); }); after( @@ -42,7 +42,7 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { const TO = '2019-02-12T01:57:24.870Z'; it('should get Source NetworkTopNFlow data with bytes_in descending sort', async () => { - const networkTopNFlow = await bsearch.send({ + const networkTopNFlow = await search.send({ supertest, options: { defaultIndex: ['filebeat-*'], @@ -77,7 +77,7 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { }); it('should get Source NetworkTopNFlow data with bytes_in ascending sort ', async () => { - const networkTopNFlow = await bsearch.send({ + const networkTopNFlow = await search.send({ supertest, options: { defaultIndex: ['filebeat-*'], @@ -114,7 +114,7 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { }); it('should get Destination NetworkTopNFlow data', async () => { - const networkTopNFlow = await bsearch.send({ + const networkTopNFlow = await search.send({ supertest, options: { defaultIndex: ['filebeat-*'], @@ -146,7 +146,7 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { }); it('should paginate NetworkTopNFlow query', async () => { - const networkTopNFlow = await bsearch.send({ + const networkTopNFlow = await search.send({ supertest, options: { defaultIndex: ['filebeat-*'], diff --git a/x-pack/test/security_solution_api_integration/test_suites/explore/network/trial_license_complete_tier/tests/tls.ts b/x-pack/test/security_solution_api_integration/test_suites/explore/network/trial_license_complete_tier/tests/tls.ts index 36b2b677a1949..004a79b9788f4 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/explore/network/trial_license_complete_tier/tests/tls.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/explore/network/trial_license_complete_tier/tests/tls.ts @@ -15,7 +15,7 @@ import { } from '@kbn/security-solution-plugin/common/search_strategy'; import TestAgent from 'supertest/lib/agent'; -import { BsearchService } from '@kbn/ftr-common-functional-services'; +import { SearchService } from '@kbn/ftr-common-functional-services'; import { FtrProviderContextWithSpaces } from '../../../../../ftr_provider_context_with_spaces'; @@ -90,11 +90,11 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { describe('Tls Test with Packetbeat', () => { let supertest: TestAgent; - let bsearch: BsearchService; + let search: SearchService; describe('Tls Test', () => { before(async () => { supertest = await utils.createSuperTest(); - bsearch = await utils.createBsearch(); + search = await utils.createSearch(); await esArchiver.load('x-pack/test/functional/es_archives/packetbeat/tls'); }); after( @@ -102,7 +102,7 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { ); it('Ensure data is returned for FlowTarget.Source', async () => { - const tls = await bsearch.send({ + const tls = await search.send({ supertest, options: { factoryQueryType: NetworkQueries.tls, @@ -131,7 +131,7 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { }); it('Ensure data is returned for FlowTarget.Destination', async () => { - const tls = await bsearch.send({ + const tls = await search.send({ supertest, options: { factoryQueryType: NetworkQueries.tls, @@ -163,7 +163,7 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { describe('Tls Overview Test', () => { before(async () => { supertest = await utils.createSuperTest(); - bsearch = await utils.createBsearch(); + search = await utils.createSearch(); await esArchiver.load('x-pack/test/functional/es_archives/packetbeat/tls'); }); after( @@ -171,7 +171,7 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { ); it('Ensure data is returned for FlowTarget.Source', async () => { - const tls = await bsearch.send({ + const tls = await search.send({ supertest, options: { factoryQueryType: NetworkQueries.tls, @@ -200,7 +200,7 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { }); it('Ensure data is returned for FlowTarget.Destination', async () => { - const tls = await bsearch.send({ + const tls = await search.send({ supertest, options: { factoryQueryType: NetworkQueries.tls, diff --git a/x-pack/test/security_solution_api_integration/test_suites/explore/overview/trial_license_complete_tier/tests/overview_host.ts b/x-pack/test/security_solution_api_integration/test_suites/explore/overview/trial_license_complete_tier/tests/overview_host.ts index ffb287239ac0f..89239282376d9 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/explore/overview/trial_license_complete_tier/tests/overview_host.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/explore/overview/trial_license_complete_tier/tests/overview_host.ts @@ -12,7 +12,7 @@ import { HostsOverviewStrategyResponse, } from '@kbn/security-solution-plugin/common/search_strategy'; import TestAgent from 'supertest/lib/agent'; -import { BsearchService } from '@kbn/ftr-common-functional-services'; +import { SearchService } from '@kbn/ftr-common-functional-services'; import { FtrProviderContextWithSpaces } from '../../../../../ftr_provider_context_with_spaces'; export default function ({ getService }: FtrProviderContextWithSpaces) { @@ -21,11 +21,11 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { describe('Overview Host', () => { let supertest: TestAgent; - let bsearch: BsearchService; + let search: SearchService; describe('With auditbeat', () => { before(async () => { supertest = await utils.createSuperTest(); - bsearch = await utils.createBsearch(); + search = await utils.createSearch(); await esArchiver.load('x-pack/test/functional/es_archives/auditbeat/overview'); }); after( @@ -54,7 +54,7 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { }; it('Make sure that we get OverviewHost data', async () => { - const { overviewHost } = await bsearch.send({ + const { overviewHost } = await search.send({ supertest, options: { defaultIndex: ['auditbeat-*'], diff --git a/x-pack/test/security_solution_api_integration/test_suites/explore/overview/trial_license_complete_tier/tests/overview_network.ts b/x-pack/test/security_solution_api_integration/test_suites/explore/overview/trial_license_complete_tier/tests/overview_network.ts index f8d4aa80c0e3d..5d2fc9c5aafdd 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/explore/overview/trial_license_complete_tier/tests/overview_network.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/explore/overview/trial_license_complete_tier/tests/overview_network.ts @@ -11,7 +11,7 @@ import { NetworkQueries, } from '@kbn/security-solution-plugin/common/search_strategy'; import TestAgent from 'supertest/lib/agent'; -import { BsearchService } from '@kbn/ftr-common-functional-services'; +import { SearchService } from '@kbn/ftr-common-functional-services'; import { FtrProviderContextWithSpaces } from '../../../../../ftr_provider_context_with_spaces'; export default function ({ getService }: FtrProviderContextWithSpaces) { @@ -20,11 +20,11 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { describe('Overview Network', () => { let supertest: TestAgent; - let bsearch: BsearchService; + let search: SearchService; describe('With filebeat', () => { before(async () => { supertest = await utils.createSuperTest(); - bsearch = await utils.createBsearch(); + search = await utils.createSearch(); await esArchiver.load('x-pack/test/functional/es_archives/filebeat/default'); }); after( @@ -47,7 +47,7 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { }; it('Make sure that we get OverviewNetwork data', async () => { - const { overviewNetwork } = await bsearch.send({ + const { overviewNetwork } = await search.send({ supertest, options: { defaultIndex: ['filebeat-*'], @@ -68,7 +68,7 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { describe('With packetbeat', () => { before(async () => { supertest = await utils.createSuperTest(); - bsearch = await utils.createBsearch(); + search = await utils.createSearch(); await esArchiver.load('x-pack/test/functional/es_archives/packetbeat/overview'); }); after( @@ -91,7 +91,7 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { }; it('Make sure that we get OverviewNetwork data', async () => { - const { overviewNetwork } = await bsearch.send({ + const { overviewNetwork } = await search.send({ supertest, options: { defaultIndex: ['packetbeat-*'], @@ -112,7 +112,7 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { describe('With auditbeat', () => { before(async () => { supertest = await utils.createSuperTest(); - bsearch = await utils.createBsearch(); + search = await utils.createSearch(); await esArchiver.load('x-pack/test/functional/es_archives/auditbeat/overview'); }); after( @@ -134,7 +134,7 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { }; it('Make sure that we get OverviewNetwork data', async () => { - const { overviewNetwork } = await bsearch.send({ + const { overviewNetwork } = await search.send({ supertest, options: { defaultIndex: ['auditbeat-*'], diff --git a/x-pack/test/security_solution_api_integration/test_suites/explore/users/trial_license_complete_tier/tests/authentications.ts b/x-pack/test/security_solution_api_integration/test_suites/explore/users/trial_license_complete_tier/tests/authentications.ts index 39dddc7a0c046..eaee29133ccb1 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/explore/users/trial_license_complete_tier/tests/authentications.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/explore/users/trial_license_complete_tier/tests/authentications.ts @@ -15,7 +15,7 @@ import { import type { UserAuthenticationsRequestOptions } from '@kbn/security-solution-plugin/common/api/search_strategy'; import TestAgent from 'supertest/lib/agent'; -import { BsearchService } from '@kbn/ftr-common-functional-services'; +import { SearchService } from '@kbn/ftr-common-functional-services'; import { FtrProviderContextWithSpaces } from '../../../../../ftr_provider_context_with_spaces'; const FROM = '2000-01-01T00:00:00.000Z'; @@ -33,11 +33,11 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { describe('authentications', () => { let supertest: TestAgent; - let bsearch: BsearchService; + let search: SearchService; before(async () => { supertest = await utils.createSuperTest(); - bsearch = await utils.createBsearch(); + search = await utils.createSearch(); await esArchiver.load('x-pack/test/functional/es_archives/auditbeat/hosts'); }); @@ -65,7 +65,7 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { filterQuery: '', }; - const authentications = await bsearch.send({ + const authentications = await search.send({ supertest, options: requestOptions, strategy: 'securitySolutionSearchStrategy', @@ -96,7 +96,7 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { filterQuery: '', }; - const authentications = await bsearch.send({ + const authentications = await search.send({ supertest, options: requestOptions, strategy: 'securitySolutionSearchStrategy', diff --git a/x-pack/test/security_solution_api_integration/test_suites/explore/users/trial_license_complete_tier/tests/users.ts b/x-pack/test/security_solution_api_integration/test_suites/explore/users/trial_license_complete_tier/tests/users.ts index 6765e6d2bb164..a1ba9a6f497a9 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/explore/users/trial_license_complete_tier/tests/users.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/explore/users/trial_license_complete_tier/tests/users.ts @@ -15,7 +15,7 @@ import { } from '@kbn/security-solution-plugin/common/search_strategy'; import TestAgent from 'supertest/lib/agent'; -import { BsearchService } from '@kbn/ftr-common-functional-services'; +import { SearchService } from '@kbn/ftr-common-functional-services'; import { FtrProviderContextWithSpaces } from '../../../../../ftr_provider_context_with_spaces'; @@ -29,11 +29,11 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { describe('Users', () => { let supertest: TestAgent; - let bsearch: BsearchService; + let search: SearchService; describe('With auditbeat', () => { before(async () => { supertest = await utils.createSuperTest(); - bsearch = await utils.createBsearch(); + search = await utils.createSearch(); await esArchiver.load('x-pack/test/functional/es_archives/auditbeat/users'); }); after( @@ -41,7 +41,7 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { ); it('Ensure data is returned from auditbeat', async () => { - const users = await bsearch.send({ + const users = await search.send({ supertest, options: { factoryQueryType: NetworkQueries.users, diff --git a/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/tests/events.ts b/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/tests/events.ts index 9db1a5dfceb22..9aa3fcc0de01d 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/tests/events.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/tests/events.ts @@ -14,7 +14,7 @@ import { TimelineEventsAllStrategyResponse, } from '@kbn/security-solution-plugin/common/search_strategy'; import TestAgent from 'supertest/lib/agent'; -import { BsearchService } from '@kbn/ftr-common-functional-services'; +import { SearchService } from '@kbn/ftr-common-functional-services'; import { FtrProviderContextWithSpaces } from '../../../../ftr_provider_context_with_spaces'; import { getFieldsToRequest, getFilterValue } from '../../../utils'; @@ -62,11 +62,11 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { describe('@skipInServerless Timeline', () => { let supertest: TestAgent; - let bsearch: BsearchService; + let search: SearchService; before(async () => { supertest = await utils.createSuperTest(); - bsearch = await utils.createBsearch(); + search = await utils.createSearch(); await esArchiver.load('x-pack/test/functional/es_archives/auditbeat/hosts'); }); after(async () => { @@ -74,7 +74,7 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { }); it('returns Timeline data', async () => { - const timeline = await bsearch.send({ + const timeline = await search.send({ supertest, options: { ...getPostBody(), @@ -89,7 +89,7 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { }); it('returns paginated Timeline query', async () => { - const timeline = await bsearch.send({ + const timeline = await search.send({ supertest, options: { ...getPostBody(), diff --git a/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/tests/timeline_details.ts b/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/tests/timeline_details.ts index 7d127ab7c0f96..5660a957c6cb3 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/tests/timeline_details.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/tests/timeline_details.ts @@ -14,7 +14,7 @@ import { } from '@kbn/security-solution-plugin/common/search_strategy'; import TestAgent from 'supertest/lib/agent'; -import { BsearchService } from '@kbn/ftr-common-functional-services'; +import { SearchService } from '@kbn/ftr-common-functional-services'; import { FtrProviderContextWithSpaces } from '../../../../ftr_provider_context_with_spaces'; import { timelineDetailsFilebeatExpectedResults as EXPECTED_DATA } from '../mocks/timeline_details'; @@ -36,10 +36,10 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { describe('@skipInServerless Timeline Details', () => { let supertest: TestAgent; - let bsearch: BsearchService; + let search: SearchService; before(async () => { supertest = await utils.createSuperTest(); - bsearch = await utils.createBsearch(); + search = await utils.createSearch(); await esArchiver.load('x-pack/test/functional/es_archives/filebeat/default'); }); after( @@ -47,7 +47,7 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { ); it('Make sure that we get Event Details data', async () => { - const { data: detailsData } = await bsearch.send({ + const { data: detailsData } = await search.send({ supertest, options: { factoryQueryType: TimelineEventsQueries.details, @@ -62,7 +62,7 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { it('Make sure that we get kpi data', async () => { const { destinationIpCount, hostCount, processCount, sourceIpCount, userCount } = - await bsearch.send({ + await search.send({ supertest, options: { factoryQueryType: TimelineEventsQueries.kpi, diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/create_new_rule.ts b/x-pack/test/security_solution_cypress/cypress/tasks/create_new_rule.ts index 501dd0461dd44..1a07ef356d516 100644 --- a/x-pack/test/security_solution_cypress/cypress/tasks/create_new_rule.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/create_new_rule.ts @@ -983,7 +983,7 @@ export const interceptEsqlQueryFieldsRequest = ( } }); } else { - cy.intercept('POST', '/internal/bsearch?*', (req) => { + cy.intercept('POST', '/internal/search?*', (req) => { if (req.body?.batch?.[0]?.request?.params?.query?.includes?.(esqlQuery)) { req.alias = alias; } diff --git a/x-pack/test_serverless/api_integration/test_suites/common/search_oss/bsearch.ts b/x-pack/test_serverless/api_integration/test_suites/common/search_oss/bsearch.ts deleted file mode 100644 index 93da25aed6000..0000000000000 --- a/x-pack/test_serverless/api_integration/test_suites/common/search_oss/bsearch.ts +++ /dev/null @@ -1,247 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import expect from '@kbn/expect'; -import request from 'superagent'; -import { inflateResponse } from '@kbn/bfetch-plugin/public/streaming'; -import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; -import { BFETCH_ROUTE_VERSION_LATEST } from '@kbn/bfetch-plugin/common'; -import { SupertestWithRoleScopeType } from '@kbn/test-suites-xpack/api_integration/deployment_agnostic/services'; -import type { FtrProviderContext } from '../../../ftr_provider_context'; -import { painlessErrReq } from './painless_err_req'; -import { verifyErrorResponse } from './verify_error'; - -function parseBfetchResponse(resp: request.Response, compressed: boolean = false) { - return resp.text - .trim() - .split('\n') - .map((item) => { - return JSON.parse(compressed ? inflateResponse(item) : item); - }); -} - -export default function ({ getService }: FtrProviderContext) { - const esArchiver = getService('esArchiver'); - const roleScopedSupertest = getService('roleScopedSupertest'); - let supertestAdminWithCookieCredentials: SupertestWithRoleScopeType; - - describe('bsearch', () => { - before(async () => { - supertestAdminWithCookieCredentials = await roleScopedSupertest.getSupertestWithRoleScope( - 'admin', - { - useCookieHeader: true, - withInternalHeaders: true, - withCustomHeaders: { - [ELASTIC_HTTP_VERSION_HEADER]: BFETCH_ROUTE_VERSION_LATEST, - }, - } - ); - }); - - describe('post', () => { - it('should return 200 a single response', async () => { - const resp = await supertestAdminWithCookieCredentials.post(`/internal/bsearch`).send({ - batch: [ - { - request: { - params: { - index: '.kibana', - body: { - query: { - match_all: {}, - }, - }, - }, - }, - options: { - strategy: 'es', - }, - }, - ], - }); - - const jsonBody = parseBfetchResponse(resp); - - expect(resp.status).to.be(200); - expect(jsonBody[0].id).to.be(0); - expect(jsonBody[0].result.isPartial).to.be(false); - expect(jsonBody[0].result.isRunning).to.be(false); - expect(jsonBody[0].result).to.have.property('rawResponse'); - }); - - it('should return 200 a single response from compressed', async () => { - const resp = await supertestAdminWithCookieCredentials - .post(`/internal/bsearch?compress=true`) - .send({ - batch: [ - { - request: { - params: { - index: '.kibana', - body: { - query: { - match_all: {}, - }, - }, - }, - }, - options: { - strategy: 'es', - }, - }, - ], - }); - - const jsonBody = parseBfetchResponse(resp, true); - - expect(resp.status).to.be(200); - expect(jsonBody[0].id).to.be(0); - expect(jsonBody[0].result.isPartial).to.be(false); - expect(jsonBody[0].result.isRunning).to.be(false); - expect(jsonBody[0].result).to.have.property('rawResponse'); - }); - - it('should return a batch of successful responses', async () => { - const resp = await supertestAdminWithCookieCredentials - .post(`/internal/bsearch`) - .set(ELASTIC_HTTP_VERSION_HEADER, BFETCH_ROUTE_VERSION_LATEST) - .send({ - batch: [ - { - request: { - params: { - index: '.kibana', - body: { - query: { - match_all: {}, - }, - }, - }, - }, - }, - { - request: { - params: { - index: '.kibana', - body: { - query: { - match_all: {}, - }, - }, - }, - }, - }, - ], - }); - - expect(resp.status).to.be(200); - const parsedResponse = parseBfetchResponse(resp); - expect(parsedResponse).to.have.length(2); - parsedResponse.forEach((responseJson) => { - expect(responseJson.result).to.have.property('isPartial'); - expect(responseJson.result).to.have.property('isRunning'); - expect(responseJson.result).to.have.property('rawResponse'); - }); - }); - - it('should return error for not found strategy', async () => { - const resp = await supertestAdminWithCookieCredentials - .post(`/internal/bsearch`) - .set(ELASTIC_HTTP_VERSION_HEADER, BFETCH_ROUTE_VERSION_LATEST) - .send({ - batch: [ - { - request: { - params: { - index: '.kibana', - body: { - query: { - match_all: {}, - }, - }, - }, - }, - options: { - strategy: 'wtf', - }, - }, - ], - }); - - expect(resp.status).to.be(200); - parseBfetchResponse(resp).forEach((responseJson, i) => { - expect(responseJson.id).to.be(i); - verifyErrorResponse(responseJson.error, 404, 'Search strategy wtf not found'); - }); - }); - - it('should return 400 when index type is provided in "es" strategy', async () => { - const resp = await supertestAdminWithCookieCredentials - .post(`/internal/bsearch`) - .set(ELASTIC_HTTP_VERSION_HEADER, BFETCH_ROUTE_VERSION_LATEST) - .send({ - batch: [ - { - request: { - index: '.kibana', - indexType: 'baad', - params: { - body: { - query: { - match_all: {}, - }, - }, - }, - }, - options: { - strategy: 'es', - }, - }, - ], - }); - - expect(resp.status).to.be(200); - parseBfetchResponse(resp).forEach((responseJson, i) => { - expect(responseJson.id).to.be(i); - verifyErrorResponse(responseJson.error, 400, 'Unsupported index pattern type baad'); - }); - }); - - describe('painless', () => { - before(async () => { - await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional'); - }); - - after(async () => { - await esArchiver.unload('test/functional/fixtures/es_archiver/logstash_functional'); - }); - it('should return 400 "search_phase_execution_exception" for Painless error in "es" strategy', async () => { - const resp = await supertestAdminWithCookieCredentials - .post(`/internal/bsearch`) - .set(ELASTIC_HTTP_VERSION_HEADER, BFETCH_ROUTE_VERSION_LATEST) - .send({ - batch: [ - { - request: painlessErrReq, - options: { - strategy: 'es', - }, - }, - ], - }); - - expect(resp.status).to.be(200); - parseBfetchResponse(resp).forEach((responseJson, i) => { - expect(responseJson.id).to.be(i); - verifyErrorResponse(responseJson.error, 400, 'search_phase_execution_exception', true); - }); - }); - }); - }); - }); -} diff --git a/x-pack/test_serverless/api_integration/test_suites/common/search_oss/index.ts b/x-pack/test_serverless/api_integration/test_suites/common/search_oss/index.ts index 79ff29fdf9f22..50299ed81a444 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/search_oss/index.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/search_oss/index.ts @@ -16,6 +16,5 @@ export default function ({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./search')); // TODO: Removed `sql_search` since // SQL is not supported in Serverless - loadTestFile(require.resolve('./bsearch')); }); } diff --git a/x-pack/test_serverless/shared/services/bsearch_secure.ts b/x-pack/test_serverless/shared/services/search_secure.ts similarity index 87% rename from x-pack/test_serverless/shared/services/bsearch_secure.ts rename to x-pack/test_serverless/shared/services/search_secure.ts index 03f8241c9e12a..7db246dc4ccdf 100644 --- a/x-pack/test_serverless/shared/services/bsearch_secure.ts +++ b/x-pack/test_serverless/shared/services/search_secure.ts @@ -13,7 +13,6 @@ import { GenericFtrService } from '@kbn/test'; import request from 'superagent'; import type { IEsSearchResponse } from '@kbn/search-types'; import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; -import { BFETCH_ROUTE_VERSION_LATEST } from '@kbn/bfetch-plugin/common'; import { SupertestWithoutAuthProviderType } from '@kbn/ftr-common-functional-services'; import { FtrProviderContext } from '../../functional/ftr_provider_context'; @@ -35,7 +34,7 @@ export interface SendOptions { internalOrigin: string; } -export class BsearchSecureService extends GenericFtrService { +export class SearchSecureService extends GenericFtrService { private readonly retry = this.ctx.getService('retry'); async send({ @@ -104,24 +103,12 @@ export class BsearchSecureService extends GenericFtrService const result = await this.retry.try(async () => { const resp = await supertestWithoutAuth - .post(`/internal/bsearch`) + .post(`/internal/search/${strategy}/${body.id}`) .set(apiKeyHeader) .set('kbn-xsrf', 'true') .set('x-elastic-internal-origin', 'Kibana') - .set(ELASTIC_HTTP_VERSION_HEADER, BFETCH_ROUTE_VERSION_LATEST) - .send({ - batch: [ - { - request: { - id: body.id, - ...options, - }, - options: { - strategy, - }, - }, - ], - }) + .set(ELASTIC_HTTP_VERSION_HEADER, '1') + .send() .expect(200); const [parsedResponse] = parseBfetchResponse(resp); expect(parsedResponse.result.isRunning).equal(false); From 625d6e44434d5dba39f6ffcf867816eb652faa6a Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Fri, 18 Oct 2024 22:08:51 +0000 Subject: [PATCH 02/13] [CI] Auto-commit changed files from 'node scripts/notice' --- packages/kbn-ftr-common-functional-services/tsconfig.json | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/kbn-ftr-common-functional-services/tsconfig.json b/packages/kbn-ftr-common-functional-services/tsconfig.json index 2cad85eb14fb2..e5239f467ba48 100644 --- a/packages/kbn-ftr-common-functional-services/tsconfig.json +++ b/packages/kbn-ftr-common-functional-services/tsconfig.json @@ -19,7 +19,6 @@ "@kbn/expect", "@kbn/search-types", "@kbn/core-http-common", - "@kbn/bfetch-plugin", "@kbn/data-plugin", "@kbn/dev-cli-runner", "@kbn/dev-cli-errors", From 096bd817a6fb6627b831bcafbeaa7c756044861d Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Fri, 18 Oct 2024 22:09:27 +0000 Subject: [PATCH 03/13] [CI] Auto-commit changed files from 'node scripts/lint_ts_projects --fix' --- x-pack/test_serverless/tsconfig.json | 1 - 1 file changed, 1 deletion(-) diff --git a/x-pack/test_serverless/tsconfig.json b/x-pack/test_serverless/tsconfig.json index d61c5c19a63db..05df4443fb6af 100644 --- a/x-pack/test_serverless/tsconfig.json +++ b/x-pack/test_serverless/tsconfig.json @@ -54,7 +54,6 @@ "@kbn/data-view-field-editor-plugin", "@kbn/data-plugin", "@kbn/dev-utils", - "@kbn/bfetch-plugin", "@kbn/es-archiver", "@kbn/rule-data-utils", "@kbn/rison", From 8ca20784d5603c025e5ea5b478611d9697bd1966 Mon Sep 17 00:00:00 2001 From: Lukas Olson Date: Mon, 21 Oct 2024 16:11:43 -0700 Subject: [PATCH 04/13] Remove bsearch endpoint --- .../search_interceptor/search_interceptor.ts | 70 ++++++------------- .../data/server/search/routes/bsearch.ts | 67 ------------------ .../data/server/search/search_service.ts | 7 -- 3 files changed, 20 insertions(+), 124 deletions(-) delete mode 100644 src/plugins/data/server/search/routes/bsearch.ts diff --git a/src/plugins/data/public/search/search_interceptor/search_interceptor.ts b/src/plugins/data/public/search/search_interceptor/search_interceptor.ts index 174dc35697ebc..c879fba1e03ae 100644 --- a/src/plugins/data/public/search/search_interceptor/search_interceptor.ts +++ b/src/plugins/data/public/search/search_interceptor/search_interceptor.ts @@ -49,10 +49,8 @@ import type { ToastsSetup, } from '@kbn/core/public'; -import { BatchedFunc, BfetchPublicSetup, DISABLE_BFETCH } from '@kbn/bfetch-plugin/public'; import { toMountPoint } from '@kbn/react-kibana-mount'; import { AbortError, KibanaServerError } from '@kbn/kibana-utils-plugin/public'; -import { BfetchRequestError } from '@kbn/bfetch-error'; import type { SanitizedConnectionRequestParams, IKibanaSearchRequest, @@ -79,7 +77,6 @@ import type { SearchServiceStartDependencies } from '../search_service'; import { createRequestHash } from './create_request_hash'; export interface SearchInterceptorDeps { - bfetch: BfetchPublicSetup; http: HttpSetup; executionContext: ExecutionContextSetup; uiSettings: IUiSettingsClient; @@ -96,7 +93,6 @@ const MAX_CACHE_SIZE_MB = 10; export class SearchInterceptor { private uiSettingsSubs: Subscription[] = []; private searchTimeout: number; - private bFetchDisabled: boolean; private readonly responseCache: SearchResponseCache = new SearchResponseCache( MAX_CACHE_ITEMS, MAX_CACHE_SIZE_MB @@ -113,10 +109,6 @@ export class SearchInterceptor { */ private application!: ApplicationStart; private docLinks!: DocLinksStart; - private batchedFetch!: BatchedFunc< - { request: IKibanaSearchRequest; options: ISearchOptionsSerializable }, - IKibanaSearchResponse - >; private inspector!: InspectorStart; /* @@ -143,19 +135,11 @@ export class SearchInterceptor { this.inspector = (depsStart as SearchServiceStartDependencies).inspector; }); - this.batchedFetch = deps.bfetch.batchedFunction({ - url: '/internal/bsearch', - }); - this.searchTimeout = deps.uiSettings.get(UI_SETTINGS.SEARCH_TIMEOUT); - this.bFetchDisabled = deps.uiSettings.get(DISABLE_BFETCH); this.uiSettingsSubs.push( deps.uiSettings.get$(UI_SETTINGS.SEARCH_TIMEOUT).subscribe((timeout: number) => { this.searchTimeout = timeout; - }), - deps.uiSettings.get$(DISABLE_BFETCH).subscribe((bFetchDisabled: boolean) => { - this.bFetchDisabled = bFetchDisabled; }) ); } @@ -215,8 +199,8 @@ export class SearchInterceptor { return err; } - if (e instanceof AbortError || e instanceof BfetchRequestError) { - // In the case an application initiated abort, throw the existing AbortError, same with BfetchRequestErrors + if (e instanceof AbortError) { + // In the case an application initiated abort, throw the existing AbortError return e; } @@ -442,38 +426,24 @@ export class SearchInterceptor { ): Promise { const { abortSignal } = options || {}; - if (this.bFetchDisabled) { - const { executionContext, strategy, ...searchOptions } = this.getSerializableOptions(options); - return this.deps.http - .post(`/internal/search/${strategy}${request.id ? `/${request.id}` : ''}`, { - version: '1', - signal: abortSignal, - context: executionContext, - body: JSON.stringify({ - ...request, - ...searchOptions, - }), - }) - .catch((e: IHttpFetchError) => { - if (e?.body) { - throw e.body; - } else { - throw e; - } - }) as Promise; - } else { - const { executionContext, ...rest } = options || {}; - return this.batchedFetch( - { - request, - options: this.getSerializableOptions({ - ...rest, - executionContext: this.deps.executionContext.withGlobalContext(executionContext), - }), - }, - abortSignal - ); - } + const { executionContext, strategy, ...searchOptions } = this.getSerializableOptions(options); + return this.deps.http + .post(`/internal/search/${strategy}${request.id ? `/${request.id}` : ''}`, { + version: '1', + signal: abortSignal, + context: executionContext, + body: JSON.stringify({ + ...request, + ...searchOptions, + }), + }) + .catch((e: IHttpFetchError) => { + if (e?.body) { + throw e.body; + } else { + throw e; + } + }) as Promise; } /** diff --git a/src/plugins/data/server/search/routes/bsearch.ts b/src/plugins/data/server/search/routes/bsearch.ts deleted file mode 100644 index 8e471bf0c4c6f..0000000000000 --- a/src/plugins/data/server/search/routes/bsearch.ts +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the "Elastic License - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { firstValueFrom } from 'rxjs'; -import { catchError } from 'rxjs'; -import { BfetchServerSetup } from '@kbn/bfetch-plugin/server'; -import type { ExecutionContextSetup } from '@kbn/core/server'; -import apm from 'elastic-apm-node'; -import type { - IKibanaSearchResponse, - IKibanaSearchRequest, - ISearchOptionsSerializable, -} from '@kbn/search-types'; -import { getRequestAbortedSignal } from '../..'; -import type { ISearchStart } from '../types'; - -export function registerBsearchRoute( - bfetch: BfetchServerSetup, - getScoped: ISearchStart['asScoped'], - executionContextService: ExecutionContextSetup -): void { - bfetch.addBatchProcessingRoute< - { request: IKibanaSearchRequest; options?: ISearchOptionsSerializable }, - IKibanaSearchResponse - >('/internal/bsearch', (request) => { - const search = getScoped(request); - const abortSignal = getRequestAbortedSignal(request.events.aborted$); - return { - /** - * @param requestOptions - * @throws `KibanaServerError` - */ - onBatchItem: async ({ request: requestData, options }) => { - const { executionContext, ...restOptions } = options || {}; - return executionContextService.withContext(executionContext, () => { - apm.addLabels(executionContextService.getAsLabels()); - - return firstValueFrom( - search.search(requestData, { ...restOptions, abortSignal }).pipe( - catchError((err) => { - // Re-throw as object, to get attributes passed to the client - // eslint-disable-next-line no-throw-literal - throw { - message: err.message, - statusCode: err.statusCode, - attributes: err.errBody - ? { - error: err.errBody.error, - rawResponse: err.errBody.response, - ...(err.requestParams ? { requestParams: err.requestParams } : {}), - } - : undefined, - }; - }) - ) - ); - }); - }, - }; - }); -} diff --git a/src/plugins/data/server/search/search_service.ts b/src/plugins/data/server/search/search_service.ts index 2ed3a7b170611..156336e47492d 100644 --- a/src/plugins/data/server/search/search_service.ts +++ b/src/plugins/data/server/search/search_service.ts @@ -93,7 +93,6 @@ import { import { aggShardDelay } from '../../common/search/aggs/buckets/shard_delay_fn'; import { ConfigSchema } from '../config'; import { SearchSessionService } from './session'; -import { registerBsearchRoute } from './routes/bsearch'; import { enhancedEsSearchStrategyProvider } from './strategies/ese_search'; import { eqlSearchStrategyProvider } from './strategies/eql_search'; import { NoSearchIdInSessionError } from './errors/no_search_id_in_session'; @@ -209,12 +208,6 @@ export class SearchService implements Plugin { sqlSearchStrategyProvider(this.initializerContext.config.get().search, this.logger) ); - registerBsearchRoute( - bfetch, - (request: KibanaRequest) => this.asScoped(request), - core.executionContext - ); - core.savedObjects.registerType(searchTelemetry); if (usageCollection) { const getIndexForType = (type: string) => From 8ab6a246332044667709d62840dc892ed46e900e Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Mon, 21 Oct 2024 23:23:45 +0000 Subject: [PATCH 05/13] [CI] Auto-commit changed files from 'node scripts/notice' --- src/plugins/data/tsconfig.json | 1 - 1 file changed, 1 deletion(-) diff --git a/src/plugins/data/tsconfig.json b/src/plugins/data/tsconfig.json index 1b2fc9ed85e93..27bf93b995381 100644 --- a/src/plugins/data/tsconfig.json +++ b/src/plugins/data/tsconfig.json @@ -47,7 +47,6 @@ "@kbn/search-errors", "@kbn/search-response-warnings", "@kbn/shared-ux-link-redirect-app", - "@kbn/bfetch-error", "@kbn/es-types", "@kbn/code-editor", "@kbn/core-test-helpers-model-versions", From bd7ba71a1e695aca295fb0091a757514e4ab4c7e Mon Sep 17 00:00:00 2001 From: Lukas Olson Date: Wed, 23 Oct 2024 13:39:03 -0700 Subject: [PATCH 06/13] Fix search interceptor tests --- .../search_interceptor.test.ts | 228 +++++++++--------- 1 file changed, 116 insertions(+), 112 deletions(-) diff --git a/src/plugins/data/public/search/search_interceptor/search_interceptor.test.ts b/src/plugins/data/public/search/search_interceptor/search_interceptor.test.ts index 9352b1cc4a230..371cbfbc176d2 100644 --- a/src/plugins/data/public/search/search_interceptor/search_interceptor.test.ts +++ b/src/plugins/data/public/search/search_interceptor/search_interceptor.test.ts @@ -8,15 +8,13 @@ */ import type { MockedKeys } from '@kbn/utility-types-jest'; -import { CoreSetup, CoreStart } from '@kbn/core/public'; +import { CoreSetup, CoreStart, HttpFetchOptions, HttpHandler } from '@kbn/core/public'; import { coreMock } from '@kbn/core/public/mocks'; -import { IEsSearchRequest } from '@kbn/search-types'; +import { IEsSearchRequest, IKibanaSearchRequest } from '@kbn/search-types'; import { SearchInterceptor } from './search_interceptor'; import { AbortError } from '@kbn/kibana-utils-plugin/public'; import { EsError, type IEsError } from '@kbn/search-errors'; import { ISessionService, SearchSessionState } from '..'; -import { bfetchPluginMock } from '@kbn/bfetch-plugin/public/mocks'; -import { BfetchPublicSetup } from '@kbn/bfetch-plugin/public'; import * as searchPhaseException from '../../../common/search/test_data/search_phase_execution_exception.json'; import * as resourceNotFoundException from '../../../common/search/test_data/resource_not_found_exception.json'; @@ -45,8 +43,6 @@ import { SearchSessionIncompleteWarning } from './search_session_incomplete_warn import { getMockSearchConfig } from '../../../config.mock'; let searchInterceptor: SearchInterceptor; -let bfetchSetup: jest.Mocked; -let fetchMock: jest.Mock; const flushPromises = () => new Promise((resolve) => jest.requireActual('timers').setImmediate(resolve)); @@ -63,10 +59,11 @@ const next = jest.fn(); const error = jest.fn(); const complete = jest.fn(); -function mockFetchImplementation(responses: any[]) { +function getResponseMock(responses: any[]) { let i = 0; - fetchMock.mockImplementation((r, abortSignal) => { - if (!r.request.id) i = 0; + return ((path: string, options?: HttpFetchOptions) => { + const request = JSON.parse(options?.body as string) as IKibanaSearchRequest; + if (!request.id) i = 0; const { time = 0, value = {}, isError = false } = responses[i++]; value.meta = { size: 10, @@ -76,14 +73,14 @@ function mockFetchImplementation(responses: any[]) { return (isError ? reject : resolve)(value); }, time); - if (abortSignal) { - if (abortSignal.aborted) reject(new AbortError()); - abortSignal.addEventListener('abort', () => { + if (options?.signal) { + if (options?.signal.aborted) reject(new AbortError()); + options?.signal.addEventListener('abort', () => { reject(new AbortError()); }); } }); - }); + }) as HttpHandler; } describe('SearchInterceptor', () => { @@ -102,7 +99,7 @@ describe('SearchInterceptor', () => { state$: sessionState$, }; - fetchMock = jest.fn(); + mockCoreSetup.http.post = jest.fn(); mockCoreSetup.uiSettings.get.mockImplementation((name: string) => { switch (name) { case UI_SETTINGS.SEARCH_TIMEOUT: @@ -117,17 +114,11 @@ describe('SearchInterceptor', () => { complete.mockClear(); jest.clearAllTimers(); - const bfetchMock = bfetchPluginMock.createSetupContract(); - bfetchMock.batchedFunction.mockReturnValue(fetchMock); - const inspectorServiceMock = { open: () => {}, } as unknown as InspectorStart; - bfetchSetup = bfetchPluginMock.createSetupContract(); - bfetchSetup.batchedFunction.mockReturnValue(fetchMock); searchInterceptor = new SearchInterceptor({ - bfetch: bfetchSetup, toasts: mockCoreSetup.notifications.toasts, startServices: new Promise((resolve) => { resolve([ @@ -185,7 +176,7 @@ describe('SearchInterceptor', () => { describe('search', () => { test('Observable should resolve if fetch is successful', async () => { const mockResponse: any = { rawResponse: {} }; - fetchMock.mockResolvedValueOnce(mockResponse); + mockCoreSetup.http.post.mockResolvedValueOnce(mockResponse); const mockRequest: IEsSearchRequest = { params: {}, }; @@ -207,7 +198,7 @@ describe('SearchInterceptor', () => { }, }, ]; - mockFetchImplementation(responses); + mockCoreSetup.http.post.mockImplementation(getResponseMock(responses)); const response = searchInterceptor.search({}); response.subscribe({ next, error, complete }); @@ -246,7 +237,7 @@ describe('SearchInterceptor', () => { }, ]; - mockFetchImplementation(responses); + mockCoreSetup.http.post.mockImplementation(getResponseMock(responses)); const response = searchInterceptor.search({}, { pollInterval: 0 }); response.subscribe({ next, error, complete }); @@ -278,7 +269,7 @@ describe('SearchInterceptor', () => { }, }, ]; - mockFetchImplementation(responses); + mockCoreSetup.http.post.mockImplementation(getResponseMock(responses)); const abortController = new AbortController(); abortController.abort(); @@ -314,7 +305,7 @@ describe('SearchInterceptor', () => { }, }, ]; - mockFetchImplementation(responses); + mockCoreSetup.http.post.mockImplementation(getResponseMock(responses)); const abortController = new AbortController(); setTimeout(() => abortController.abort(), 250); @@ -335,7 +326,7 @@ describe('SearchInterceptor', () => { expect(error).toHaveBeenCalled(); expect(error.mock.calls[0][0]).toBeInstanceOf(AbortError); - expect(fetchMock).toHaveBeenCalledTimes(2); + expect(mockCoreSetup.http.post).toHaveBeenCalledTimes(2); expect(mockCoreSetup.http.delete).toHaveBeenCalledTimes(1); }); @@ -351,19 +342,19 @@ describe('SearchInterceptor', () => { }, }, ]; - mockFetchImplementation(responses); + mockCoreSetup.http.post.mockImplementation(getResponseMock(responses)); const response = searchInterceptor.search({}, { pollInterval: 0 }); response.subscribe({ next, error }); await timeTravel(1000); - expect(fetchMock).toHaveBeenCalled(); + expect(mockCoreSetup.http.post).toHaveBeenCalled(); expect(mockCoreSetup.http.delete).not.toHaveBeenCalled(); }); test('should DELETE a running async search on async timeout after first response', async () => { - fetchMock.mockResolvedValue({ + mockCoreSetup.http.post.mockResolvedValue({ isPartial: true, isRunning: true, rawResponse: {}, @@ -377,7 +368,7 @@ describe('SearchInterceptor', () => { expect(next).toHaveBeenCalled(); expect(error).not.toHaveBeenCalled(); - expect(fetchMock).toHaveBeenCalled(); + expect(mockCoreSetup.http.post).toHaveBeenCalled(); expect(mockCoreSetup.http.delete).not.toHaveBeenCalled(); // Long enough to reach the timeout @@ -387,7 +378,7 @@ describe('SearchInterceptor', () => { }); test('should return the last response on async timeout', async () => { - fetchMock.mockResolvedValue({ + mockCoreSetup.http.post.mockResolvedValue({ isPartial: true, isRunning: true, rawResponse: { @@ -403,7 +394,7 @@ describe('SearchInterceptor', () => { expect(next).toHaveBeenCalled(); expect(error).not.toHaveBeenCalled(); - expect(fetchMock).toHaveBeenCalled(); + expect(mockCoreSetup.http.post).toHaveBeenCalled(); expect(mockCoreSetup.http.delete).not.toHaveBeenCalled(); // Long enough to reach the timeout but not long enough to reach the next response @@ -445,7 +436,7 @@ describe('SearchInterceptor', () => { isError: true, }, ]; - mockFetchImplementation(responses); + mockCoreSetup.http.post.mockImplementation(getResponseMock(responses)); const response = searchInterceptor.search({}, { pollInterval: 0 }); response.subscribe({ next, error }); @@ -454,7 +445,7 @@ describe('SearchInterceptor', () => { expect(next).toHaveBeenCalled(); expect(error).not.toHaveBeenCalled(); - expect(fetchMock).toHaveBeenCalled(); + expect(mockCoreSetup.http.post).toHaveBeenCalled(); expect(mockCoreSetup.http.delete).not.toHaveBeenCalled(); // Long enough to reach the timeout but not long enough to reach the next response @@ -463,7 +454,7 @@ describe('SearchInterceptor', () => { expect(error).toHaveBeenCalled(); expect(error.mock.calls[0][0]).toBeInstanceOf(Error); expect((error.mock.calls[0][0] as Error).message).toBe('oh no'); - expect(fetchMock).toHaveBeenCalledTimes(2); + expect(mockCoreSetup.http.post).toHaveBeenCalledTimes(2); expect(mockCoreSetup.http.delete).toHaveBeenCalledTimes(1); }); @@ -489,7 +480,7 @@ describe('SearchInterceptor', () => { isError: true, }, ]; - mockFetchImplementation(responses); + mockCoreSetup.http.post.mockImplementation(getResponseMock(responses)); const response = searchInterceptor.search({}, { pollInterval: 0 }); response.subscribe({ next, error }); @@ -498,7 +489,7 @@ describe('SearchInterceptor', () => { expect(next).toHaveBeenCalled(); expect(error).not.toHaveBeenCalled(); - expect(fetchMock).toHaveBeenCalled(); + expect(mockCoreSetup.http.post).toHaveBeenCalled(); expect(mockCoreSetup.http.delete).not.toHaveBeenCalled(); // Long enough to reach the timeout but not long enough to reach the next response @@ -507,7 +498,7 @@ describe('SearchInterceptor', () => { expect(error).toHaveBeenCalled(); expect(error.mock.calls[0][0]).toBeInstanceOf(Error); expect((error.mock.calls[0][0] as Error).message).toBe('oh no'); - expect(fetchMock).toHaveBeenCalledTimes(2); + expect(mockCoreSetup.http.post).toHaveBeenCalledTimes(2); expect(mockCoreSetup.http.delete).toHaveBeenCalledTimes(1); }); @@ -534,7 +525,7 @@ describe('SearchInterceptor', () => { }, }, ]; - mockFetchImplementation(responses); + mockCoreSetup.http.post.mockImplementation(getResponseMock(responses)); const abortController = new AbortController(); setTimeout(() => abortController.abort(), 250); @@ -557,7 +548,7 @@ describe('SearchInterceptor', () => { expect(error).toHaveBeenCalled(); expect(error.mock.calls[0][0]).toBeInstanceOf(AbortError); - expect(fetchMock).toHaveBeenCalledTimes(2); + expect(mockCoreSetup.http.post).toHaveBeenCalledTimes(2); expect(mockCoreSetup.http.delete).not.toHaveBeenCalled(); }); @@ -581,7 +572,7 @@ describe('SearchInterceptor', () => { ); sessionServiceMock.isRestore.mockReturnValue(!!opts?.isRestore); sessionServiceMock.getSessionId.mockImplementation(() => opts?.sessionId); - fetchMock.mockResolvedValue({ result: 200 }); + mockCoreSetup.http.post.mockResolvedValue({ result: 200 }); }; const mockRequest: IEsSearchRequest = { @@ -591,7 +582,7 @@ describe('SearchInterceptor', () => { afterEach(() => { const sessionServiceMock = sessionService as jest.Mocked; sessionServiceMock.getSearchOptions.mockReset(); - fetchMock.mockReset(); + mockCoreSetup.http.post.mockReset(); }); test('gets session search options from session service', async () => { @@ -606,15 +597,18 @@ describe('SearchInterceptor', () => { .search(mockRequest, { sessionId }) .toPromise() .catch(() => {}); - expect(fetchMock.mock.calls[0][0]).toEqual( + const [path, options] = mockCoreSetup.http.post.mock.calls[0] as unknown as [ + path: string, + options: HttpFetchOptions + ]; + const body = JSON.parse(options?.body as string); + expect(path).toEqual('/internal/search/ese'); + expect(body).toEqual( expect.objectContaining({ - options: { - sessionId, - isStored: true, - isRestore: true, - isSearchStored: false, - strategy: 'ese', - }, + sessionId, + isStored: true, + isRestore: true, + isSearchStored: false, }) ); @@ -631,7 +625,7 @@ describe('SearchInterceptor', () => { .search(mockRequest, { sessionId }) .toPromise() .catch(() => {}); - expect(fetchMock.mock.calls[0][0]).toEqual( + expect(mockCoreSetup.http.post.mock.calls[0][0]).toEqual( expect.not.objectContaining({ options: { sessionId }, }) @@ -663,7 +657,7 @@ describe('SearchInterceptor', () => { }, }, ]; - mockFetchImplementation(responses); + mockCoreSetup.http.post.mockImplementation(getResponseMock(responses)); const response = searchInterceptor.search( {}, @@ -698,7 +692,7 @@ describe('SearchInterceptor', () => { }, }, ]; - mockFetchImplementation(responses); + mockCoreSetup.http.post.mockImplementation(getResponseMock(responses)); const response = searchInterceptor.search( {}, @@ -734,7 +728,7 @@ describe('SearchInterceptor', () => { }, }, ]; - mockFetchImplementation(responses); + mockCoreSetup.http.post.mockImplementation(getResponseMock(responses)); searchInterceptor .search( @@ -787,7 +781,7 @@ describe('SearchInterceptor', () => { }, ]; - mockFetchImplementation(responses); + mockCoreSetup.http.post.mockImplementation(getResponseMock(responses)); }); test('should track searches', async () => { @@ -930,17 +924,17 @@ describe('SearchInterceptor', () => { }); test('should be disabled if there is no session', async () => { - mockFetchImplementation(basicCompleteResponse); + mockCoreSetup.http.post.mockImplementation(getResponseMock(basicCompleteResponse)); searchInterceptor.search(basicReq, {}).subscribe({ next, error, complete }); - expect(fetchMock).toBeCalledTimes(1); + expect(mockCoreSetup.http.post).toBeCalledTimes(1); searchInterceptor.search(basicReq, {}).subscribe({ next, error, complete }); - expect(fetchMock).toBeCalledTimes(2); + expect(mockCoreSetup.http.post).toBeCalledTimes(2); }); test('should fetch different requests in a single session', async () => { - mockFetchImplementation(basicCompleteResponse); + mockCoreSetup.http.post.mockImplementation(getResponseMock(basicCompleteResponse)); const req2 = { params: { @@ -948,31 +942,41 @@ describe('SearchInterceptor', () => { }, }; + next.mockImplementation(() => { + console.log('next'); + }); + error.mockImplementation((...args) => { + console.log('error'); + }); + complete.mockImplementation((...args) => { + console.log('complete'); + }); + searchInterceptor.search(basicReq, { sessionId }).subscribe({ next, error, complete }); await timeTravel(10); - expect(fetchMock).toBeCalledTimes(1); + expect(mockCoreSetup.http.post).toBeCalledTimes(1); searchInterceptor.search(req2, { sessionId }).subscribe({ next, error, complete }); await timeTravel(10); - expect(fetchMock).toBeCalledTimes(2); + expect(mockCoreSetup.http.post).toBeCalledTimes(2); }); test('should fetch the same request for two different sessions', async () => { - mockFetchImplementation(basicCompleteResponse); + mockCoreSetup.http.post.mockImplementation(getResponseMock(basicCompleteResponse)); searchInterceptor.search(basicReq, { sessionId }).subscribe({ next, error, complete }); await timeTravel(10); - expect(fetchMock).toBeCalledTimes(1); + expect(mockCoreSetup.http.post).toBeCalledTimes(1); searchInterceptor .search(basicReq, { sessionId: 'anotherSession' }) .subscribe({ next, error, complete }); await timeTravel(10); - expect(fetchMock).toBeCalledTimes(2); + expect(mockCoreSetup.http.post).toBeCalledTimes(2); }); test('should not track searches that come from cache', async () => { - mockFetchImplementation(partialCompleteResponse); + mockCoreSetup.http.post.mockImplementation(getResponseMock(partialCompleteResponse)); sessionService.isCurrentSession.mockImplementation( (_sessionId) => _sessionId === sessionId ); @@ -1000,12 +1004,12 @@ describe('SearchInterceptor', () => { response2.subscribe({ next, error, complete }); await timeTravel(10); - expect(fetchMock).toBeCalledTimes(1); + expect(mockCoreSetup.http.post).toBeCalledTimes(1); expect(sessionService.trackSearch).toBeCalledTimes(1); expect(completeSearch).not.toBeCalled(); await timeTravel(300); // Should be called only 2 times (once per partial response) - expect(fetchMock).toBeCalledTimes(2); + expect(mockCoreSetup.http.post).toBeCalledTimes(2); expect(sessionService.trackSearch).toBeCalledTimes(1); expect(completeSearch).toBeCalledTimes(1); @@ -1027,15 +1031,15 @@ describe('SearchInterceptor', () => { }, ]; - mockFetchImplementation(responses); + mockCoreSetup.http.post.mockImplementation(getResponseMock(responses)); searchInterceptor.search(basicReq, { sessionId }).subscribe({ next, error, complete }); await timeTravel(10); - expect(fetchMock).toBeCalledTimes(1); + expect(mockCoreSetup.http.post).toBeCalledTimes(1); searchInterceptor.search(basicReq, { sessionId }).subscribe({ next, error, complete }); await timeTravel(10); - expect(fetchMock).toBeCalledTimes(1); + expect(mockCoreSetup.http.post).toBeCalledTimes(1); }); test('should not cache error responses', async () => { @@ -1050,19 +1054,19 @@ describe('SearchInterceptor', () => { }, ]; - mockFetchImplementation(responses); + mockCoreSetup.http.post.mockImplementation(getResponseMock(responses)); searchInterceptor.search(basicReq, { sessionId }).subscribe({ next, error, complete }); await timeTravel(10); - expect(fetchMock).toBeCalledTimes(1); + expect(mockCoreSetup.http.post).toBeCalledTimes(1); searchInterceptor.search(basicReq, { sessionId }).subscribe({ next, error, complete }); await timeTravel(10); - expect(fetchMock).toBeCalledTimes(2); + expect(mockCoreSetup.http.post).toBeCalledTimes(2); }); test('should ignore anything outside params when hashing', async () => { - mockFetchImplementation(basicCompleteResponse); + mockCoreSetup.http.post.mockImplementation(getResponseMock(basicCompleteResponse)); const req = { something: 123, @@ -1080,11 +1084,11 @@ describe('SearchInterceptor', () => { searchInterceptor.search(req, { sessionId }).subscribe({ next, error, complete }); await timeTravel(10); - expect(fetchMock).toBeCalledTimes(1); + expect(mockCoreSetup.http.post).toBeCalledTimes(1); searchInterceptor.search(req2, { sessionId }).subscribe({ next, error, complete }); await timeTravel(10); - expect(fetchMock).toBeCalledTimes(1); + expect(mockCoreSetup.http.post).toBeCalledTimes(1); }); test('should deliver error to all replays', async () => { @@ -1095,19 +1099,19 @@ describe('SearchInterceptor', () => { }, ]; - mockFetchImplementation(responses); + mockCoreSetup.http.post.mockImplementation(getResponseMock(responses)); searchInterceptor.search(basicReq, { sessionId }).subscribe({ next, error, complete }); searchInterceptor.search(basicReq, { sessionId }).subscribe({ next, error, complete }); await timeTravel(10); - expect(fetchMock).toBeCalledTimes(1); + expect(mockCoreSetup.http.post).toBeCalledTimes(1); expect(error).toBeCalledTimes(2); expect(error.mock.calls[0][0].message).toEqual('Aborted'); expect(error.mock.calls[1][0].message).toEqual('Aborted'); }); test('should ignore preference when hashing', async () => { - mockFetchImplementation(basicCompleteResponse); + mockCoreSetup.http.post.mockImplementation(getResponseMock(basicCompleteResponse)); const req = { params: { @@ -1125,27 +1129,27 @@ describe('SearchInterceptor', () => { searchInterceptor.search(req, { sessionId }).subscribe({ next, error, complete }); await timeTravel(10); - expect(fetchMock).toBeCalledTimes(1); + expect(mockCoreSetup.http.post).toBeCalledTimes(1); searchInterceptor.search(req2, { sessionId }).subscribe({ next, error, complete }); await timeTravel(10); - expect(fetchMock).toBeCalledTimes(1); + expect(mockCoreSetup.http.post).toBeCalledTimes(1); }); test('should return from cache for identical requests in the same session', async () => { - mockFetchImplementation(basicCompleteResponse); + mockCoreSetup.http.post.mockImplementation(getResponseMock(basicCompleteResponse)); searchInterceptor.search(basicReq, { sessionId }).subscribe({ next, error, complete }); await timeTravel(10); - expect(fetchMock).toBeCalledTimes(1); + expect(mockCoreSetup.http.post).toBeCalledTimes(1); searchInterceptor.search(basicReq, { sessionId }).subscribe({ next, error, complete }); await timeTravel(10); - expect(fetchMock).toBeCalledTimes(1); + expect(mockCoreSetup.http.post).toBeCalledTimes(1); }); test('aborting a search that didnt get any response should retrigger search', async () => { - mockFetchImplementation(basicCompleteResponse); + mockCoreSetup.http.post.mockImplementation(getResponseMock(basicCompleteResponse)); const abortController = new AbortController(); @@ -1159,7 +1163,7 @@ describe('SearchInterceptor', () => { // Time travel to make sure nothing appens await timeTravel(10); - expect(fetchMock).toBeCalledTimes(0); + expect(mockCoreSetup.http.post).toBeCalledTimes(0); expect(next).toBeCalledTimes(0); expect(error).toBeCalledTimes(1); expect(complete).toBeCalledTimes(0); @@ -1175,14 +1179,14 @@ describe('SearchInterceptor', () => { // Should search again await timeTravel(10); - expect(fetchMock).toBeCalledTimes(1); + expect(mockCoreSetup.http.post).toBeCalledTimes(1); expect(next2).toBeCalledTimes(1); expect(error2).toBeCalledTimes(0); expect(complete2).toBeCalledTimes(1); }); test('aborting a running first search shouldnt clear cache', async () => { - mockFetchImplementation(partialCompleteResponse); + mockCoreSetup.http.post.mockImplementation(getResponseMock(partialCompleteResponse)); sessionService.isCurrentSession.mockImplementation( (_sessionId) => _sessionId === sessionId ); @@ -1214,7 +1218,7 @@ describe('SearchInterceptor', () => { response.subscribe({ next, error, complete }); await timeTravel(10); - expect(fetchMock).toBeCalledTimes(1); + expect(mockCoreSetup.http.post).toBeCalledTimes(1); expect(next).toBeCalledTimes(1); expect(error).toBeCalledTimes(0); expect(complete).toBeCalledTimes(0); @@ -1245,11 +1249,11 @@ describe('SearchInterceptor', () => { expect(complete2).toBeCalledTimes(1); // Should be called only 2 times (once per partial response) - expect(fetchMock).toBeCalledTimes(2); + expect(mockCoreSetup.http.post).toBeCalledTimes(2); }); test('aborting a running second search shouldnt clear cache', async () => { - mockFetchImplementation(partialCompleteResponse); + mockCoreSetup.http.post.mockImplementation(getResponseMock(partialCompleteResponse)); sessionService.isCurrentSession.mockImplementation( (_sessionId) => _sessionId === sessionId ); @@ -1277,7 +1281,7 @@ describe('SearchInterceptor', () => { response.subscribe({ next, error, complete }); await timeTravel(10); - expect(fetchMock).toBeCalledTimes(1); + expect(mockCoreSetup.http.post).toBeCalledTimes(1); expect(next).toBeCalledTimes(1); expect(error).toBeCalledTimes(0); expect(complete).toBeCalledTimes(0); @@ -1310,11 +1314,11 @@ describe('SearchInterceptor', () => { expect(complete2).toBeCalledTimes(0); // Should be called only 2 times (once per partial response) - expect(fetchMock).toBeCalledTimes(2); + expect(mockCoreSetup.http.post).toBeCalledTimes(2); }); test('aborting both requests should cancel underlaying search only once', async () => { - mockFetchImplementation(partialCompleteResponse); + mockCoreSetup.http.post.mockImplementation(getResponseMock(partialCompleteResponse)); sessionService.isCurrentSession.mockImplementation( (_sessionId) => _sessionId === sessionId ); @@ -1351,7 +1355,7 @@ describe('SearchInterceptor', () => { }); test('aborting both searches should stop searching and clear cache', async () => { - mockFetchImplementation(partialCompleteResponse); + mockCoreSetup.http.post.mockImplementation(getResponseMock(partialCompleteResponse)); sessionService.isCurrentSession.mockImplementation( (_sessionId) => _sessionId === sessionId ); @@ -1382,7 +1386,7 @@ describe('SearchInterceptor', () => { }); response.subscribe({ next, error, complete }); await timeTravel(10); - expect(fetchMock).toBeCalledTimes(1); + expect(mockCoreSetup.http.post).toBeCalledTimes(1); const response2 = searchInterceptor.search(req, { pollInterval: 1, @@ -1391,7 +1395,7 @@ describe('SearchInterceptor', () => { }); response2.subscribe({ next, error, complete }); await timeTravel(0); - expect(fetchMock).toBeCalledTimes(1); + expect(mockCoreSetup.http.post).toBeCalledTimes(1); abortController.abort(); @@ -1404,11 +1408,11 @@ describe('SearchInterceptor', () => { expect(error.mock.calls[1][0]).toBeInstanceOf(AbortError); // Should be called only 1 times (one partial response) - expect(fetchMock).toBeCalledTimes(1); + expect(mockCoreSetup.http.post).toBeCalledTimes(1); // Clear mock and research - fetchMock.mockReset(); - mockFetchImplementation(partialCompleteResponse); + mockCoreSetup.http.post.mockReset(); + mockCoreSetup.http.post.mockImplementation(getResponseMock(partialCompleteResponse)); // Run the search again to see that we don't hit the cache const response3 = searchInterceptor.search(req, { pollInterval: 1, sessionId }); response3.subscribe({ next, error, complete }); @@ -1418,12 +1422,12 @@ describe('SearchInterceptor', () => { await timeTravel(300); // Should be called 2 times (two partial response) - expect(fetchMock).toBeCalledTimes(2); + expect(mockCoreSetup.http.post).toBeCalledTimes(2); expect(complete).toBeCalledTimes(1); }); test("aborting a completed search shouldn't effect cache", async () => { - mockFetchImplementation(basicCompleteResponse); + mockCoreSetup.http.post.mockImplementation(getResponseMock(basicCompleteResponse)); const abortController = new AbortController(); @@ -1434,7 +1438,7 @@ describe('SearchInterceptor', () => { // Get a final response await timeTravel(10); - expect(fetchMock).toBeCalledTimes(1); + expect(mockCoreSetup.http.post).toBeCalledTimes(1); // Abort the search request abortController.abort(); @@ -1443,14 +1447,14 @@ describe('SearchInterceptor', () => { searchInterceptor.search(basicReq, { sessionId }).subscribe({ next, error, complete }); // Get the response from cache - expect(fetchMock).toBeCalledTimes(1); + expect(mockCoreSetup.http.post).toBeCalledTimes(1); }); }); describe('Should throw typed errors', () => { test('Observable should fail if fetch has an internal error', async () => { const mockResponse: any = new Error('Internal Error'); - fetchMock.mockRejectedValue(mockResponse); + mockCoreSetup.http.post.mockRejectedValue(mockResponse); const mockRequest: IEsSearchRequest = { params: {}, }; @@ -1464,7 +1468,7 @@ describe('SearchInterceptor', () => { statusCode: 500, message: 'Request timed out', }; - fetchMock.mockRejectedValueOnce(mockResponse); + mockCoreSetup.http.post.mockRejectedValueOnce(mockResponse); const mockRequest: IEsSearchRequest = { params: {}, }; @@ -1478,7 +1482,7 @@ describe('SearchInterceptor', () => { statusCode: 500, message: 'Request timed out', }; - fetchMock.mockRejectedValue(mockResponse); + mockCoreSetup.http.post.mockRejectedValue(mockResponse); const mockRequest: IEsSearchRequest = { params: {}, }; @@ -1497,7 +1501,7 @@ describe('SearchInterceptor', () => { statusCode: 500, message: 'Request timed out', }; - fetchMock.mockRejectedValue(mockResponse); + mockCoreSetup.http.post.mockRejectedValue(mockResponse); const mockRequest: IEsSearchRequest = { params: {}, }; @@ -1516,7 +1520,7 @@ describe('SearchInterceptor', () => { statusCode: 500, message: 'Request timed out', }; - fetchMock.mockRejectedValue(mockResponse); + mockCoreSetup.http.post.mockRejectedValue(mockResponse); const mockRequest: IEsSearchRequest = { params: {}, }; @@ -1538,7 +1542,7 @@ describe('SearchInterceptor', () => { error: resourceNotFoundException.error, }, }; - fetchMock.mockRejectedValueOnce(mockResponse); + mockCoreSetup.http.post.mockRejectedValueOnce(mockResponse); const mockRequest: IEsSearchRequest = { params: {}, }; @@ -1548,7 +1552,7 @@ describe('SearchInterceptor', () => { test('Observable should fail if user aborts (test merged signal)', async () => { const abortController = new AbortController(); - fetchMock.mockImplementationOnce((options: any) => { + mockCoreSetup.http.post.mockImplementationOnce((options: any) => { return new Promise((resolve, reject) => { options.signal.addEventListener('abort', () => { reject(new AbortError()); @@ -1586,7 +1590,7 @@ describe('SearchInterceptor', () => { error.mockImplementation((e) => { expect(e).toBeInstanceOf(AbortError); - expect(fetchMock).not.toBeCalled(); + expect(mockCoreSetup.http.post).not.toBeCalled(); }); response.subscribe({ error }); From 43f1bb69b6aaed108539ed68f8849ccf6997bfe5 Mon Sep 17 00:00:00 2001 From: Lukas Olson Date: Wed, 23 Oct 2024 13:40:23 -0700 Subject: [PATCH 07/13] Remove bsearch API integration tests --- test/api_integration/apis/search/bsearch.ts | 577 -------------------- test/api_integration/apis/search/index.ts | 1 - 2 files changed, 578 deletions(-) delete mode 100644 test/api_integration/apis/search/bsearch.ts diff --git a/test/api_integration/apis/search/bsearch.ts b/test/api_integration/apis/search/bsearch.ts deleted file mode 100644 index 2c4bcead1d475..0000000000000 --- a/test/api_integration/apis/search/bsearch.ts +++ /dev/null @@ -1,577 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the "Elastic License - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import expect from '@kbn/expect'; -import request from 'superagent'; -import { inflateResponse } from '@kbn/bfetch-plugin/public/streaming'; -import { - ELASTIC_HTTP_VERSION_HEADER, - X_ELASTIC_INTERNAL_ORIGIN_REQUEST, -} from '@kbn/core-http-common'; -import { BFETCH_ROUTE_VERSION_LATEST } from '@kbn/bfetch-plugin/common'; -import { FtrProviderContext } from '../../ftr_provider_context'; -import { painlessErrReq } from './painless_err_req'; -import { verifyErrorResponse } from './verify_error'; - -function parseBfetchResponse(resp: request.Response, compressed: boolean = false) { - return resp.text - .trim() - .split('\n') - .map((item) => { - return JSON.parse(compressed ? inflateResponse(item) : item); - }); -} - -export default function ({ getService }: FtrProviderContext) { - const supertest = getService('supertest'); - const esArchiver = getService('esArchiver'); - - describe('bsearch', () => { - describe('post', () => { - it('should return 200 a single response', async () => { - const resp = await supertest - .post(`/internal/bsearch`) - .set(ELASTIC_HTTP_VERSION_HEADER, BFETCH_ROUTE_VERSION_LATEST) - .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') - .send({ - batch: [ - { - request: { - params: { - index: '.kibana', - body: { - query: { - match_all: {}, - }, - }, - }, - }, - options: { - strategy: 'es', - }, - }, - ], - }); - - const jsonBody = parseBfetchResponse(resp); - - expect(resp.status).to.be(200); - expect(jsonBody[0].id).to.be(0); - expect(jsonBody[0].result.isPartial).to.be(false); - expect(jsonBody[0].result.isRunning).to.be(false); - expect(jsonBody[0].result).to.have.property('rawResponse'); - }); - - it('should return 200 a single response from compressed', async () => { - const resp = await supertest - .post(`/internal/bsearch?compress=true`) - .set(ELASTIC_HTTP_VERSION_HEADER, BFETCH_ROUTE_VERSION_LATEST) - .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') - .send({ - batch: [ - { - request: { - params: { - index: '.kibana', - body: { - query: { - match_all: {}, - }, - }, - }, - }, - options: { - strategy: 'es', - }, - }, - ], - }); - - const jsonBody = parseBfetchResponse(resp, true); - - expect(resp.status).to.be(200); - expect(jsonBody[0].id).to.be(0); - expect(jsonBody[0].result.isPartial).to.be(false); - expect(jsonBody[0].result.isRunning).to.be(false); - expect(jsonBody[0].result).to.have.property('rawResponse'); - }); - - it('should return a batch of successful responses', async () => { - const resp = await supertest - .post(`/internal/bsearch`) - .set(ELASTIC_HTTP_VERSION_HEADER, BFETCH_ROUTE_VERSION_LATEST) - .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') - .send({ - batch: [ - { - request: { - params: { - index: '.kibana', - body: { - query: { - match_all: {}, - }, - }, - }, - }, - }, - { - request: { - params: { - index: '.kibana', - body: { - query: { - match_all: {}, - }, - }, - }, - }, - }, - ], - }); - - expect(resp.status).to.be(200); - const parsedResponse = parseBfetchResponse(resp); - expect(parsedResponse).to.have.length(2); - parsedResponse.forEach((responseJson) => { - expect(responseJson.result).to.have.property('isPartial'); - expect(responseJson.result).to.have.property('isRunning'); - expect(responseJson.result).to.have.property('rawResponse'); - }); - }); - - it('should return error for not found strategy', async () => { - const resp = await supertest - .post(`/internal/bsearch`) - .set(ELASTIC_HTTP_VERSION_HEADER, BFETCH_ROUTE_VERSION_LATEST) - .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') - .send({ - batch: [ - { - request: { - params: { - index: '.kibana', - body: { - query: { - match_all: {}, - }, - }, - }, - }, - options: { - strategy: 'wtf', - }, - }, - ], - }); - - expect(resp.status).to.be(200); - parseBfetchResponse(resp).forEach((responseJson, i) => { - expect(responseJson.id).to.be(i); - verifyErrorResponse(responseJson.error, 404, 'Search strategy wtf not found'); - }); - }); - - it('should return 400 when index type is provided in "es" strategy', async () => { - const resp = await supertest - .post(`/internal/bsearch`) - .set(ELASTIC_HTTP_VERSION_HEADER, BFETCH_ROUTE_VERSION_LATEST) - .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') - .send({ - batch: [ - { - request: { - index: '.kibana', - indexType: 'baad', - params: { - body: { - query: { - match_all: {}, - }, - }, - }, - }, - options: { - strategy: 'es', - }, - }, - ], - }); - - expect(resp.status).to.be(200); - parseBfetchResponse(resp).forEach((responseJson, i) => { - expect(responseJson.id).to.be(i); - verifyErrorResponse(responseJson.error, 400, 'Unsupported index pattern type baad'); - }); - }); - - describe('painless', () => { - before(async () => { - await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional'); - }); - - after(async () => { - await esArchiver.unload('test/functional/fixtures/es_archiver/logstash_functional'); - }); - it('should return 400 "search_phase_execution_exception" for Painless error in "es" strategy', async () => { - const resp = await supertest - .post(`/internal/bsearch`) - .set(ELASTIC_HTTP_VERSION_HEADER, BFETCH_ROUTE_VERSION_LATEST) - .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') - .send({ - batch: [ - { - request: painlessErrReq, - options: { - strategy: 'es', - }, - }, - ], - }); - - expect(resp.status).to.be(200); - parseBfetchResponse(resp).forEach((responseJson, i) => { - expect(responseJson.id).to.be(i); - verifyErrorResponse(responseJson.error, 400, 'search_phase_execution_exception', true); - }); - }); - }); - - describe('request meta', () => { - describe('es', () => { - it(`should return request meta`, async () => { - const resp = await supertest - .post(`/internal/bsearch`) - .set(ELASTIC_HTTP_VERSION_HEADER, BFETCH_ROUTE_VERSION_LATEST) - .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') - .send({ - batch: [ - { - request: { - params: { - index: '.kibana', - body: { - query: { - match_all: {}, - }, - }, - }, - }, - options: { - strategy: 'es', - }, - }, - ], - }); - - const jsonBody = parseBfetchResponse(resp); - - expect(resp.status).to.be(200); - expect(jsonBody[0].result.requestParams).to.eql({ - method: 'POST', - path: '/.kibana/_search', - querystring: 'ignore_unavailable=true', - }); - }); - - it(`should return request meta when request fails`, async () => { - const resp = await supertest - .post(`/internal/bsearch`) - .set(ELASTIC_HTTP_VERSION_HEADER, BFETCH_ROUTE_VERSION_LATEST) - .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') - .send({ - batch: [ - { - request: { - params: { - index: '.kibana', - body: { - query: { - bool: { - filter: [ - { - error_query: { - indices: [ - { - error_type: 'exception', - message: 'simulated failure', - name: '.kibana', - }, - ], - }, - }, - ], - }, - }, - }, - }, - }, - options: { - strategy: 'es', - }, - }, - ], - }); - - const jsonBody = parseBfetchResponse(resp); - - expect(resp.status).to.be(200); - expect(jsonBody[0].error.attributes.requestParams).to.eql({ - method: 'POST', - path: '/.kibana/_search', - querystring: 'ignore_unavailable=true', - }); - }); - }); - - describe('ese', () => { - it(`should return request meta`, async () => { - const resp = await supertest - .post(`/internal/bsearch`) - .set(ELASTIC_HTTP_VERSION_HEADER, BFETCH_ROUTE_VERSION_LATEST) - .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') - .send({ - batch: [ - { - request: { - params: { - index: '.kibana', - body: { - query: { - match_all: {}, - }, - }, - }, - }, - options: { - strategy: 'ese', - }, - }, - ], - }); - - const jsonBody = parseBfetchResponse(resp); - - expect(resp.status).to.be(200); - expect(jsonBody[0].result.requestParams).to.eql({ - method: 'POST', - path: '/.kibana/_async_search', - querystring: - 'batched_reduce_size=64&ccs_minimize_roundtrips=true&wait_for_completion_timeout=200ms&keep_on_completion=false&keep_alive=60000ms&ignore_unavailable=true', - }); - }); - - it(`should return request meta when request fails`, async () => { - const resp = await supertest - .post(`/internal/bsearch`) - .set(ELASTIC_HTTP_VERSION_HEADER, BFETCH_ROUTE_VERSION_LATEST) - .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') - .send({ - batch: [ - { - request: { - params: { - index: '.kibana', - body: { - bool: { - filter: [ - { - error_query: { - indices: [ - { - error_type: 'exception', - message: 'simulated failure', - name: '.kibana', - }, - ], - }, - }, - ], - }, - }, - }, - }, - options: { - strategy: 'ese', - }, - }, - ], - }); - - const jsonBody = parseBfetchResponse(resp); - - expect(resp.status).to.be(200); - expect(jsonBody[0].error.attributes.requestParams).to.eql({ - method: 'POST', - path: '/.kibana/_async_search', - querystring: - 'batched_reduce_size=64&ccs_minimize_roundtrips=true&wait_for_completion_timeout=200ms&keep_on_completion=false&keep_alive=60000ms&ignore_unavailable=true', - }); - }); - }); - - describe('esql', () => { - it(`should return request meta`, async () => { - const resp = await supertest - .post(`/internal/bsearch`) - .set(ELASTIC_HTTP_VERSION_HEADER, BFETCH_ROUTE_VERSION_LATEST) - .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') - .send({ - batch: [ - { - request: { - params: { - query: 'from .kibana | limit 1', - }, - }, - options: { - strategy: 'esql', - }, - }, - ], - }); - - const jsonBody = parseBfetchResponse(resp); - - expect(resp.status).to.be(200); - expect(jsonBody[0].result.requestParams).to.eql({ - method: 'POST', - path: '/_query', - }); - }); - - it(`should return request meta when request fails`, async () => { - const resp = await supertest - .post(`/internal/bsearch`) - .set(ELASTIC_HTTP_VERSION_HEADER, BFETCH_ROUTE_VERSION_LATEST) - .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') - .send({ - batch: [ - { - request: { - params: { - query: 'fro .kibana | limit 1', - }, - }, - options: { - strategy: 'esql', - }, - }, - ], - }); - - const jsonBody = parseBfetchResponse(resp); - - expect(resp.status).to.be(200); - expect(jsonBody[0].error.attributes.requestParams).to.eql({ - method: 'POST', - path: '/_query', - }); - }); - }); - - describe('sql', () => { - it(`should return request meta`, async () => { - const resp = await supertest - .post(`/internal/bsearch`) - .set(ELASTIC_HTTP_VERSION_HEADER, BFETCH_ROUTE_VERSION_LATEST) - .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') - .send({ - batch: [ - { - request: { - params: { - query: 'SELECT * FROM ".kibana" LIMIT 1', - }, - }, - options: { - strategy: 'sql', - }, - }, - ], - }); - - const jsonBody = parseBfetchResponse(resp); - - expect(resp.status).to.be(200); - expect(jsonBody[0].result.requestParams).to.eql({ - method: 'POST', - path: '/_sql', - querystring: 'format=json', - }); - }); - - it(`should return request meta when request fails`, async () => { - const resp = await supertest - .post(`/internal/bsearch`) - .set(ELASTIC_HTTP_VERSION_HEADER, BFETCH_ROUTE_VERSION_LATEST) - .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') - .send({ - batch: [ - { - request: { - params: { - query: 'SELEC * FROM ".kibana" LIMIT 1', - }, - }, - options: { - strategy: 'sql', - }, - }, - ], - }); - - const jsonBody = parseBfetchResponse(resp); - - expect(resp.status).to.be(200); - expect(jsonBody[0].error.attributes.requestParams).to.eql({ - method: 'POST', - path: '/_sql', - querystring: 'format=json', - }); - }); - }); - - describe('eql', () => { - it(`should return request meta`, async () => { - const resp = await supertest - .post(`/internal/bsearch`) - .set(ELASTIC_HTTP_VERSION_HEADER, BFETCH_ROUTE_VERSION_LATEST) - .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') - .send({ - batch: [ - { - request: { - params: { - index: '.kibana', - query: 'any where true', - timestamp_field: 'created_at', - }, - }, - options: { - strategy: 'eql', - }, - }, - ], - }); - - const jsonBody = parseBfetchResponse(resp); - - expect(resp.status).to.be(200); - expect(jsonBody[0].result.requestParams).to.eql({ - method: 'POST', - path: '/.kibana/_eql/search', - querystring: 'ignore_unavailable=true', - }); - }); - }); - }); - }); - }); -} diff --git a/test/api_integration/apis/search/index.ts b/test/api_integration/apis/search/index.ts index 1ef0efee92d42..3d4b77634adf0 100644 --- a/test/api_integration/apis/search/index.ts +++ b/test/api_integration/apis/search/index.ts @@ -13,6 +13,5 @@ export default function ({ loadTestFile }: FtrProviderContext) { describe('search', () => { loadTestFile(require.resolve('./search')); loadTestFile(require.resolve('./sql_search')); - loadTestFile(require.resolve('./bsearch')); }); } From 6c8614f1fd8d2ef362e43599a88a92410bd4dcaa Mon Sep 17 00:00:00 2001 From: Lukas Olson Date: Mon, 4 Nov 2024 14:48:46 -0700 Subject: [PATCH 08/13] Review feedback --- .../test_suites/common/search_oss/bsearch.ts | 247 ++++++++++++++++++ .../test_suites/common/search_oss/index.ts | 1 + 2 files changed, 248 insertions(+) create mode 100644 x-pack/test_serverless/api_integration/test_suites/common/search_oss/bsearch.ts diff --git a/x-pack/test_serverless/api_integration/test_suites/common/search_oss/bsearch.ts b/x-pack/test_serverless/api_integration/test_suites/common/search_oss/bsearch.ts new file mode 100644 index 0000000000000..93da25aed6000 --- /dev/null +++ b/x-pack/test_serverless/api_integration/test_suites/common/search_oss/bsearch.ts @@ -0,0 +1,247 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import request from 'superagent'; +import { inflateResponse } from '@kbn/bfetch-plugin/public/streaming'; +import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; +import { BFETCH_ROUTE_VERSION_LATEST } from '@kbn/bfetch-plugin/common'; +import { SupertestWithRoleScopeType } from '@kbn/test-suites-xpack/api_integration/deployment_agnostic/services'; +import type { FtrProviderContext } from '../../../ftr_provider_context'; +import { painlessErrReq } from './painless_err_req'; +import { verifyErrorResponse } from './verify_error'; + +function parseBfetchResponse(resp: request.Response, compressed: boolean = false) { + return resp.text + .trim() + .split('\n') + .map((item) => { + return JSON.parse(compressed ? inflateResponse(item) : item); + }); +} + +export default function ({ getService }: FtrProviderContext) { + const esArchiver = getService('esArchiver'); + const roleScopedSupertest = getService('roleScopedSupertest'); + let supertestAdminWithCookieCredentials: SupertestWithRoleScopeType; + + describe('bsearch', () => { + before(async () => { + supertestAdminWithCookieCredentials = await roleScopedSupertest.getSupertestWithRoleScope( + 'admin', + { + useCookieHeader: true, + withInternalHeaders: true, + withCustomHeaders: { + [ELASTIC_HTTP_VERSION_HEADER]: BFETCH_ROUTE_VERSION_LATEST, + }, + } + ); + }); + + describe('post', () => { + it('should return 200 a single response', async () => { + const resp = await supertestAdminWithCookieCredentials.post(`/internal/bsearch`).send({ + batch: [ + { + request: { + params: { + index: '.kibana', + body: { + query: { + match_all: {}, + }, + }, + }, + }, + options: { + strategy: 'es', + }, + }, + ], + }); + + const jsonBody = parseBfetchResponse(resp); + + expect(resp.status).to.be(200); + expect(jsonBody[0].id).to.be(0); + expect(jsonBody[0].result.isPartial).to.be(false); + expect(jsonBody[0].result.isRunning).to.be(false); + expect(jsonBody[0].result).to.have.property('rawResponse'); + }); + + it('should return 200 a single response from compressed', async () => { + const resp = await supertestAdminWithCookieCredentials + .post(`/internal/bsearch?compress=true`) + .send({ + batch: [ + { + request: { + params: { + index: '.kibana', + body: { + query: { + match_all: {}, + }, + }, + }, + }, + options: { + strategy: 'es', + }, + }, + ], + }); + + const jsonBody = parseBfetchResponse(resp, true); + + expect(resp.status).to.be(200); + expect(jsonBody[0].id).to.be(0); + expect(jsonBody[0].result.isPartial).to.be(false); + expect(jsonBody[0].result.isRunning).to.be(false); + expect(jsonBody[0].result).to.have.property('rawResponse'); + }); + + it('should return a batch of successful responses', async () => { + const resp = await supertestAdminWithCookieCredentials + .post(`/internal/bsearch`) + .set(ELASTIC_HTTP_VERSION_HEADER, BFETCH_ROUTE_VERSION_LATEST) + .send({ + batch: [ + { + request: { + params: { + index: '.kibana', + body: { + query: { + match_all: {}, + }, + }, + }, + }, + }, + { + request: { + params: { + index: '.kibana', + body: { + query: { + match_all: {}, + }, + }, + }, + }, + }, + ], + }); + + expect(resp.status).to.be(200); + const parsedResponse = parseBfetchResponse(resp); + expect(parsedResponse).to.have.length(2); + parsedResponse.forEach((responseJson) => { + expect(responseJson.result).to.have.property('isPartial'); + expect(responseJson.result).to.have.property('isRunning'); + expect(responseJson.result).to.have.property('rawResponse'); + }); + }); + + it('should return error for not found strategy', async () => { + const resp = await supertestAdminWithCookieCredentials + .post(`/internal/bsearch`) + .set(ELASTIC_HTTP_VERSION_HEADER, BFETCH_ROUTE_VERSION_LATEST) + .send({ + batch: [ + { + request: { + params: { + index: '.kibana', + body: { + query: { + match_all: {}, + }, + }, + }, + }, + options: { + strategy: 'wtf', + }, + }, + ], + }); + + expect(resp.status).to.be(200); + parseBfetchResponse(resp).forEach((responseJson, i) => { + expect(responseJson.id).to.be(i); + verifyErrorResponse(responseJson.error, 404, 'Search strategy wtf not found'); + }); + }); + + it('should return 400 when index type is provided in "es" strategy', async () => { + const resp = await supertestAdminWithCookieCredentials + .post(`/internal/bsearch`) + .set(ELASTIC_HTTP_VERSION_HEADER, BFETCH_ROUTE_VERSION_LATEST) + .send({ + batch: [ + { + request: { + index: '.kibana', + indexType: 'baad', + params: { + body: { + query: { + match_all: {}, + }, + }, + }, + }, + options: { + strategy: 'es', + }, + }, + ], + }); + + expect(resp.status).to.be(200); + parseBfetchResponse(resp).forEach((responseJson, i) => { + expect(responseJson.id).to.be(i); + verifyErrorResponse(responseJson.error, 400, 'Unsupported index pattern type baad'); + }); + }); + + describe('painless', () => { + before(async () => { + await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional'); + }); + + after(async () => { + await esArchiver.unload('test/functional/fixtures/es_archiver/logstash_functional'); + }); + it('should return 400 "search_phase_execution_exception" for Painless error in "es" strategy', async () => { + const resp = await supertestAdminWithCookieCredentials + .post(`/internal/bsearch`) + .set(ELASTIC_HTTP_VERSION_HEADER, BFETCH_ROUTE_VERSION_LATEST) + .send({ + batch: [ + { + request: painlessErrReq, + options: { + strategy: 'es', + }, + }, + ], + }); + + expect(resp.status).to.be(200); + parseBfetchResponse(resp).forEach((responseJson, i) => { + expect(responseJson.id).to.be(i); + verifyErrorResponse(responseJson.error, 400, 'search_phase_execution_exception', true); + }); + }); + }); + }); + }); +} diff --git a/x-pack/test_serverless/api_integration/test_suites/common/search_oss/index.ts b/x-pack/test_serverless/api_integration/test_suites/common/search_oss/index.ts index 50299ed81a444..79ff29fdf9f22 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/search_oss/index.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/search_oss/index.ts @@ -16,5 +16,6 @@ export default function ({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./search')); // TODO: Removed `sql_search` since // SQL is not supported in Serverless + loadTestFile(require.resolve('./bsearch')); }); } From 5b663c200b6a6b02391a4c97ab020ce8f214708e Mon Sep 17 00:00:00 2001 From: Lukas Olson Date: Mon, 4 Nov 2024 14:51:26 -0700 Subject: [PATCH 09/13] Remove bsearch tests --- .../test_suites/common/search_oss/bsearch.ts | 247 ------------------ .../test_suites/common/search_oss/index.ts | 1 - 2 files changed, 248 deletions(-) delete mode 100644 x-pack/test_serverless/api_integration/test_suites/common/search_oss/bsearch.ts diff --git a/x-pack/test_serverless/api_integration/test_suites/common/search_oss/bsearch.ts b/x-pack/test_serverless/api_integration/test_suites/common/search_oss/bsearch.ts deleted file mode 100644 index 93da25aed6000..0000000000000 --- a/x-pack/test_serverless/api_integration/test_suites/common/search_oss/bsearch.ts +++ /dev/null @@ -1,247 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import expect from '@kbn/expect'; -import request from 'superagent'; -import { inflateResponse } from '@kbn/bfetch-plugin/public/streaming'; -import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; -import { BFETCH_ROUTE_VERSION_LATEST } from '@kbn/bfetch-plugin/common'; -import { SupertestWithRoleScopeType } from '@kbn/test-suites-xpack/api_integration/deployment_agnostic/services'; -import type { FtrProviderContext } from '../../../ftr_provider_context'; -import { painlessErrReq } from './painless_err_req'; -import { verifyErrorResponse } from './verify_error'; - -function parseBfetchResponse(resp: request.Response, compressed: boolean = false) { - return resp.text - .trim() - .split('\n') - .map((item) => { - return JSON.parse(compressed ? inflateResponse(item) : item); - }); -} - -export default function ({ getService }: FtrProviderContext) { - const esArchiver = getService('esArchiver'); - const roleScopedSupertest = getService('roleScopedSupertest'); - let supertestAdminWithCookieCredentials: SupertestWithRoleScopeType; - - describe('bsearch', () => { - before(async () => { - supertestAdminWithCookieCredentials = await roleScopedSupertest.getSupertestWithRoleScope( - 'admin', - { - useCookieHeader: true, - withInternalHeaders: true, - withCustomHeaders: { - [ELASTIC_HTTP_VERSION_HEADER]: BFETCH_ROUTE_VERSION_LATEST, - }, - } - ); - }); - - describe('post', () => { - it('should return 200 a single response', async () => { - const resp = await supertestAdminWithCookieCredentials.post(`/internal/bsearch`).send({ - batch: [ - { - request: { - params: { - index: '.kibana', - body: { - query: { - match_all: {}, - }, - }, - }, - }, - options: { - strategy: 'es', - }, - }, - ], - }); - - const jsonBody = parseBfetchResponse(resp); - - expect(resp.status).to.be(200); - expect(jsonBody[0].id).to.be(0); - expect(jsonBody[0].result.isPartial).to.be(false); - expect(jsonBody[0].result.isRunning).to.be(false); - expect(jsonBody[0].result).to.have.property('rawResponse'); - }); - - it('should return 200 a single response from compressed', async () => { - const resp = await supertestAdminWithCookieCredentials - .post(`/internal/bsearch?compress=true`) - .send({ - batch: [ - { - request: { - params: { - index: '.kibana', - body: { - query: { - match_all: {}, - }, - }, - }, - }, - options: { - strategy: 'es', - }, - }, - ], - }); - - const jsonBody = parseBfetchResponse(resp, true); - - expect(resp.status).to.be(200); - expect(jsonBody[0].id).to.be(0); - expect(jsonBody[0].result.isPartial).to.be(false); - expect(jsonBody[0].result.isRunning).to.be(false); - expect(jsonBody[0].result).to.have.property('rawResponse'); - }); - - it('should return a batch of successful responses', async () => { - const resp = await supertestAdminWithCookieCredentials - .post(`/internal/bsearch`) - .set(ELASTIC_HTTP_VERSION_HEADER, BFETCH_ROUTE_VERSION_LATEST) - .send({ - batch: [ - { - request: { - params: { - index: '.kibana', - body: { - query: { - match_all: {}, - }, - }, - }, - }, - }, - { - request: { - params: { - index: '.kibana', - body: { - query: { - match_all: {}, - }, - }, - }, - }, - }, - ], - }); - - expect(resp.status).to.be(200); - const parsedResponse = parseBfetchResponse(resp); - expect(parsedResponse).to.have.length(2); - parsedResponse.forEach((responseJson) => { - expect(responseJson.result).to.have.property('isPartial'); - expect(responseJson.result).to.have.property('isRunning'); - expect(responseJson.result).to.have.property('rawResponse'); - }); - }); - - it('should return error for not found strategy', async () => { - const resp = await supertestAdminWithCookieCredentials - .post(`/internal/bsearch`) - .set(ELASTIC_HTTP_VERSION_HEADER, BFETCH_ROUTE_VERSION_LATEST) - .send({ - batch: [ - { - request: { - params: { - index: '.kibana', - body: { - query: { - match_all: {}, - }, - }, - }, - }, - options: { - strategy: 'wtf', - }, - }, - ], - }); - - expect(resp.status).to.be(200); - parseBfetchResponse(resp).forEach((responseJson, i) => { - expect(responseJson.id).to.be(i); - verifyErrorResponse(responseJson.error, 404, 'Search strategy wtf not found'); - }); - }); - - it('should return 400 when index type is provided in "es" strategy', async () => { - const resp = await supertestAdminWithCookieCredentials - .post(`/internal/bsearch`) - .set(ELASTIC_HTTP_VERSION_HEADER, BFETCH_ROUTE_VERSION_LATEST) - .send({ - batch: [ - { - request: { - index: '.kibana', - indexType: 'baad', - params: { - body: { - query: { - match_all: {}, - }, - }, - }, - }, - options: { - strategy: 'es', - }, - }, - ], - }); - - expect(resp.status).to.be(200); - parseBfetchResponse(resp).forEach((responseJson, i) => { - expect(responseJson.id).to.be(i); - verifyErrorResponse(responseJson.error, 400, 'Unsupported index pattern type baad'); - }); - }); - - describe('painless', () => { - before(async () => { - await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional'); - }); - - after(async () => { - await esArchiver.unload('test/functional/fixtures/es_archiver/logstash_functional'); - }); - it('should return 400 "search_phase_execution_exception" for Painless error in "es" strategy', async () => { - const resp = await supertestAdminWithCookieCredentials - .post(`/internal/bsearch`) - .set(ELASTIC_HTTP_VERSION_HEADER, BFETCH_ROUTE_VERSION_LATEST) - .send({ - batch: [ - { - request: painlessErrReq, - options: { - strategy: 'es', - }, - }, - ], - }); - - expect(resp.status).to.be(200); - parseBfetchResponse(resp).forEach((responseJson, i) => { - expect(responseJson.id).to.be(i); - verifyErrorResponse(responseJson.error, 400, 'search_phase_execution_exception', true); - }); - }); - }); - }); - }); -} diff --git a/x-pack/test_serverless/api_integration/test_suites/common/search_oss/index.ts b/x-pack/test_serverless/api_integration/test_suites/common/search_oss/index.ts index 79ff29fdf9f22..50299ed81a444 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/search_oss/index.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/search_oss/index.ts @@ -16,6 +16,5 @@ export default function ({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./search')); // TODO: Removed `sql_search` since // SQL is not supported in Serverless - loadTestFile(require.resolve('./bsearch')); }); } From 364088a827e051ba177ff1d825b7b0f24ce5260b Mon Sep 17 00:00:00 2001 From: Lukas Olson Date: Tue, 5 Nov 2024 13:53:27 -0700 Subject: [PATCH 10/13] Don't use bfetch route version number --- x-pack/test/common/services/search_secure.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/x-pack/test/common/services/search_secure.ts b/x-pack/test/common/services/search_secure.ts index 93654fddd611a..4808346c9bec3 100644 --- a/x-pack/test/common/services/search_secure.ts +++ b/x-pack/test/common/services/search_secure.ts @@ -12,7 +12,6 @@ import expect from '@kbn/expect'; import request from 'superagent'; import type { IEsSearchResponse } from '@kbn/search-types'; import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; -import { BFETCH_ROUTE_VERSION_LATEST } from '@kbn/bfetch-plugin/common'; import { SupertestWithoutAuthProviderType } from '@kbn/ftr-common-functional-services'; import { FtrService } from '../ftr_provider_context'; @@ -113,7 +112,7 @@ export class SearchSecureService extends FtrService { .auth(auth.username, auth.password) .set('kbn-xsrf', 'true') .set('x-elastic-internal-origin', 'Kibana') - .set(ELASTIC_HTTP_VERSION_HEADER, BFETCH_ROUTE_VERSION_LATEST) + .set(ELASTIC_HTTP_VERSION_HEADER, '1') .send() .expect(200); const [parsedResponse] = parseBfetchResponse(resp); From 0bde3619d74783fe639dac92a3252e14f1b8a027 Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Tue, 19 Nov 2024 23:41:33 +0000 Subject: [PATCH 11/13] [CI] Auto-commit changed files from 'node scripts/notice' --- test/tsconfig.json | 1 - 1 file changed, 1 deletion(-) diff --git a/test/tsconfig.json b/test/tsconfig.json index 1d8c301c44a2b..a4ddfc2f4d2a6 100644 --- a/test/tsconfig.json +++ b/test/tsconfig.json @@ -23,7 +23,6 @@ "kbn_references": [ "@kbn/core", { "path": "../src/setup_node_env/tsconfig.json" }, - "@kbn/bfetch-plugin", "@kbn/dashboard-plugin", "@kbn/expressions-plugin", "@kbn/saved-objects-management-plugin", From 09e892ca7ea286832c2726c7f5e7425a313119a1 Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Tue, 19 Nov 2024 23:52:33 +0000 Subject: [PATCH 12/13] [CI] Auto-commit changed files from 'node scripts/eslint --no-cache --fix' --- x-pack/test/common/services/search_secure.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/test/common/services/search_secure.ts b/x-pack/test/common/services/search_secure.ts index 31f02254ca24e..62a09bfdb074f 100644 --- a/x-pack/test/common/services/search_secure.ts +++ b/x-pack/test/common/services/search_secure.ts @@ -8,7 +8,7 @@ // NOTE: This is pretty much a copy/paste from packages/kbn-ftr-common-functional-services/services/bsearch.ts // but with the ability to provide custom auth -import expect from '@kbn/expect/expect'; +import expect from '@kbn/expect'; import type { IEsSearchResponse } from '@kbn/search-types'; import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; import { SupertestWithoutAuthProviderType } from '@kbn/ftr-common-functional-services'; From 23eb8a926d9fc2e2e7615e1a28b1cf144f3e88ed Mon Sep 17 00:00:00 2001 From: Lukas Olson Date: Wed, 27 Nov 2024 16:27:09 -0700 Subject: [PATCH 13/13] Update search interceptor tests and fix types --- src/plugins/data/public/plugin.ts | 2 - .../search_interceptor.test.ts | 409 ++++++++++++------ .../data/public/search/search_service.ts | 11 +- 3 files changed, 281 insertions(+), 141 deletions(-) diff --git a/src/plugins/data/public/plugin.ts b/src/plugins/data/public/plugin.ts index 5dceb2cacac9d..c31031a5c657e 100644 --- a/src/plugins/data/public/plugin.ts +++ b/src/plugins/data/public/plugin.ts @@ -71,7 +71,6 @@ export class DataPublicPlugin public setup( core: CoreSetup, { - bfetch, expressions, uiActions, usageCollection, @@ -85,7 +84,6 @@ export class DataPublicPlugin setTheme(core.theme); const searchService = this.searchService.setup(core, { - bfetch, usageCollection, expressions, management, diff --git a/src/plugins/data/public/search/search_interceptor/search_interceptor.test.ts b/src/plugins/data/public/search/search_interceptor/search_interceptor.test.ts index 371cbfbc176d2..4a1f2be310361 100644 --- a/src/plugins/data/public/search/search_interceptor/search_interceptor.test.ts +++ b/src/plugins/data/public/search/search_interceptor/search_interceptor.test.ts @@ -10,7 +10,11 @@ import type { MockedKeys } from '@kbn/utility-types-jest'; import { CoreSetup, CoreStart, HttpFetchOptions, HttpHandler } from '@kbn/core/public'; import { coreMock } from '@kbn/core/public/mocks'; -import { IEsSearchRequest, IKibanaSearchRequest } from '@kbn/search-types'; +import { + IEsSearchRequest, + IKibanaSearchRequest, + type IKibanaSearchResponse, +} from '@kbn/search-types'; import { SearchInterceptor } from './search_interceptor'; import { AbortError } from '@kbn/kibana-utils-plugin/public'; import { EsError, type IEsError } from '@kbn/search-errors'; @@ -59,7 +63,7 @@ const next = jest.fn(); const error = jest.fn(); const complete = jest.fn(); -function getResponseMock(responses: any[]) { +function getHttpMock(responses: any[]) { let i = 0; return ((path: string, options?: HttpFetchOptions) => { const request = JSON.parse(options?.body as string) as IKibanaSearchRequest; @@ -83,6 +87,38 @@ function getResponseMock(responses: any[]) { }) as HttpHandler; } +function getMockSearchResponse( + { id, isPartial, isRunning, rawResponse }: IKibanaSearchResponse = { + rawResponse: {}, + } +) { + const body = { + ...(id ? { id } : {}), + is_partial: isPartial ?? false, + is_running: isRunning ?? false, + response: { + took: 2, + timed_out: false, + _shards: { + total: 12, + successful: 12, + skipped: 11, + failed: 0, + }, + hits: { + total: { + value: 61, + relation: 'eq', + }, + max_score: null, + hits: [], + }, + ...rawResponse, + }, + }; + return { body }; +} + describe('SearchInterceptor', () => { let mockCoreSetup: MockedKeys; let mockCoreStart: MockedKeys; @@ -175,30 +211,48 @@ describe('SearchInterceptor', () => { describe('search', () => { test('Observable should resolve if fetch is successful', async () => { - const mockResponse: any = { rawResponse: {} }; - mockCoreSetup.http.post.mockResolvedValueOnce(mockResponse); + mockCoreSetup.http.post.mockResolvedValueOnce(getMockSearchResponse()); const mockRequest: IEsSearchRequest = { params: {}, }; const response = searchInterceptor.search(mockRequest); - await expect(response.toPromise()).resolves.toBe(mockResponse); + await expect(response.toPromise()).resolves.toMatchInlineSnapshot(` + Object { + "id": undefined, + "isPartial": false, + "isRestored": false, + "isRunning": false, + "loaded": 12, + "rawResponse": Object { + "_shards": Object { + "failed": 0, + "skipped": 11, + "successful": 12, + "total": 12, + }, + "hits": Object { + "hits": Array [], + "max_score": null, + "total": 61, + }, + "timed_out": false, + "took": 2, + }, + "requestParams": Object {}, + "total": 12, + "warning": undefined, + } + `); }); test('should resolve immediately if first call returns full result', async () => { const responses = [ { time: 10, - value: { - isPartial: false, - isRunning: false, - id: 1, - rawResponse: { - took: 1, - }, - }, + value: getMockSearchResponse(), }, ]; - mockCoreSetup.http.post.mockImplementation(getResponseMock(responses)); + mockCoreSetup.http.post.mockImplementation(getHttpMock(responses)); const response = searchInterceptor.search({}); response.subscribe({ next, error, complete }); @@ -206,7 +260,33 @@ describe('SearchInterceptor', () => { await timeTravel(10); expect(next).toHaveBeenCalled(); - expect(next.mock.calls[0][0]).toStrictEqual(responses[0].value); + expect(next.mock.calls[0][0]).toMatchInlineSnapshot(` + Object { + "id": undefined, + "isPartial": false, + "isRestored": false, + "isRunning": false, + "loaded": 12, + "rawResponse": Object { + "_shards": Object { + "failed": 0, + "skipped": 11, + "successful": 12, + "total": 12, + }, + "hits": Object { + "hits": Array [], + "max_score": null, + "total": 61, + }, + "timed_out": false, + "took": 2, + }, + "requestParams": Object {}, + "total": 12, + "warning": undefined, + } + `); expect(complete).toHaveBeenCalled(); expect(error).not.toHaveBeenCalled(); }); @@ -215,29 +295,29 @@ describe('SearchInterceptor', () => { const responses = [ { time: 10, - value: { + value: getMockSearchResponse({ isPartial: true, isRunning: true, - id: 1, + id: '1', rawResponse: { took: 1, }, - }, + }), }, { time: 20, - value: { + value: getMockSearchResponse({ isPartial: false, isRunning: false, - id: 1, + id: '1', rawResponse: { took: 1, }, - }, + }), }, ]; - mockCoreSetup.http.post.mockImplementation(getResponseMock(responses)); + mockCoreSetup.http.post.mockImplementation(getHttpMock(responses)); const response = searchInterceptor.search({}, { pollInterval: 0 }); response.subscribe({ next, error, complete }); @@ -245,14 +325,66 @@ describe('SearchInterceptor', () => { await timeTravel(10); expect(next).toHaveBeenCalled(); - expect(next.mock.calls[0][0]).toStrictEqual(responses[0].value); + expect(next.mock.calls[0][0]).toMatchInlineSnapshot(` + Object { + "id": "1", + "isPartial": true, + "isRestored": false, + "isRunning": true, + "loaded": 12, + "rawResponse": Object { + "_shards": Object { + "failed": 0, + "skipped": 11, + "successful": 12, + "total": 12, + }, + "hits": Object { + "hits": Array [], + "max_score": null, + "total": 61, + }, + "timed_out": false, + "took": 1, + }, + "requestParams": Object {}, + "total": 12, + "warning": undefined, + } + `); expect(complete).not.toHaveBeenCalled(); expect(error).not.toHaveBeenCalled(); await timeTravel(20); expect(next).toHaveBeenCalledTimes(2); - expect(next.mock.calls[1][0]).toStrictEqual(responses[1].value); + expect(next.mock.calls[1][0]).toMatchInlineSnapshot(` + Object { + "id": "1", + "isPartial": false, + "isRestored": false, + "isRunning": false, + "loaded": 12, + "rawResponse": Object { + "_shards": Object { + "failed": 0, + "skipped": 11, + "successful": 12, + "total": 12, + }, + "hits": Object { + "hits": Array [], + "max_score": null, + "total": 61, + }, + "timed_out": false, + "took": 1, + }, + "requestParams": Object {}, + "total": 12, + "warning": undefined, + } + `); expect(complete).toHaveBeenCalled(); expect(error).not.toHaveBeenCalled(); }); @@ -261,15 +393,15 @@ describe('SearchInterceptor', () => { const responses = [ { time: 500, - value: { + value: getMockSearchResponse({ isPartial: false, isRunning: false, rawResponse: {}, - id: 1, - }, + id: '1', + }), }, ]; - mockCoreSetup.http.post.mockImplementation(getResponseMock(responses)); + mockCoreSetup.http.post.mockImplementation(getHttpMock(responses)); const abortController = new AbortController(); abortController.abort(); @@ -288,24 +420,24 @@ describe('SearchInterceptor', () => { const responses = [ { time: 10, - value: { + value: getMockSearchResponse({ isPartial: true, isRunning: true, rawResponse: {}, - id: 1, - }, + id: '1', + }), }, { time: 300, - value: { + value: getMockSearchResponse({ isPartial: false, isRunning: false, rawResponse: {}, - id: 1, - }, + id: '1', + }), }, ]; - mockCoreSetup.http.post.mockImplementation(getResponseMock(responses)); + mockCoreSetup.http.post.mockImplementation(getHttpMock(responses)); const abortController = new AbortController(); setTimeout(() => abortController.abort(), 250); @@ -334,15 +466,15 @@ describe('SearchInterceptor', () => { const responses = [ { time: 2000, - value: { + value: getMockSearchResponse({ isPartial: false, isRunning: false, rawResponse: {}, - id: 1, - }, + id: '1', + }), }, ]; - mockCoreSetup.http.post.mockImplementation(getResponseMock(responses)); + mockCoreSetup.http.post.mockImplementation(getHttpMock(responses)); const response = searchInterceptor.search({}, { pollInterval: 0 }); response.subscribe({ next, error }); @@ -354,12 +486,14 @@ describe('SearchInterceptor', () => { }); test('should DELETE a running async search on async timeout after first response', async () => { - mockCoreSetup.http.post.mockResolvedValue({ - isPartial: true, - isRunning: true, - rawResponse: {}, - id: 1, - }); + mockCoreSetup.http.post.mockResolvedValue( + getMockSearchResponse({ + isPartial: true, + isRunning: true, + rawResponse: {}, + id: '1', + }) + ); const response = searchInterceptor.search({}, { pollInterval: 0 }); response.subscribe({ next, error }); @@ -378,14 +512,16 @@ describe('SearchInterceptor', () => { }); test('should return the last response on async timeout', async () => { - mockCoreSetup.http.post.mockResolvedValue({ - isPartial: true, - isRunning: true, - rawResponse: { - foo: 'bar', - }, - id: 1, - }); + mockCoreSetup.http.post.mockResolvedValue( + getMockSearchResponse({ + isPartial: true, + isRunning: true, + rawResponse: { + foo: 'bar', + }, + id: '1', + }) + ); const response = searchInterceptor.search({}, { pollInterval: 0 }); response.subscribe({ next, error }); @@ -404,12 +540,30 @@ describe('SearchInterceptor', () => { expect(next.mock.calls[1]).toMatchInlineSnapshot(` Array [ Object { - "id": 1, + "id": "1", "isPartial": true, + "isRestored": false, "isRunning": true, + "loaded": 12, "rawResponse": Object { + "_shards": Object { + "failed": 0, + "skipped": 11, + "successful": 12, + "total": 12, + }, "foo": "bar", + "hits": Object { + "hits": Array [], + "max_score": null, + "total": 61, + }, + "timed_out": false, + "took": 2, }, + "requestParams": Object {}, + "total": 12, + "warning": undefined, }, ] `); @@ -419,24 +573,24 @@ describe('SearchInterceptor', () => { const responses = [ { time: 10, - value: { + value: getMockSearchResponse({ isPartial: true, isRunning: true, rawResponse: {}, - id: 1, - }, + id: '1', + }), }, { time: 10, value: { statusCode: 500, message: 'oh no', - id: 1, + id: '1', }, isError: true, }, ]; - mockCoreSetup.http.post.mockImplementation(getResponseMock(responses)); + mockCoreSetup.http.post.mockImplementation(getHttpMock(responses)); const response = searchInterceptor.search({}, { pollInterval: 0 }); response.subscribe({ next, error }); @@ -463,24 +617,24 @@ describe('SearchInterceptor', () => { const responses = [ { time: 10, - value: { + value: getMockSearchResponse({ isPartial: true, isRunning: true, rawResponse: {}, - id: 1, - }, + id: '1', + }), }, { time: 10, value: { statusCode: 500, message: 'oh no', - id: 1, + id: '1', }, isError: true, }, ]; - mockCoreSetup.http.post.mockImplementation(getResponseMock(responses)); + mockCoreSetup.http.post.mockImplementation(getHttpMock(responses)); const response = searchInterceptor.search({}, { pollInterval: 0 }); response.subscribe({ next, error }); @@ -508,24 +662,24 @@ describe('SearchInterceptor', () => { const responses = [ { time: 10, - value: { + value: getMockSearchResponse({ isPartial: true, isRunning: true, rawResponse: {}, - id: 1, - }, + id: '1', + }), }, { time: 300, - value: { + value: getMockSearchResponse({ isPartial: false, isRunning: false, rawResponse: {}, - id: 1, - }, + id: '1', + }), }, ]; - mockCoreSetup.http.post.mockImplementation(getResponseMock(responses)); + mockCoreSetup.http.post.mockImplementation(getHttpMock(responses)); const abortController = new AbortController(); setTimeout(() => abortController.abort(), 250); @@ -650,14 +804,14 @@ describe('SearchInterceptor', () => { isPartial: false, isRunning: false, isRestored: true, - id: 1, + id: '1', rawResponse: { took: 1, }, }, }, ]; - mockCoreSetup.http.post.mockImplementation(getResponseMock(responses)); + mockCoreSetup.http.post.mockImplementation(getHttpMock(responses)); const response = searchInterceptor.search( {}, @@ -685,14 +839,14 @@ describe('SearchInterceptor', () => { isPartial: false, isRunning: false, isRestored: false, - id: 1, + id: '1', rawResponse: { took: 1, }, }, }, ]; - mockCoreSetup.http.post.mockImplementation(getResponseMock(responses)); + mockCoreSetup.http.post.mockImplementation(getHttpMock(responses)); const response = searchInterceptor.search( {}, @@ -717,18 +871,18 @@ describe('SearchInterceptor', () => { const responses = [ { time: 10, - value: { + value: getMockSearchResponse({ isPartial: false, isRunning: false, isRestored: false, - id: 1, + id: '1', rawResponse: { took: 1, }, - }, + }), }, ]; - mockCoreSetup.http.post.mockImplementation(getResponseMock(responses)); + mockCoreSetup.http.post.mockImplementation(getHttpMock(responses)); searchInterceptor .search( @@ -763,25 +917,25 @@ describe('SearchInterceptor', () => { const responses = [ { time: 10, - value: { + value: getMockSearchResponse({ isPartial: true, isRunning: true, rawResponse: {}, - id: 1, - }, + id: '1', + }), }, { time: 300, - value: { + value: getMockSearchResponse({ isPartial: false, isRunning: false, rawResponse: {}, - id: 1, - }, + id: '1', + }), }, ]; - mockCoreSetup.http.post.mockImplementation(getResponseMock(responses)); + mockCoreSetup.http.post.mockImplementation(getHttpMock(responses)); }); test('should track searches', async () => { @@ -880,39 +1034,39 @@ describe('SearchInterceptor', () => { const basicCompleteResponse = [ { time: 10, - value: { + value: getMockSearchResponse({ isPartial: false, isRunning: false, - id: 1, + id: '1', rawResponse: { took: 1, }, - }, + }), }, ]; const partialCompleteResponse = [ { time: 10, - value: { + value: getMockSearchResponse({ isPartial: true, isRunning: true, - id: 1, + id: '1', rawResponse: { took: 1, }, - }, + }), }, { time: 20, - value: { + value: getMockSearchResponse({ isPartial: false, isRunning: false, - id: 1, + id: '1', rawResponse: { took: 1, }, - }, + }), }, ]; @@ -924,7 +1078,7 @@ describe('SearchInterceptor', () => { }); test('should be disabled if there is no session', async () => { - mockCoreSetup.http.post.mockImplementation(getResponseMock(basicCompleteResponse)); + mockCoreSetup.http.post.mockImplementation(getHttpMock(basicCompleteResponse)); searchInterceptor.search(basicReq, {}).subscribe({ next, error, complete }); expect(mockCoreSetup.http.post).toBeCalledTimes(1); @@ -934,7 +1088,7 @@ describe('SearchInterceptor', () => { }); test('should fetch different requests in a single session', async () => { - mockCoreSetup.http.post.mockImplementation(getResponseMock(basicCompleteResponse)); + mockCoreSetup.http.post.mockImplementation(getHttpMock(basicCompleteResponse)); const req2 = { params: { @@ -942,16 +1096,6 @@ describe('SearchInterceptor', () => { }, }; - next.mockImplementation(() => { - console.log('next'); - }); - error.mockImplementation((...args) => { - console.log('error'); - }); - complete.mockImplementation((...args) => { - console.log('complete'); - }); - searchInterceptor.search(basicReq, { sessionId }).subscribe({ next, error, complete }); await timeTravel(10); expect(mockCoreSetup.http.post).toBeCalledTimes(1); @@ -962,7 +1106,7 @@ describe('SearchInterceptor', () => { }); test('should fetch the same request for two different sessions', async () => { - mockCoreSetup.http.post.mockImplementation(getResponseMock(basicCompleteResponse)); + mockCoreSetup.http.post.mockImplementation(getHttpMock(basicCompleteResponse)); searchInterceptor.search(basicReq, { sessionId }).subscribe({ next, error, complete }); await timeTravel(10); @@ -976,7 +1120,7 @@ describe('SearchInterceptor', () => { }); test('should not track searches that come from cache', async () => { - mockCoreSetup.http.post.mockImplementation(getResponseMock(partialCompleteResponse)); + mockCoreSetup.http.post.mockImplementation(getHttpMock(partialCompleteResponse)); sessionService.isCurrentSession.mockImplementation( (_sessionId) => _sessionId === sessionId ); @@ -1022,16 +1166,16 @@ describe('SearchInterceptor', () => { const responses = [ { time: 10, - value: { + value: getMockSearchResponse({ isPartial: true, isRunning: true, rawResponse: {}, - id: 1, - }, + id: '1', + }), }, ]; - mockCoreSetup.http.post.mockImplementation(getResponseMock(responses)); + mockCoreSetup.http.post.mockImplementation(getHttpMock(responses)); searchInterceptor.search(basicReq, { sessionId }).subscribe({ next, error, complete }); await timeTravel(10); @@ -1046,15 +1190,17 @@ describe('SearchInterceptor', () => { const responses = [ { time: 10, - value: { + value: getMockSearchResponse({ isPartial: true, isRunning: false, - id: 1, - }, + id: '1', + rawResponse: {}, + }), + isError: true, }, ]; - mockCoreSetup.http.post.mockImplementation(getResponseMock(responses)); + mockCoreSetup.http.post.mockImplementation(getHttpMock(responses)); searchInterceptor.search(basicReq, { sessionId }).subscribe({ next, error, complete }); await timeTravel(10); @@ -1066,7 +1212,7 @@ describe('SearchInterceptor', () => { }); test('should ignore anything outside params when hashing', async () => { - mockCoreSetup.http.post.mockImplementation(getResponseMock(basicCompleteResponse)); + mockCoreSetup.http.post.mockImplementation(getHttpMock(basicCompleteResponse)); const req = { something: 123, @@ -1095,11 +1241,16 @@ describe('SearchInterceptor', () => { const responses = [ { time: 10, - value: {}, + value: { + statusCode: 500, + message: 'Aborted', + id: '1', + }, + isError: true, }, ]; - mockCoreSetup.http.post.mockImplementation(getResponseMock(responses)); + mockCoreSetup.http.post.mockImplementation(getHttpMock(responses)); searchInterceptor.search(basicReq, { sessionId }).subscribe({ next, error, complete }); searchInterceptor.search(basicReq, { sessionId }).subscribe({ next, error, complete }); @@ -1111,7 +1262,7 @@ describe('SearchInterceptor', () => { }); test('should ignore preference when hashing', async () => { - mockCoreSetup.http.post.mockImplementation(getResponseMock(basicCompleteResponse)); + mockCoreSetup.http.post.mockImplementation(getHttpMock(basicCompleteResponse)); const req = { params: { @@ -1137,7 +1288,7 @@ describe('SearchInterceptor', () => { }); test('should return from cache for identical requests in the same session', async () => { - mockCoreSetup.http.post.mockImplementation(getResponseMock(basicCompleteResponse)); + mockCoreSetup.http.post.mockImplementation(getHttpMock(basicCompleteResponse)); searchInterceptor.search(basicReq, { sessionId }).subscribe({ next, error, complete }); await timeTravel(10); @@ -1149,7 +1300,7 @@ describe('SearchInterceptor', () => { }); test('aborting a search that didnt get any response should retrigger search', async () => { - mockCoreSetup.http.post.mockImplementation(getResponseMock(basicCompleteResponse)); + mockCoreSetup.http.post.mockImplementation(getHttpMock(basicCompleteResponse)); const abortController = new AbortController(); @@ -1186,7 +1337,7 @@ describe('SearchInterceptor', () => { }); test('aborting a running first search shouldnt clear cache', async () => { - mockCoreSetup.http.post.mockImplementation(getResponseMock(partialCompleteResponse)); + mockCoreSetup.http.post.mockImplementation(getHttpMock(partialCompleteResponse)); sessionService.isCurrentSession.mockImplementation( (_sessionId) => _sessionId === sessionId ); @@ -1253,7 +1404,7 @@ describe('SearchInterceptor', () => { }); test('aborting a running second search shouldnt clear cache', async () => { - mockCoreSetup.http.post.mockImplementation(getResponseMock(partialCompleteResponse)); + mockCoreSetup.http.post.mockImplementation(getHttpMock(partialCompleteResponse)); sessionService.isCurrentSession.mockImplementation( (_sessionId) => _sessionId === sessionId ); @@ -1318,7 +1469,7 @@ describe('SearchInterceptor', () => { }); test('aborting both requests should cancel underlaying search only once', async () => { - mockCoreSetup.http.post.mockImplementation(getResponseMock(partialCompleteResponse)); + mockCoreSetup.http.post.mockImplementation(getHttpMock(partialCompleteResponse)); sessionService.isCurrentSession.mockImplementation( (_sessionId) => _sessionId === sessionId ); @@ -1355,7 +1506,7 @@ describe('SearchInterceptor', () => { }); test('aborting both searches should stop searching and clear cache', async () => { - mockCoreSetup.http.post.mockImplementation(getResponseMock(partialCompleteResponse)); + mockCoreSetup.http.post.mockImplementation(getHttpMock(partialCompleteResponse)); sessionService.isCurrentSession.mockImplementation( (_sessionId) => _sessionId === sessionId ); @@ -1412,7 +1563,7 @@ describe('SearchInterceptor', () => { // Clear mock and research mockCoreSetup.http.post.mockReset(); - mockCoreSetup.http.post.mockImplementation(getResponseMock(partialCompleteResponse)); + mockCoreSetup.http.post.mockImplementation(getHttpMock(partialCompleteResponse)); // Run the search again to see that we don't hit the cache const response3 = searchInterceptor.search(req, { pollInterval: 1, sessionId }); response3.subscribe({ next, error, complete }); @@ -1427,7 +1578,7 @@ describe('SearchInterceptor', () => { }); test("aborting a completed search shouldn't effect cache", async () => { - mockCoreSetup.http.post.mockImplementation(getResponseMock(basicCompleteResponse)); + mockCoreSetup.http.post.mockImplementation(getHttpMock(basicCompleteResponse)); const abortController = new AbortController(); diff --git a/src/plugins/data/public/search/search_service.ts b/src/plugins/data/public/search/search_service.ts index 279e9cddc8986..d1e5d02e5d840 100644 --- a/src/plugins/data/public/search/search_service.ts +++ b/src/plugins/data/public/search/search_service.ts @@ -9,7 +9,6 @@ import { i18n } from '@kbn/i18n'; import { estypes } from '@elastic/elasticsearch'; -import { BfetchPublicSetup } from '@kbn/bfetch-plugin/public'; import { handleWarnings } from '@kbn/search-response-warnings'; import { CoreSetup, @@ -78,7 +77,6 @@ import { ISearchSetup, ISearchStart } from './types'; /** @internal */ export interface SearchServiceSetupDependencies { - bfetch: BfetchPublicSetup; expressions: ExpressionsSetup; usageCollection?: UsageCollectionSetup; management: ManagementSetup; @@ -106,13 +104,7 @@ export class SearchService implements Plugin { public setup( core: CoreSetup, - { - bfetch, - expressions, - usageCollection, - nowProvider, - management, - }: SearchServiceSetupDependencies + { expressions, usageCollection, nowProvider, management }: SearchServiceSetupDependencies ): ISearchSetup { const { http, getStartServices, notifications, uiSettings, executionContext } = core; this.usageCollector = createUsageCollector(getStartServices, usageCollection); @@ -130,7 +122,6 @@ export class SearchService implements Plugin { * all pending search requests, as well as getting the number of pending search requests. */ this.searchInterceptor = new SearchInterceptor({ - bfetch, toasts: notifications.toasts, executionContext, http,