From 65c450c77e49ca9aeb7f8f32a29a28e9018de3fc Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Wed, 15 Dec 2021 16:49:13 -0700 Subject: [PATCH 01/13] [Reporting] remove legacy pdf shim --- .../types/export_types/printable_pdf.ts | 5 - .../create_job/compatibility_shim.test.ts | 257 ------------------ .../create_job/compatibility_shim.ts | 132 --------- .../printable_pdf/create_job/index.ts | 34 +-- .../export_types/printable_pdf/types.ts | 2 +- .../server/routes/lib/request_handler.test.ts | 3 +- .../server/routes/lib/request_handler.ts | 6 +- 7 files changed, 17 insertions(+), 422 deletions(-) delete mode 100644 x-pack/plugins/reporting/server/export_types/printable_pdf/create_job/compatibility_shim.test.ts delete mode 100644 x-pack/plugins/reporting/server/export_types/printable_pdf/create_job/compatibility_shim.ts diff --git a/x-pack/plugins/reporting/common/types/export_types/printable_pdf.ts b/x-pack/plugins/reporting/common/types/export_types/printable_pdf.ts index 57e5a90595d5cd..55a686cc829bed 100644 --- a/x-pack/plugins/reporting/common/types/export_types/printable_pdf.ts +++ b/x-pack/plugins/reporting/common/types/export_types/printable_pdf.ts @@ -25,8 +25,3 @@ export interface TaskPayloadPDF extends BasePayload { forceNow?: string; objects: Array<{ relativeUrl: string }>; } - -export interface JobParamsPDFLegacy extends Omit { - savedObjectId: string; - queryString: string; -} diff --git a/x-pack/plugins/reporting/server/export_types/printable_pdf/create_job/compatibility_shim.test.ts b/x-pack/plugins/reporting/server/export_types/printable_pdf/create_job/compatibility_shim.test.ts deleted file mode 100644 index 0166e82744e5d8..00000000000000 --- a/x-pack/plugins/reporting/server/export_types/printable_pdf/create_job/compatibility_shim.test.ts +++ /dev/null @@ -1,257 +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 { coreMock } from 'src/core/server/mocks'; -import { createMockLevelLogger } from '../../../test_helpers'; -import { compatibilityShim } from './compatibility_shim'; - -const mockRequestHandlerContext = { - core: coreMock.createRequestHandlerContext(), - reporting: { usesUiCapabilities: () => true }, -}; -const mockLogger = createMockLevelLogger(); - -const createMockSavedObject = (body: any) => ({ - id: 'mockSavedObjectId123', - type: 'mockSavedObjectType', - references: [], - ...body, -}); -const createMockJobParams = (body: any) => ({ - ...body, -}); - -beforeEach(() => { - jest.clearAllMocks(); -}); - -test(`passes title through if provided`, async () => { - const title = 'test title'; - - const createJobMock = jest.fn(); - await compatibilityShim(createJobMock, mockLogger)( - createMockJobParams({ title, relativeUrls: ['/something'] }), - mockRequestHandlerContext - ); - - expect(mockLogger.warn.mock.calls.length).toBe(0); - expect(mockLogger.error.mock.calls.length).toBe(0); - - expect(createJobMock.mock.calls.length).toBe(1); - expect(createJobMock.mock.calls[0][0].title).toBe(title); -}); - -test(`gets the title from the savedObject`, async () => { - const createJobMock = jest.fn(); - const title = 'savedTitle'; - mockRequestHandlerContext.core.savedObjects.client.resolve.mockResolvedValue({ - saved_object: createMockSavedObject({ - attributes: { title }, - }), - } as any); - - await compatibilityShim(createJobMock, mockLogger)( - createMockJobParams({ objectType: 'search', savedObjectId: 'abc' }), - mockRequestHandlerContext - ); - - expect(mockLogger.warn.mock.calls.length).toBe(2); - expect(mockLogger.warn.mock.calls[0][0]).toEqual( - 'The relativeUrls have been derived from saved object parameters. This functionality will be removed with the next major version.' - ); - expect(mockLogger.error.mock.calls.length).toBe(0); - - expect(createJobMock.mock.calls.length).toBe(1); - expect(createJobMock.mock.calls[0][0].title).toBe(title); -}); - -test(`passes the objectType and savedObjectId to the savedObjectsClient`, async () => { - const createJobMock = jest.fn(); - const context = mockRequestHandlerContext; - context.core.savedObjects.client.resolve.mockResolvedValue({ - saved_object: createMockSavedObject({ attributes: { title: '' } }), - } as any); - - const objectType = 'search'; - const savedObjectId = 'abc'; - await compatibilityShim(createJobMock, mockLogger)( - createMockJobParams({ objectType, savedObjectId }), - context - ); - - expect(mockLogger.warn.mock.calls.length).toBe(2); - expect(mockLogger.warn.mock.calls[0][0]).toEqual( - 'The relativeUrls have been derived from saved object parameters. This functionality will be removed with the next major version.' - ); - expect(mockLogger.warn.mock.calls[1][0]).toEqual( - 'The title has been derived from saved object parameters. This functionality will be removed with the next major version.' - ); - expect(mockLogger.error.mock.calls.length).toBe(0); - - expect(context.core.savedObjects.client.resolve).toHaveBeenCalledTimes(1); - expect(context.core.savedObjects.client.resolve).toHaveBeenCalledWith(objectType, savedObjectId); -}); - -test(`logs no warnings when title and relativeUrls is passed`, async () => { - const createJobMock = jest.fn(); - - await compatibilityShim(createJobMock, mockLogger)( - createMockJobParams({ title: 'Phenomenal Dashboard', relativeUrls: ['/abc', '/def'] }), - mockRequestHandlerContext - ); - - expect(mockLogger.warn.mock.calls.length).toBe(0); - expect(mockLogger.error.mock.calls.length).toBe(0); -}); - -test(`logs warning if title can not be provided`, async () => { - const createJobMock = jest.fn(); - await compatibilityShim(createJobMock, mockLogger)( - createMockJobParams({ relativeUrls: ['/abc'] }), - mockRequestHandlerContext - ); - - expect(mockLogger.warn.mock.calls.length).toBe(1); - expect(mockLogger.warn.mock.calls[0][0]).toEqual( - `A title parameter should be provided with the job generation request. Please ` + - `use Kibana to regenerate your POST URL to have a title included in the PDF.` - ); -}); - -test(`logs deprecations when generating the title/relativeUrl using the savedObject`, async () => { - const createJobMock = jest.fn(); - mockRequestHandlerContext.core.savedObjects.client.get.mockResolvedValue( - createMockSavedObject({ - attributes: { title: '' }, - }) - ); - - await compatibilityShim(createJobMock, mockLogger)( - createMockJobParams({ objectType: 'search', savedObjectId: 'abc' }), - mockRequestHandlerContext - ); - - expect(mockLogger.warn.mock.calls.length).toBe(2); - expect(mockLogger.warn.mock.calls[0][0]).toEqual( - 'The relativeUrls have been derived from saved object parameters. This functionality will be removed with the next major version.' - ); - expect(mockLogger.warn.mock.calls[1][0]).toEqual( - 'The title has been derived from saved object parameters. This functionality will be removed with the next major version.' - ); -}); - -test(`passes objectType through`, async () => { - const createJobMock = jest.fn(); - - const objectType = 'foo'; - await compatibilityShim(createJobMock, mockLogger)( - createMockJobParams({ title: 'test', relativeUrls: ['/something'], objectType }), - mockRequestHandlerContext - ); - - expect(mockLogger.warn.mock.calls.length).toBe(0); - expect(mockLogger.error.mock.calls.length).toBe(0); - - expect(createJobMock.mock.calls.length).toBe(1); - expect(createJobMock.mock.calls[0][0].objectType).toBe(objectType); -}); - -test(`passes the relativeUrls through`, async () => { - const createJobMock = jest.fn(); - - const relativeUrls = ['/app/kibana#something', '/app/kibana#something-else']; - await compatibilityShim(createJobMock, mockLogger)( - createMockJobParams({ title: 'test', relativeUrls }), - mockRequestHandlerContext - ); - - expect(mockLogger.warn.mock.calls.length).toBe(0); - expect(mockLogger.error.mock.calls.length).toBe(0); - - expect(createJobMock.mock.calls.length).toBe(1); - expect(createJobMock.mock.calls[0][0].relativeUrls).toBe(relativeUrls); -}); - -const testSavedObjectRelativeUrl = (objectType: string, expectedUrl: string) => { - test(`generates the saved object relativeUrl for ${objectType}`, async () => { - const createJobMock = jest.fn(); - - await compatibilityShim(createJobMock, mockLogger)( - createMockJobParams({ title: 'test', objectType, savedObjectId: 'abc' }), - mockRequestHandlerContext - ); - - expect(mockLogger.warn.mock.calls.length).toBe(1); - expect(mockLogger.warn.mock.calls[0][0]).toEqual( - 'The relativeUrls have been derived from saved object parameters. This functionality will be removed with the next major version.' - ); - expect(mockLogger.error.mock.calls.length).toBe(0); - - expect(createJobMock.mock.calls.length).toBe(1); - expect(createJobMock.mock.calls[0][0].relativeUrls).toEqual([expectedUrl]); - }); -}; - -testSavedObjectRelativeUrl('search', '/app/kibana#/discover/abc?'); -testSavedObjectRelativeUrl('visualization', '/app/kibana#/visualize/edit/abc?'); -testSavedObjectRelativeUrl('dashboard', '/app/kibana#/dashboard/abc?'); - -test(`appends the queryString to the relativeUrl when generating from the savedObject`, async () => { - const createJobMock = jest.fn(); - - await compatibilityShim(createJobMock, mockLogger)( - createMockJobParams({ - title: 'test', - objectType: 'search', - savedObjectId: 'abc', - queryString: 'foo=bar', - }), - mockRequestHandlerContext - ); - - expect(mockLogger.warn.mock.calls.length).toBe(1); - expect(mockLogger.warn.mock.calls[0][0]).toEqual( - 'The relativeUrls have been derived from saved object parameters. This functionality will be removed with the next major version.' - ); - expect(mockLogger.error.mock.calls.length).toBe(0); - - expect(createJobMock.mock.calls.length).toBe(1); - expect(createJobMock.mock.calls[0][0].relativeUrls).toEqual([ - '/app/kibana#/discover/abc?foo=bar', - ]); -}); - -test(`throw an Error if the objectType, savedObjectId and relativeUrls are provided`, async () => { - const createJobMock = jest.fn(); - - const promise = compatibilityShim(createJobMock, mockLogger)( - createMockJobParams({ - title: 'test', - objectType: 'something', - relativeUrls: ['/something'], - savedObjectId: 'abc', - }), - mockRequestHandlerContext - ); - - await expect(promise).rejects.toBeDefined(); -}); - -test(`passes headers and request through`, async () => { - const createJobMock = jest.fn(); - - await compatibilityShim(createJobMock, mockLogger)( - createMockJobParams({ title: 'test', relativeUrls: ['/something'] }), - mockRequestHandlerContext - ); - - expect(mockLogger.warn.mock.calls.length).toBe(0); - expect(mockLogger.error.mock.calls.length).toBe(0); - - expect(createJobMock.mock.calls.length).toBe(1); - expect(createJobMock.mock.calls[0][1]).toBe(mockRequestHandlerContext); -}); diff --git a/x-pack/plugins/reporting/server/export_types/printable_pdf/create_job/compatibility_shim.ts b/x-pack/plugins/reporting/server/export_types/printable_pdf/create_job/compatibility_shim.ts deleted file mode 100644 index d5e78bcf68f4bf..00000000000000 --- a/x-pack/plugins/reporting/server/export_types/printable_pdf/create_job/compatibility_shim.ts +++ /dev/null @@ -1,132 +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 type { SavedObjectsClientContract } from 'kibana/server'; -import { url as urlUtils } from '../../../../../../../src/plugins/kibana_utils/server'; -import type { LevelLogger } from '../../../lib'; -import type { CreateJobFn, ReportingRequestHandlerContext } from '../../../types'; -import type { JobParamsPDF, JobParamsPDFLegacy, TaskPayloadPDF } from '../types'; - -function isLegacyJob( - jobParams: JobParamsPDF | JobParamsPDFLegacy -): jobParams is JobParamsPDFLegacy { - return (jobParams as JobParamsPDFLegacy).savedObjectId != null; -} - -const getSavedObjectTitle = async ( - objectType: string, - savedObjectId: string, - savedObjectsClient: SavedObjectsClientContract -) => { - const { saved_object: savedObject } = await savedObjectsClient.resolve<{ title: string }>( - objectType, - savedObjectId - ); - return savedObject.attributes.title; -}; - -const getSavedObjectRelativeUrl = ( - objectType: string, - savedObjectId: string, - queryString: string -) => { - const appPrefixes: Record = { - dashboard: '/dashboard/', - visualization: '/visualize/edit/', - search: '/discover/', - }; - - const appPrefix = appPrefixes[objectType]; - if (!appPrefix) throw new Error('Unexpected app type: ' + objectType); - - const hash = appPrefix + urlUtils.encodeUriQuery(savedObjectId, true); - - return `/app/kibana#${hash}?${queryString || ''}`; -}; - -/* - * The compatibility shim is responsible for migrating an older shape of the - * PDF Job Params into a newer shape, by deriving a report title and relative - * URL from a savedObjectId and queryString. - */ -export function compatibilityShim( - createJobFn: CreateJobFn, - logger: LevelLogger -) { - return async function ( - jobParams: JobParamsPDF | JobParamsPDFLegacy, - context: ReportingRequestHandlerContext - ) { - let kibanaRelativeUrls = (jobParams as JobParamsPDF).relativeUrls; - let reportTitle = jobParams.title; - let isDeprecated = false; - - if ( - (jobParams as JobParamsPDFLegacy).savedObjectId && - (jobParams as JobParamsPDF).relativeUrls - ) { - throw new Error(`savedObjectId should not be provided if relativeUrls are provided`); - } - - if (isLegacyJob(jobParams)) { - const { savedObjectId, objectType, queryString } = jobParams; - - // input validation and deprecation logging - if (typeof savedObjectId !== 'string') { - throw new Error('Invalid savedObjectId (deprecated). String is expected.'); - } - if (typeof objectType !== 'string') { - throw new Error('Invalid objectType (deprecated). String is expected.'); - } - - // legacy parameters need to be converted into a relative URL - kibanaRelativeUrls = [getSavedObjectRelativeUrl(objectType, savedObjectId, queryString)]; - logger.warn( - `The relativeUrls have been derived from saved object parameters. ` + - `This functionality will be removed with the next major version.` - ); - - // legacy parameters might need to get the title from the saved object - if (!reportTitle) { - try { - reportTitle = await getSavedObjectTitle( - objectType, - savedObjectId, - context.core.savedObjects.client - ); - logger.warn( - `The title has been derived from saved object parameters. This ` + - `functionality will be removed with the next major version.` - ); - } catch (err) { - logger.error(err); // 404 for the savedObjectId, etc - throw err; - } - } - - isDeprecated = true; - } - - if (typeof reportTitle !== 'string') { - logger.warn( - `A title parameter should be provided with the job generation ` + - `request. Please use Kibana to regenerate your POST URL to have a ` + - `title included in the PDF.` - ); - reportTitle = ''; - } - - const transformedJobParams: JobParamsPDF = { - ...jobParams, - title: reportTitle, - relativeUrls: kibanaRelativeUrls, - isDeprecated, // tack on this flag so it will be saved the TaskPayload - }; - - return await createJobFn(transformedJobParams, context); - }; -} diff --git a/x-pack/plugins/reporting/server/export_types/printable_pdf/create_job/index.ts b/x-pack/plugins/reporting/server/export_types/printable_pdf/create_job/index.ts index 1a017726207b4e..00702341f0dc9a 100644 --- a/x-pack/plugins/reporting/server/export_types/printable_pdf/create_job/index.ts +++ b/x-pack/plugins/reporting/server/export_types/printable_pdf/create_job/index.ts @@ -7,26 +7,20 @@ import { CreateJobFn, CreateJobFnFactory } from '../../../types'; import { validateUrls } from '../../common'; -import { JobParamsPDF, JobParamsPDFLegacy, TaskPayloadPDF } from '../types'; -import { compatibilityShim } from './compatibility_shim'; +import { JobParamsPDF, TaskPayloadPDF } from '../types'; -/* - * Incoming job params can be `JobParamsPDF` or `JobParamsPDFLegacy` depending - * on the version that the POST URL was copied from. - */ -export const createJobFnFactory: CreateJobFnFactory< - CreateJobFn -> = function createJobFactoryFn(_reporting, logger) { - return compatibilityShim(async function createJobFn( - { relativeUrls, ...jobParams }: JobParamsPDF // relativeUrls does not belong in the payload of PDFV1 - ) { - validateUrls(relativeUrls); +export const createJobFnFactory: CreateJobFnFactory> = + function createJobFactoryFn() { + return async function createJobFn( + { relativeUrls, ...jobParams }: JobParamsPDF // relativeUrls does not belong in the payload of PDFV1 + ) { + validateUrls(relativeUrls); - // return the payload - return { - ...jobParams, - forceNow: new Date().toISOString(), - objects: relativeUrls.map((u) => ({ relativeUrl: u })), + // return the payload + return { + ...jobParams, + forceNow: new Date().toISOString(), + objects: relativeUrls.map((u) => ({ relativeUrl: u })), + }; }; - }, logger); -}; + }; diff --git a/x-pack/plugins/reporting/server/export_types/printable_pdf/types.ts b/x-pack/plugins/reporting/server/export_types/printable_pdf/types.ts index 763fb8942b4707..85ca3802c7755e 100644 --- a/x-pack/plugins/reporting/server/export_types/printable_pdf/types.ts +++ b/x-pack/plugins/reporting/server/export_types/printable_pdf/types.ts @@ -5,4 +5,4 @@ * 2.0. */ -export type { JobParamsPDF, TaskPayloadPDF, JobParamsPDFLegacy } from '../../../common/types'; +export type { JobParamsPDF, TaskPayloadPDF } from '../../../common/types'; diff --git a/x-pack/plugins/reporting/server/routes/lib/request_handler.test.ts b/x-pack/plugins/reporting/server/routes/lib/request_handler.test.ts index 6d73a3ec7ee744..6fdc55346c496c 100644 --- a/x-pack/plugins/reporting/server/routes/lib/request_handler.test.ts +++ b/x-pack/plugins/reporting/server/routes/lib/request_handler.test.ts @@ -110,7 +110,7 @@ describe('Handle request to generate', () => { "kibana_name": undefined, "max_attempts": undefined, "meta": Object { - "isDeprecated": false, + "isDeprecated": undefined, "layout": "preserve_layout", "objectType": "cool_object_type", }, @@ -127,7 +127,6 @@ describe('Handle request to generate', () => { Object { "browserTimezone": "UTC", "headers": "hello mock cypher text", - "isDeprecated": false, "layout": Object { "id": "preserve_layout", }, diff --git a/x-pack/plugins/reporting/server/routes/lib/request_handler.ts b/x-pack/plugins/reporting/server/routes/lib/request_handler.ts index 2100c4c3c43acd..998e8d12076b95 100644 --- a/x-pack/plugins/reporting/server/routes/lib/request_handler.ts +++ b/x-pack/plugins/reporting/server/routes/lib/request_handler.ts @@ -10,7 +10,6 @@ import { i18n } from '@kbn/i18n'; import { KibanaRequest, KibanaResponseFactory } from 'kibana/server'; import { ReportingCore } from '../..'; import { API_BASE_URL } from '../../../common/constants'; -import { JobParamsPDFLegacy } from '../../export_types/printable_pdf/types'; import { checkParamsVersion, cryptoFactory, LevelLogger } from '../../lib'; import { Report } from '../../lib/store'; import { BaseParams, ReportingRequestHandlerContext, ReportingUser } from '../../types'; @@ -103,10 +102,7 @@ export class RequestHandler { return report; } - public async handleGenerateRequest( - exportTypeId: string, - jobParams: BaseParams | JobParamsPDFLegacy - ) { + public async handleGenerateRequest(exportTypeId: string, jobParams: BaseParams) { // ensure the async dependencies are loaded if (!this.context.reporting) { return handleUnavailable(this.res); From 89f86c61877378c3b1f82e8483900ac954474db6 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Wed, 15 Dec 2021 17:00:31 -0700 Subject: [PATCH 02/13] remove supporting files for deprecated type --- .../reporting/server/routes/generate/index.ts | 1 - .../server/routes/generate/legacy.ts | 79 ------------------- .../plugins/reporting/server/routes/index.ts | 2 - .../bwc_generation_urls.ts | 65 --------------- .../reporting_and_security/index.ts | 1 - 5 files changed, 148 deletions(-) delete mode 100644 x-pack/plugins/reporting/server/routes/generate/legacy.ts delete mode 100644 x-pack/test/reporting_api_integration/reporting_and_security/bwc_generation_urls.ts diff --git a/x-pack/plugins/reporting/server/routes/generate/index.ts b/x-pack/plugins/reporting/server/routes/generate/index.ts index 0df9b4a7257686..210abee3e66065 100644 --- a/x-pack/plugins/reporting/server/routes/generate/index.ts +++ b/x-pack/plugins/reporting/server/routes/generate/index.ts @@ -7,4 +7,3 @@ export { registerGenerateCsvFromSavedObjectImmediate } from './csv_searchsource_immediate'; // FIXME: should not need to register each immediate export type separately export { registerJobGenerationRoutes } from './generate_from_jobparams'; -export { registerLegacy } from './legacy'; diff --git a/x-pack/plugins/reporting/server/routes/generate/legacy.ts b/x-pack/plugins/reporting/server/routes/generate/legacy.ts deleted file mode 100644 index f262d186d55317..00000000000000 --- a/x-pack/plugins/reporting/server/routes/generate/legacy.ts +++ /dev/null @@ -1,79 +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 { schema } from '@kbn/config-schema'; -import querystring, { ParsedUrlQueryInput } from 'querystring'; -import { API_BASE_URL } from '../../../common/constants'; -import { ReportingCore } from '../../core'; -import { LevelLogger } from '../../lib'; -import { authorizedUserPreRouting } from '../lib/authorized_user_pre_routing'; -import { RequestHandler } from '../lib/request_handler'; - -const BASE_GENERATE = `${API_BASE_URL}/generate`; - -export function registerLegacy(reporting: ReportingCore, logger: LevelLogger) { - const { router } = reporting.getPluginSetupDeps(); - - function createLegacyPdfRoute({ path, objectType }: { path: string; objectType: string }) { - const exportTypeId = 'printablePdf'; - - router.post( - { - path, - validate: { - params: schema.object({ - savedObjectId: schema.string({ minLength: 3 }), - title: schema.string(), - browserTimezone: schema.string(), - }), - query: schema.maybe(schema.string()), - }, - }, - - authorizedUserPreRouting(reporting, async (user, context, req, res) => { - const requestHandler = new RequestHandler(reporting, user, context, req, res, logger); - const message = `The following URL is deprecated and will stop working in the next major version: ${req.url.pathname}${req.url.search}`; - logger.warn(message, ['deprecation']); - - try { - const { - title, - savedObjectId, - browserTimezone, - }: { title: string; savedObjectId: string; browserTimezone: string } = req.params; - const queryString = querystring.stringify(req.query as ParsedUrlQueryInput | undefined); - - return await requestHandler.handleGenerateRequest(exportTypeId, { - title, - objectType, - savedObjectId, - browserTimezone, - queryString, - version: reporting.getKibanaPackageInfo().version, - }); - } catch (err) { - throw requestHandler.handleError(err); - } - }) - ); - } - - createLegacyPdfRoute({ - path: `${BASE_GENERATE}/visualization/{savedId}`, - objectType: 'visualization', - }); - - createLegacyPdfRoute({ - path: `${BASE_GENERATE}/search/{savedId}`, - objectType: 'search', - }); - - createLegacyPdfRoute({ - path: `${BASE_GENERATE}/dashboard/{savedId}`, - objectType: 'dashboard', - }); -} diff --git a/x-pack/plugins/reporting/server/routes/index.ts b/x-pack/plugins/reporting/server/routes/index.ts index 14a16e563ccbbf..3a49e7dc67e388 100644 --- a/x-pack/plugins/reporting/server/routes/index.ts +++ b/x-pack/plugins/reporting/server/routes/index.ts @@ -12,7 +12,6 @@ import { registerDiagnosticRoutes } from './diagnostic'; import { registerGenerateCsvFromSavedObjectImmediate, registerJobGenerationRoutes, - registerLegacy, } from './generate'; import { registerJobInfoRoutes } from './management'; @@ -21,6 +20,5 @@ export function registerRoutes(reporting: ReportingCore, logger: LevelLogger) { registerDiagnosticRoutes(reporting, logger); registerGenerateCsvFromSavedObjectImmediate(reporting, logger); registerJobGenerationRoutes(reporting, logger); - registerLegacy(reporting, logger); registerJobInfoRoutes(reporting); } diff --git a/x-pack/test/reporting_api_integration/reporting_and_security/bwc_generation_urls.ts b/x-pack/test/reporting_api_integration/reporting_and_security/bwc_generation_urls.ts deleted file mode 100644 index 03e1592df0818a..00000000000000 --- a/x-pack/test/reporting_api_integration/reporting_and_security/bwc_generation_urls.ts +++ /dev/null @@ -1,65 +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 { REPO_ROOT } from '@kbn/utils'; -import pathNode from 'path'; -import { FtrProviderContext } from '../ftr_provider_context'; -import * as GenerationUrls from '../services/generation_urls'; - -const OSS_KIBANA_ARCHIVE_PATH = pathNode.resolve( - REPO_ROOT, - 'test/functional/fixtures/es_archiver/dashboard/current/kibana' -); -const OSS_DATA_ARCHIVE_PATH = pathNode.resolve( - REPO_ROOT, - 'test/functional/fixtures/es_archiver/dashboard/current/data' -); - -// eslint-disable-next-line import/no-default-export -export default function ({ getService }: FtrProviderContext) { - const esArchiver = getService('esArchiver'); - const kibanaServer = getService('kibanaServer'); - const reportingAPI = getService('reportingAPI'); - - describe('BWC report generation urls', () => { - before(async () => { - await esArchiver.load(OSS_KIBANA_ARCHIVE_PATH); - await esArchiver.load(OSS_DATA_ARCHIVE_PATH); - - await kibanaServer.uiSettings.update({ - defaultIndex: '0bf35f60-3dc9-11e8-8660-4d65aa086b3c', - }); - await reportingAPI.deleteAllReports(); - }); - - // FLAKY: https://github.com/elastic/kibana/issues/93354 - describe.skip('Pre 6_2', () => { - // The URL being tested was captured from release 6.4 and then the layout section was removed to test structure before - // preserve_layout was introduced. See https://github.com/elastic/kibana/issues/23414 - it('job posted successfully', async () => { - const path = await reportingAPI.postJob(GenerationUrls.PDF_PRINT_DASHBOARD_PRE_6_2); - await reportingAPI.waitForJobToFinish(path); - }).timeout(500000); - }); - - describe('6_2', () => { - // Might not be great test practice to lump all these jobs together but reporting takes awhile and it'll be - // more efficient to post them all up front, then sequentially. - it('multiple jobs posted', async () => { - const reportPaths = []; - reportPaths.push(await reportingAPI.postJob(GenerationUrls.PDF_PRINT_DASHBOARD_6_2)); - reportPaths.push(await reportingAPI.postJob(GenerationUrls.PDF_PRESERVE_VISUALIZATION_6_2)); - reportPaths.push(await reportingAPI.postJob(GenerationUrls.CSV_DISCOVER_FILTER_QUERY_6_2)); - - await reportingAPI.expectAllJobsToFinishSuccessfully(reportPaths); - }).timeout(1540000); - }); - - // 6.3 urls currently being tested as part of the "bwc_existing_indexes" test suite. Reports are time consuming, - // don't replicate tests if we don't need to, so no specific 6_3 url tests here. - }); -} diff --git a/x-pack/test/reporting_api_integration/reporting_and_security/index.ts b/x-pack/test/reporting_api_integration/reporting_and_security/index.ts index 6ea6de34825012..8b52f5fab304b5 100644 --- a/x-pack/test/reporting_api_integration/reporting_and_security/index.ts +++ b/x-pack/test/reporting_api_integration/reporting_and_security/index.ts @@ -21,7 +21,6 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { await reportingAPI.createTestReportingUser(); }); - loadTestFile(require.resolve('./bwc_generation_urls')); loadTestFile(require.resolve('./bwc_existing_indexes')); loadTestFile(require.resolve('./security_roles_privileges')); loadTestFile(require.resolve('./download_csv_dashboard')); From c4a88932379942771c3e631916cbc79cf724d7d6 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Wed, 15 Dec 2021 17:51:36 -0700 Subject: [PATCH 03/13] cleanup generation URLs that are only used for usage --- .../reporting_and_security/usage.ts | 21 +++++++++----- .../services/generation_urls.ts | 29 ------------------- 2 files changed, 14 insertions(+), 36 deletions(-) delete mode 100644 x-pack/test/reporting_api_integration/services/generation_urls.ts diff --git a/x-pack/test/reporting_api_integration/reporting_and_security/usage.ts b/x-pack/test/reporting_api_integration/reporting_and_security/usage.ts index 4f17d753faf0e9..da6499fbfb4c31 100644 --- a/x-pack/test/reporting_api_integration/reporting_and_security/usage.ts +++ b/x-pack/test/reporting_api_integration/reporting_and_security/usage.ts @@ -7,9 +7,18 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../ftr_provider_context'; -import * as GenerationUrls from '../services/generation_urls'; import { ReportingUsageStats } from '../services/usage'; +// These all have the domain name portion stripped out. The api infrastructure assumes it when we post to it anyhow. +const PDF_PRINT_DASHBOARD_6_3 = + '/api/reporting/generate/printablePdf?jobParams=(browserTimezone:America%2FNew_York,layout:(id:print),objectType:dashboard,relativeUrls:!(%27%2Fapp%2Fkibana%23%2Fdashboard%2F2ae34a60-3dd4-11e8-b2b9-5d5dc1715159%3F_g%3D(refreshInterval:(display:Off,pause:!!f,value:0),time:(from:!%27Mon%2BApr%2B09%2B2018%2B17:56:08%2BGMT-0400!%27,mode:absolute,to:!%27Wed%2BApr%2B11%2B2018%2B17:56:08%2BGMT-0400!%27))%26_a%3D(description:!%27!%27,filters:!!(),fullScreenMode:!!f,options:(hidePanelTitles:!!f,useMargins:!!t),panels:!!((embeddableConfig:(),gridData:(h:15,i:!%271!%27,w:24,x:0,y:0),id:!%27145ced90-3dcb-11e8-8660-4d65aa086b3c!%27,panelIndex:!%271!%27,type:visualization,version:!%276.3.0!%27),(embeddableConfig:(),gridData:(h:15,i:!%272!%27,w:24,x:24,y:0),id:e2023110-3dcb-11e8-8660-4d65aa086b3c,panelIndex:!%272!%27,type:visualization,version:!%276.3.0!%27)),query:(language:lucene,query:!%27!%27),timeRestore:!!f,title:!%27couple%2Bpanels!%27,viewMode:view)%27),title:%27couple%20panels%27)'; +const PDF_PRESERVE_DASHBOARD_FILTER_6_3 = + '/api/reporting/generate/printablePdf?jobParams=(browserTimezone:America%2FNew_York,layout:(dimensions:(height:439,width:1362),id:preserve_layout),objectType:dashboard,relativeUrls:!(%27%2Fapp%2Fkibana%23%2Fdashboard%2F61c58ad0-3dd3-11e8-b2b9-5d5dc1715159%3F_g%3D(refreshInterval:(display:Off,pause:!!f,value:0),time:(from:!%27Mon%2BApr%2B09%2B2018%2B17:56:08%2BGMT-0400!%27,mode:absolute,to:!%27Wed%2BApr%2B11%2B2018%2B17:56:08%2BGMT-0400!%27))%26_a%3D(description:!%27!%27,filters:!!((!%27$state!%27:(store:appState),meta:(alias:!!n,disabled:!!f,index:a0f483a0-3dc9-11e8-8660-4d65aa086b3c,key:animal,negate:!!f,params:(query:dog,type:phrase),type:phrase,value:dog),query:(match:(animal:(query:dog,type:phrase))))),fullScreenMode:!!f,options:(hidePanelTitles:!!f,useMargins:!!t),panels:!!((embeddableConfig:(),gridData:(h:15,i:!%271!%27,w:24,x:0,y:0),id:!%2750643b60-3dd3-11e8-b2b9-5d5dc1715159!%27,panelIndex:!%271!%27,type:visualization,version:!%276.3.0!%27),(embeddableConfig:(),gridData:(h:15,i:!%272!%27,w:24,x:24,y:0),id:a16d1990-3dca-11e8-8660-4d65aa086b3c,panelIndex:!%272!%27,type:search,version:!%276.3.0!%27)),query:(language:lucene,query:!%27!%27),timeRestore:!!t,title:!%27dashboard%2Bwith%2Bfilter!%27,viewMode:view)%27),title:%27dashboard%20with%20filter%27)'; +const PDF_PRESERVE_PIE_VISUALIZATION_6_3 = + '/api/reporting/generate/printablePdf?jobParams=(browserTimezone:America%2FNew_York,layout:(dimensions:(height:441,width:1002),id:preserve_layout),objectType:visualization,relativeUrls:!(%27%2Fapp%2Fkibana%23%2Fvisualize%2Fedit%2F3fe22200-3dcb-11e8-8660-4d65aa086b3c%3F_g%3D(refreshInterval:(display:Off,pause:!!f,value:0),time:(from:!%27Mon%2BApr%2B09%2B2018%2B17:56:08%2BGMT-0400!%27,mode:absolute,to:!%27Wed%2BApr%2B11%2B2018%2B17:56:08%2BGMT-0400!%27))%26_a%3D(filters:!!(),linked:!!f,query:(language:lucene,query:!%27!%27),uiState:(),vis:(aggs:!!((enabled:!!t,id:!%271!%27,params:(),schema:metric,type:count),(enabled:!!t,id:!%272!%27,params:(field:bytes,missingBucket:!!f,missingBucketLabel:Missing,order:desc,orderBy:!%271!%27,otherBucket:!!f,otherBucketLabel:Other,size:5),schema:segment,type:terms)),params:(addLegend:!!t,addTooltip:!!t,isDonut:!!t,labels:(last_level:!!t,show:!!f,truncate:100,values:!!t),legendPosition:right,type:pie),title:!%27Rendering%2BTest:%2Bpie!%27,type:pie))%27),title:%27Rendering%20Test:%20pie%27)'; +const PDF_PRINT_PIE_VISUALIZATION_FILTER_AND_SAVED_SEARCH_6_3 = + '/api/reporting/generate/printablePdf?jobParams=(browserTimezone:America%2FNew_York,layout:(id:print),objectType:visualization,relativeUrls:!(%27%2Fapp%2Fkibana%23%2Fvisualize%2Fedit%2Fbefdb6b0-3e59-11e8-9fc3-39e49624228e%3F_g%3D(refreshInterval:(display:Off,pause:!!f,value:0),time:(from:!%27Mon%2BApr%2B09%2B2018%2B17:56:08%2BGMT-0400!%27,mode:absolute,to:!%27Wed%2BApr%2B11%2B2018%2B17:56:08%2BGMT-0400!%27))%26_a%3D(filters:!!((!%27$state!%27:(store:appState),meta:(alias:!!n,disabled:!!f,index:a0f483a0-3dc9-11e8-8660-4d65aa086b3c,key:animal.keyword,negate:!!f,params:(query:dog,type:phrase),type:phrase,value:dog),query:(match:(animal.keyword:(query:dog,type:phrase))))),linked:!!t,query:(language:lucene,query:!%27!%27),uiState:(),vis:(aggs:!!((enabled:!!t,id:!%271!%27,params:(),schema:metric,type:count),(enabled:!!t,id:!%272!%27,params:(field:name.keyword,missingBucket:!!f,missingBucketLabel:Missing,order:desc,orderBy:!%271!%27,otherBucket:!!f,otherBucketLabel:Other,size:5),schema:segment,type:terms)),params:(addLegend:!!t,addTooltip:!!t,isDonut:!!t,labels:(last_level:!!t,show:!!f,truncate:100,values:!!t),legendPosition:right,type:pie),title:!%27Filter%2BTest:%2Banimals:%2Blinked%2Bto%2Bsearch%2Bwith%2Bfilter!%27,type:pie))%27),title:%27Filter%20Test:%20animals:%20linked%20to%20search%20with%20filter%27)'; + const JOB_PARAMS_CSV_DEFAULT_SPACE = `columns:!(order_date,category,customer_full_name,taxful_total_price,currency),objectType:search,searchSource:(fields:!((field:'*',include_unmapped:true))` + `,filter:!((meta:(field:order_date,index:aac3e500-f2c7-11ea-8250-fb138aa491e7,params:()),query:(range:(order_date:(format:strict_date_optional_time,gte:'2019-06-02T12:28:40.866Z'` + @@ -145,8 +154,8 @@ export default function ({ getService }: FtrProviderContext) { it('should handle preserve_layout pdf', async () => { await reportingAPI.expectAllJobsToFinishSuccessfully( await Promise.all([ - reportingAPI.postJob(GenerationUrls.PDF_PRESERVE_DASHBOARD_FILTER_6_3), - reportingAPI.postJob(GenerationUrls.PDF_PRESERVE_PIE_VISUALIZATION_6_3), + reportingAPI.postJob(PDF_PRESERVE_DASHBOARD_FILTER_6_3), + reportingAPI.postJob(PDF_PRESERVE_PIE_VISUALIZATION_6_3), ]) ); @@ -162,10 +171,8 @@ export default function ({ getService }: FtrProviderContext) { it('should handle print_layout pdf', async () => { await reportingAPI.expectAllJobsToFinishSuccessfully( await Promise.all([ - reportingAPI.postJob(GenerationUrls.PDF_PRINT_DASHBOARD_6_3), - reportingAPI.postJob( - GenerationUrls.PDF_PRINT_PIE_VISUALIZATION_FILTER_AND_SAVED_SEARCH_6_3 - ), + reportingAPI.postJob(PDF_PRINT_DASHBOARD_6_3), + reportingAPI.postJob(PDF_PRINT_PIE_VISUALIZATION_FILTER_AND_SAVED_SEARCH_6_3), ]) ); diff --git a/x-pack/test/reporting_api_integration/services/generation_urls.ts b/x-pack/test/reporting_api_integration/services/generation_urls.ts deleted file mode 100644 index d5cf96d9116286..00000000000000 --- a/x-pack/test/reporting_api_integration/services/generation_urls.ts +++ /dev/null @@ -1,29 +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. - */ - -// These all have the domain name portion stripped out. The api infrastructure assumes it when we post to it anyhow. - -// The URL below was captured from release 6.4 and then the layout section was removed to test structure before -// preserve_layout was introduced. See https://github.com/elastic/kibana/issues/23414 -export const PDF_PRINT_DASHBOARD_PRE_6_2 = - '/api/reporting/generate/printablePdf?jobParams=(browserTimezone:America%2FNew_York,objectType:dashboard,relativeUrls:!(%27%2Fapp%2Fkibana%23%2Fdashboard%2F2ae34a60-3dd4-11e8-b2b9-5d5dc1715159%3F_g%3D(refreshInterval:(pause:!!t,value:0),time:(from:!%27Mon%2BApr%2B09%2B2018%2B17:56:08%2BGMT-0400!%27,mode:absolute,to:!%27Wed%2BApr%2B11%2B2018%2B17:56:08%2BGMT-0400!%27))%26_a%3D(description:!%27!%27,filters:!!(),fullScreenMode:!!f,options:(hidePanelTitles:!!f,useMargins:!!t),panels:!!((embeddableConfig:(),gridData:(h:15,i:!%271!%27,w:24,x:0,y:0),id:!%27145ced90-3dcb-11e8-8660-4d65aa086b3c!%27,panelIndex:!%271!%27,type:visualization,version:!%276.3.0!%27),(embeddableConfig:(),gridData:(h:15,i:!%272!%27,w:24,x:24,y:0),id:e2023110-3dcb-11e8-8660-4d65aa086b3c,panelIndex:!%272!%27,type:visualization,version:!%276.3.0!%27)),query:(language:lucene,query:!%27!%27),timeRestore:!!f,title:!%27couple%2Bpanels!%27,viewMode:view)%27),title:%27couple%20panels%27)'; - -export const PDF_PRINT_DASHBOARD_6_3 = - '/api/reporting/generate/printablePdf?jobParams=(browserTimezone:America%2FNew_York,layout:(id:print),objectType:dashboard,relativeUrls:!(%27%2Fapp%2Fkibana%23%2Fdashboard%2F2ae34a60-3dd4-11e8-b2b9-5d5dc1715159%3F_g%3D(refreshInterval:(display:Off,pause:!!f,value:0),time:(from:!%27Mon%2BApr%2B09%2B2018%2B17:56:08%2BGMT-0400!%27,mode:absolute,to:!%27Wed%2BApr%2B11%2B2018%2B17:56:08%2BGMT-0400!%27))%26_a%3D(description:!%27!%27,filters:!!(),fullScreenMode:!!f,options:(hidePanelTitles:!!f,useMargins:!!t),panels:!!((embeddableConfig:(),gridData:(h:15,i:!%271!%27,w:24,x:0,y:0),id:!%27145ced90-3dcb-11e8-8660-4d65aa086b3c!%27,panelIndex:!%271!%27,type:visualization,version:!%276.3.0!%27),(embeddableConfig:(),gridData:(h:15,i:!%272!%27,w:24,x:24,y:0),id:e2023110-3dcb-11e8-8660-4d65aa086b3c,panelIndex:!%272!%27,type:visualization,version:!%276.3.0!%27)),query:(language:lucene,query:!%27!%27),timeRestore:!!f,title:!%27couple%2Bpanels!%27,viewMode:view)%27),title:%27couple%20panels%27)'; -export const PDF_PRESERVE_DASHBOARD_FILTER_6_3 = - '/api/reporting/generate/printablePdf?jobParams=(browserTimezone:America%2FNew_York,layout:(dimensions:(height:439,width:1362),id:preserve_layout),objectType:dashboard,relativeUrls:!(%27%2Fapp%2Fkibana%23%2Fdashboard%2F61c58ad0-3dd3-11e8-b2b9-5d5dc1715159%3F_g%3D(refreshInterval:(display:Off,pause:!!f,value:0),time:(from:!%27Mon%2BApr%2B09%2B2018%2B17:56:08%2BGMT-0400!%27,mode:absolute,to:!%27Wed%2BApr%2B11%2B2018%2B17:56:08%2BGMT-0400!%27))%26_a%3D(description:!%27!%27,filters:!!((!%27$state!%27:(store:appState),meta:(alias:!!n,disabled:!!f,index:a0f483a0-3dc9-11e8-8660-4d65aa086b3c,key:animal,negate:!!f,params:(query:dog,type:phrase),type:phrase,value:dog),query:(match:(animal:(query:dog,type:phrase))))),fullScreenMode:!!f,options:(hidePanelTitles:!!f,useMargins:!!t),panels:!!((embeddableConfig:(),gridData:(h:15,i:!%271!%27,w:24,x:0,y:0),id:!%2750643b60-3dd3-11e8-b2b9-5d5dc1715159!%27,panelIndex:!%271!%27,type:visualization,version:!%276.3.0!%27),(embeddableConfig:(),gridData:(h:15,i:!%272!%27,w:24,x:24,y:0),id:a16d1990-3dca-11e8-8660-4d65aa086b3c,panelIndex:!%272!%27,type:search,version:!%276.3.0!%27)),query:(language:lucene,query:!%27!%27),timeRestore:!!t,title:!%27dashboard%2Bwith%2Bfilter!%27,viewMode:view)%27),title:%27dashboard%20with%20filter%27)'; -export const PDF_PRESERVE_PIE_VISUALIZATION_6_3 = - '/api/reporting/generate/printablePdf?jobParams=(browserTimezone:America%2FNew_York,layout:(dimensions:(height:441,width:1002),id:preserve_layout),objectType:visualization,relativeUrls:!(%27%2Fapp%2Fkibana%23%2Fvisualize%2Fedit%2F3fe22200-3dcb-11e8-8660-4d65aa086b3c%3F_g%3D(refreshInterval:(display:Off,pause:!!f,value:0),time:(from:!%27Mon%2BApr%2B09%2B2018%2B17:56:08%2BGMT-0400!%27,mode:absolute,to:!%27Wed%2BApr%2B11%2B2018%2B17:56:08%2BGMT-0400!%27))%26_a%3D(filters:!!(),linked:!!f,query:(language:lucene,query:!%27!%27),uiState:(),vis:(aggs:!!((enabled:!!t,id:!%271!%27,params:(),schema:metric,type:count),(enabled:!!t,id:!%272!%27,params:(field:bytes,missingBucket:!!f,missingBucketLabel:Missing,order:desc,orderBy:!%271!%27,otherBucket:!!f,otherBucketLabel:Other,size:5),schema:segment,type:terms)),params:(addLegend:!!t,addTooltip:!!t,isDonut:!!t,labels:(last_level:!!t,show:!!f,truncate:100,values:!!t),legendPosition:right,type:pie),title:!%27Rendering%2BTest:%2Bpie!%27,type:pie))%27),title:%27Rendering%20Test:%20pie%27)'; -export const PDF_PRINT_PIE_VISUALIZATION_FILTER_AND_SAVED_SEARCH_6_3 = - '/api/reporting/generate/printablePdf?jobParams=(browserTimezone:America%2FNew_York,layout:(id:print),objectType:visualization,relativeUrls:!(%27%2Fapp%2Fkibana%23%2Fvisualize%2Fedit%2Fbefdb6b0-3e59-11e8-9fc3-39e49624228e%3F_g%3D(refreshInterval:(display:Off,pause:!!f,value:0),time:(from:!%27Mon%2BApr%2B09%2B2018%2B17:56:08%2BGMT-0400!%27,mode:absolute,to:!%27Wed%2BApr%2B11%2B2018%2B17:56:08%2BGMT-0400!%27))%26_a%3D(filters:!!((!%27$state!%27:(store:appState),meta:(alias:!!n,disabled:!!f,index:a0f483a0-3dc9-11e8-8660-4d65aa086b3c,key:animal.keyword,negate:!!f,params:(query:dog,type:phrase),type:phrase,value:dog),query:(match:(animal.keyword:(query:dog,type:phrase))))),linked:!!t,query:(language:lucene,query:!%27!%27),uiState:(),vis:(aggs:!!((enabled:!!t,id:!%271!%27,params:(),schema:metric,type:count),(enabled:!!t,id:!%272!%27,params:(field:name.keyword,missingBucket:!!f,missingBucketLabel:Missing,order:desc,orderBy:!%271!%27,otherBucket:!!f,otherBucketLabel:Other,size:5),schema:segment,type:terms)),params:(addLegend:!!t,addTooltip:!!t,isDonut:!!t,labels:(last_level:!!t,show:!!f,truncate:100,values:!!t),legendPosition:right,type:pie),title:!%27Filter%2BTest:%2Banimals:%2Blinked%2Bto%2Bsearch%2Bwith%2Bfilter!%27,type:pie))%27),title:%27Filter%20Test:%20animals:%20linked%20to%20search%20with%20filter%27)'; - -export const PDF_PRINT_DASHBOARD_6_2 = - '/api/reporting/generate/printablePdf?jobParams=(browserTimezone:America%2FNew_York,layout:(id:print),objectType:dashboard,queryString:%27_g%3D(refreshInterval:(display:Off,pause:!!f,value:0),time:(from:!%27Mon%2BApr%2B09%2B2018%2B17:56:08%2BGMT-0400!%27,mode:absolute,to:!%27Wed%2BApr%2B11%2B2018%2B17:56:08%2BGMT-0400!%27))%26_a%3D(description:!%27!%27,filters:!!((!%27$state!%27:(store:appState),meta:(alias:!!n,disabled:!!f,field:isDog,index:a0f483a0-3dc9-11e8-8660-4d65aa086b3c,key:isDog,negate:!!f,params:(value:!!t),type:phrase,value:true),script:(script:(inline:!%27boolean%2Bcompare(Supplier%2Bs,%2Bdef%2Bv)%2B%257Breturn%2Bs.get()%2B%253D%253D%2Bv%3B%257Dcompare(()%2B-%253E%2B%257B%2Breturn%2Bdoc%255B!!!%27animal.keyword!!!%27%255D.value%2B%253D%253D%2B!!!%27dog!!!%27%2B%257D,%2Bparams.value)%3B!%27,lang:painless,params:(value:!!t))))),fullScreenMode:!!f,options:(hidePanelTitles:!!f,useMargins:!!t),panels:!!((gridData:(h:3,i:!%274!%27,w:6,x:6,y:0),id:edb65990-53ca-11e8-b481-c9426d020fcd,panelIndex:!%274!%27,type:visualization,version:!%276.2.4!%27),(gridData:(h:3,i:!%275!%27,w:6,x:0,y:0),id:!%270644f890-53cb-11e8-b481-c9426d020fcd!%27,panelIndex:!%275!%27,type:visualization,version:!%276.2.4!%27)),query:(language:lucene,query:!%27weightLbs:%253E15!%27),timeRestore:!!t,title:!%27Animal%2BWeights%2B(created%2Bin%2B6.2)!%27,viewMode:view)%27,savedObjectId:%271b2f47b0-53cb-11e8-b481-c9426d020fcd%27)'; -export const PDF_PRESERVE_VISUALIZATION_6_2 = - '/api/reporting/generate/printablePdf?jobParams=(browserTimezone:America%2FNew_York,layout:(dimensions:(height:441,width:1002),id:preserve_layout),objectType:visualization,queryString:%27_g%3D(refreshInterval:(display:Off,pause:!!f,value:0),time:(from:!%27Mon%2BApr%2B09%2B2018%2B17:56:08%2BGMT-0400!%27,mode:absolute,to:!%27Wed%2BApr%2B11%2B2018%2B17:56:08%2BGMT-0400!%27))%26_a%3D(filters:!!(),linked:!!f,query:(language:lucene,query:!%27weightLbs:%253E10!%27),uiState:(),vis:(aggs:!!((enabled:!!t,id:!%271!%27,params:(),schema:metric,type:count),(enabled:!!t,id:!%272!%27,params:(field:weightLbs,missingBucket:!!f,missingBucketLabel:Missing,order:desc,orderBy:!%271!%27,otherBucket:!!f,otherBucketLabel:Other,size:5),schema:segment,type:terms)),params:(addLegend:!!t,addTooltip:!!t,isDonut:!!t,labels:(last_level:!!t,show:!!f,truncate:100,values:!!t),legendPosition:right,type:pie),title:!%27Weight%2Bin%2Blbs%2Bpie%2Bcreated%2Bin%2B6.2!%27,type:pie))%27,savedObjectId:%270644f890-53cb-11e8-b481-c9426d020fcd%27)'; -export const CSV_DISCOVER_FILTER_QUERY_6_2 = - '/api/reporting/generate/csv?jobParams=(conflictedTypesFields:!(),fields:!(%27@timestamp%27,animal,sound,weightLbs),indexPatternId:a0f483a0-3dc9-11e8-8660-4d65aa086b3c,metaFields:!(_source,_id,_type,_index,_score),searchRequest:(body:(_source:(excludes:!(),includes:!(%27@timestamp%27,animal,sound,weightLbs)),docvalue_fields:!(%27@timestamp%27),query:(bool:(filter:!(),must:!((query_string:(analyze_wildcard:!t,default_field:%27*%27,query:%27weightLbs:%3E10%27)),(match_phrase:(sound.keyword:(query:growl))),(range:(%27@timestamp%27:(format:epoch_millis,gte:1523310968000,lte:1523483768000)))),must_not:!(),should:!())),script_fields:(),sort:!((%27@timestamp%27:(order:desc,unmapped_type:boolean))),stored_fields:!(%27@timestamp%27,animal,sound,weightLbs),version:!t),index:%27animals-*%27),title:%27Search%20created%20in%206.2%27,type:search)'; From 7a328d3ac7a633fcd2af25842a1396fd219fd614 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Thu, 16 Dec 2021 10:37:31 -0700 Subject: [PATCH 04/13] remove legacy csv export type --- x-pack/plugins/reporting/README.md | 33 +- .../common/types/export_types/csv.ts | 63 - .../common/types/export_types/index.ts | 1 - .../server/export_types/csv/create_job.ts | 24 - .../export_types/csv/execute_job.test.ts | 1189 ----------------- .../server/export_types/csv/execute_job.ts | 48 - .../check_cells_for_formulas.test.ts | 98 -- .../generate_csv/check_cells_for_formulas.ts | 20 - .../csv/generate_csv/field_format_map.test.ts | 56 - .../csv/generate_csv/field_format_map.ts | 59 - .../csv/generate_csv/flatten_hit.test.ts | 153 --- .../csv/generate_csv/flatten_hit.ts | 66 - .../generate_csv/format_csv_values.test.ts | 88 -- .../csv/generate_csv/format_csv_values.ts | 46 - .../csv/generate_csv/get_ui_settings.ts | 59 - .../csv/generate_csv/hit_iterator.test.ts | 189 --- .../csv/generate_csv/hit_iterator.ts | 110 -- .../export_types/csv/generate_csv/index.ts | 163 --- .../server/export_types/csv/index.ts | 40 - .../server/export_types/csv/metadata.ts | 11 - .../server/export_types/csv/types.ts | 14 - .../server/lib/check_license.test.ts | 24 +- .../server/lib/export_types_registry.ts | 2 - .../reporting/server/lib/store/store.test.ts | 4 +- .../server/routes/lib/request_handler.test.ts | 15 +- .../reporting_usage_collector.test.ts.snap | 164 +-- .../server/usage/get_export_stats.test.ts | 62 +- .../usage/reporting_usage_collector.test.ts | 36 +- .../plugins/reporting/server/usage/types.ts | 1 - .../generate_csv_discover_deprecated.ts | 75 -- .../reporting_and_security/index.ts | 1 - .../reporting_without_security/index.ts | 1 - .../job_apis_csv_deprecated.ts | 189 --- .../services/fixtures.ts | 42 - .../reporting_without_security/management.ts | 26 +- 35 files changed, 82 insertions(+), 3090 deletions(-) delete mode 100644 x-pack/plugins/reporting/common/types/export_types/csv.ts delete mode 100644 x-pack/plugins/reporting/server/export_types/csv/create_job.ts delete mode 100644 x-pack/plugins/reporting/server/export_types/csv/execute_job.test.ts delete mode 100644 x-pack/plugins/reporting/server/export_types/csv/execute_job.ts delete mode 100644 x-pack/plugins/reporting/server/export_types/csv/generate_csv/check_cells_for_formulas.test.ts delete mode 100644 x-pack/plugins/reporting/server/export_types/csv/generate_csv/check_cells_for_formulas.ts delete mode 100644 x-pack/plugins/reporting/server/export_types/csv/generate_csv/field_format_map.test.ts delete mode 100644 x-pack/plugins/reporting/server/export_types/csv/generate_csv/field_format_map.ts delete mode 100644 x-pack/plugins/reporting/server/export_types/csv/generate_csv/flatten_hit.test.ts delete mode 100644 x-pack/plugins/reporting/server/export_types/csv/generate_csv/flatten_hit.ts delete mode 100644 x-pack/plugins/reporting/server/export_types/csv/generate_csv/format_csv_values.test.ts delete mode 100644 x-pack/plugins/reporting/server/export_types/csv/generate_csv/format_csv_values.ts delete mode 100644 x-pack/plugins/reporting/server/export_types/csv/generate_csv/get_ui_settings.ts delete mode 100644 x-pack/plugins/reporting/server/export_types/csv/generate_csv/hit_iterator.test.ts delete mode 100644 x-pack/plugins/reporting/server/export_types/csv/generate_csv/hit_iterator.ts delete mode 100644 x-pack/plugins/reporting/server/export_types/csv/generate_csv/index.ts delete mode 100644 x-pack/plugins/reporting/server/export_types/csv/index.ts delete mode 100644 x-pack/plugins/reporting/server/export_types/csv/metadata.ts delete mode 100644 x-pack/plugins/reporting/server/export_types/csv/types.ts delete mode 100644 x-pack/test/reporting_api_integration/reporting_and_security/generate_csv_discover_deprecated.ts delete mode 100644 x-pack/test/reporting_api_integration/reporting_without_security/job_apis_csv_deprecated.ts delete mode 100644 x-pack/test/reporting_api_integration/services/fixtures.ts diff --git a/x-pack/plugins/reporting/README.md b/x-pack/plugins/reporting/README.md index bae359b03c8414..40cedae7b3623a 100644 --- a/x-pack/plugins/reporting/README.md +++ b/x-pack/plugins/reporting/README.md @@ -1,34 +1,3 @@ # Kibana Reporting -An awesome Kibana reporting plugin - -# Development - -Assuming you've checked out x-plugins next to kibana... - -- Run `yarn kbn bootstrap` -- Run `yarn start` to watch for and sync files on change -- Open a new terminal to run Kibana - use `yarn start` to launch it in dev mode - - Kibana will automatically restart as files are synced - - If you need debugging output, run `DEBUG=reporting yarn start` instead - -If you have installed this somewhere other than via x-plugins, and next to the kibana repo, you'll need to change the `pathToKibana` setting in `gulpfile.js` - -# Conventions - -This plugins adopts some conventions in addition to or in place of conventions in Kibana (at the time of the plugin's creation): - -## Folder structure -``` -export_types/ (contains public and server aspects of the different export types) - printable_pdf/ - public/ - server/ - csv/ - public/ - server/ -public/ (shared public code for all export types) -server/ (shared server code for all export types) -``` - -This folder structure treats the different export_types like Plugins, with their public/server code being separate in a folder. \ No newline at end of file +An awesome Kibana reporting plugin \ No newline at end of file diff --git a/x-pack/plugins/reporting/common/types/export_types/csv.ts b/x-pack/plugins/reporting/common/types/export_types/csv.ts deleted file mode 100644 index 8249c129052d75..00000000000000 --- a/x-pack/plugins/reporting/common/types/export_types/csv.ts +++ /dev/null @@ -1,63 +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 { BaseParams, BasePayload } from '../base'; - -export type RawValue = string | object | null | undefined; - -interface BaseParamsDeprecatedCSV { - searchRequest: SearchRequestDeprecatedCSV; - fields: string[]; - metaFields: string[]; - conflictedTypesFields: string[]; -} - -export type JobParamsDeprecatedCSV = BaseParamsDeprecatedCSV & - BaseParams & { - indexPatternId: string; - }; - -export type TaskPayloadDeprecatedCSV = BaseParamsDeprecatedCSV & - BasePayload & { - indexPatternId: string; - }; - -export interface SearchRequestDeprecatedCSV { - index: string; - body: - | { - _source: { - excludes: string[]; - includes: string[]; - }; - docvalue_fields: string[]; - query: - | { - bool: { - filter: any[]; - must_not: any[]; - should: any[]; - must: any[]; - }; - } - | any; - script_fields: any; - sort: Array<{ - [key: string]: { - order: string; - }; - }>; - stored_fields: string[]; - } - | any; -} - -export interface SavedSearchGeneratorResultDeprecatedCSV { - maxSizeReached: boolean; - csvContainsFormulas?: boolean; - warnings: string[]; -} diff --git a/x-pack/plugins/reporting/common/types/export_types/index.ts b/x-pack/plugins/reporting/common/types/export_types/index.ts index 0ad47e74140317..e475f6a3ebd376 100644 --- a/x-pack/plugins/reporting/common/types/export_types/index.ts +++ b/x-pack/plugins/reporting/common/types/export_types/index.ts @@ -5,7 +5,6 @@ * 2.0. */ -export * from './csv'; export * from './csv_searchsource'; export * from './csv_searchsource_immediate'; export * from './png'; diff --git a/x-pack/plugins/reporting/server/export_types/csv/create_job.ts b/x-pack/plugins/reporting/server/export_types/csv/create_job.ts deleted file mode 100644 index 9ebfc2c57e3455..00000000000000 --- a/x-pack/plugins/reporting/server/export_types/csv/create_job.ts +++ /dev/null @@ -1,24 +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 { CreateJobFn, CreateJobFnFactory } from '../../types'; -import { JobParamsDeprecatedCSV, TaskPayloadDeprecatedCSV } from './types'; - -export const createJobFnFactory: CreateJobFnFactory< - CreateJobFn -> = function createJobFactoryFn(reporting, logger) { - return async function createJob(jobParams, context) { - logger.warn( - `The "/generate/csv" endpoint is deprecated. Please recreate the POST URL used to automate this CSV export.` - ); - - return { - isDeprecated: true, - ...jobParams, - }; - }; -}; diff --git a/x-pack/plugins/reporting/server/export_types/csv/execute_job.test.ts b/x-pack/plugins/reporting/server/export_types/csv/execute_job.test.ts deleted file mode 100644 index 6af186fa6baf61..00000000000000 --- a/x-pack/plugins/reporting/server/export_types/csv/execute_job.test.ts +++ /dev/null @@ -1,1189 +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 { Writable } from 'stream'; -import type { DeeplyMockedKeys } from '@kbn/utility-types/jest'; -import nodeCrypto from '@elastic/node-crypto'; -import { ElasticsearchClient, IUiSettingsClient } from 'kibana/server'; -import moment from 'moment'; -import Puid from 'puid'; -import sinon from 'sinon'; -import type { DataView, DataViewsService } from 'src/plugins/data/common'; -import { ReportingConfig, ReportingCore } from '../../'; -import { - FieldFormatsRegistry, - StringFormat, - FORMATS_UI_SETTINGS, -} from '../../../../../../src/plugins/field_formats/common'; -import { - CSV_QUOTE_VALUES_SETTING, - CSV_SEPARATOR_SETTING, -} from '../../../../../../src/plugins/share/server'; -import { CancellationToken } from '../../../common'; -import { CSV_BOM_CHARS } from '../../../common/constants'; -import { LevelLogger } from '../../lib'; -import { setFieldFormats } from '../../services'; -import { createMockConfigSchema, createMockReportingCore } from '../../test_helpers'; -import { runTaskFnFactory } from './execute_job'; -import { TaskPayloadDeprecatedCSV } from './types'; - -const delay = (ms: number) => new Promise((resolve) => setTimeout(() => resolve(), ms)); - -const puid = new Puid(); -const getRandomScrollId = () => { - return puid.generate(); -}; - -const getBasePayload = (baseObj: any) => baseObj as TaskPayloadDeprecatedCSV; - -describe('CSV Execute Job', function () { - const encryptionKey = 'testEncryptionKey'; - const headers = { - sid: 'test', - }; - const mockLogger = new LevelLogger({ - get: () => - ({ - debug: jest.fn(), - warn: jest.fn(), - error: jest.fn(), - } as any), - }); - let defaultElasticsearchResponse: any; - let encryptedHeaders: any; - - let configGetStub: any; - let mockDataView: jest.Mocked; - let mockDataViewsService: jest.Mocked; - let mockEsClient: DeeplyMockedKeys; - let mockReportingConfig: ReportingConfig; - let mockReportingCore: ReportingCore; - let cancellationToken: any; - let stream: jest.Mocked; - let content: string; - - const mockUiSettingsClient = { - get: sinon.stub(), - }; - - beforeAll(async function () { - const crypto = nodeCrypto({ encryptionKey }); - encryptedHeaders = await crypto.encrypt(headers); - }); - - beforeEach(async function () { - content = ''; - stream = { write: jest.fn((chunk) => (content += chunk)) } as unknown as typeof stream; - configGetStub = sinon.stub(); - configGetStub.withArgs('queue', 'timeout').returns(moment.duration('2m')); - configGetStub.withArgs('encryptionKey').returns(encryptionKey); - configGetStub.withArgs('csv', 'maxSizeBytes').returns(1024 * 1000); // 1mB - configGetStub.withArgs('csv', 'scroll').returns({}); - mockReportingConfig = { get: configGetStub, kbnConfig: { get: configGetStub } }; - mockDataView = { fieldFormatMap: {}, fields: [] } as unknown as typeof mockDataView; - mockDataViewsService = { - get: jest.fn().mockResolvedValue(mockDataView), - } as unknown as typeof mockDataViewsService; - - mockReportingCore = await createMockReportingCore(createMockConfigSchema()); - mockReportingCore.getUiSettingsServiceFactory = () => - Promise.resolve(mockUiSettingsClient as unknown as IUiSettingsClient); - mockReportingCore.getDataViewsService = jest.fn().mockResolvedValue(mockDataViewsService); - mockReportingCore.setConfig(mockReportingConfig); - - mockEsClient = (await mockReportingCore.getEsClient()).asScoped({} as any) - .asCurrentUser as typeof mockEsClient; - cancellationToken = new CancellationToken(); - - defaultElasticsearchResponse = { - hits: { - hits: [], - }, - _scroll_id: 'defaultScrollId', - }; - - mockEsClient.search.mockResolvedValue({ body: defaultElasticsearchResponse } as any); - mockEsClient.scroll.mockResolvedValue({ body: defaultElasticsearchResponse } as any); - mockUiSettingsClient.get.withArgs(CSV_SEPARATOR_SETTING).returns(','); - mockUiSettingsClient.get.withArgs(CSV_QUOTE_VALUES_SETTING).returns(true); - - setFieldFormats({ - fieldFormatServiceFactory() { - const uiConfigMock = {}; - (uiConfigMock as any)[FORMATS_UI_SETTINGS.FORMAT_DEFAULT_TYPE_MAP] = { - _default_: { id: 'string', params: {} }, - }; - - const fieldFormatsRegistry = new FieldFormatsRegistry(); - - fieldFormatsRegistry.init((key) => (uiConfigMock as any)[key], {}, [StringFormat]); - - return Promise.resolve(fieldFormatsRegistry); - }, - }); - }); - - describe('basic Elasticsearch call behavior', function () { - it('should decrypt encrypted headers and pass to the elasticsearch client', async function () { - const runTask = runTaskFnFactory(mockReportingCore, mockLogger); - await runTask( - 'job456', - getBasePayload({ - headers: encryptedHeaders, - fields: [], - searchRequest: { index: null, body: null }, - }), - cancellationToken, - stream - ); - expect(mockEsClient.search).toHaveBeenCalled(); - }); - - it('should pass the index and body to execute the initial search', async function () { - const index = 'index'; - const body = { - testBody: true, - }; - - const runTask = runTaskFnFactory(mockReportingCore, mockLogger); - const job = getBasePayload({ - headers: encryptedHeaders, - fields: [], - searchRequest: { - index, - body, - }, - }); - - await runTask('job777', job, cancellationToken, stream); - - expect(mockEsClient.search).toHaveBeenCalledWith(expect.objectContaining({ body, index })); - }); - - it('should pass the scrollId from the initial search to the subsequent scroll', async function () { - const scrollId = getRandomScrollId(); - - mockEsClient.search.mockResolvedValueOnce({ - body: { - hits: { - hits: [{}], - }, - _scroll_id: scrollId, - }, - } as any); - mockEsClient.scroll.mockResolvedValue({ body: defaultElasticsearchResponse } as any); - - const runTask = runTaskFnFactory(mockReportingCore, mockLogger); - await runTask( - 'job456', - getBasePayload({ - headers: encryptedHeaders, - fields: [], - searchRequest: { index: null, body: null }, - }), - cancellationToken, - stream - ); - - expect(mockEsClient.scroll).toHaveBeenCalledWith( - expect.objectContaining({ scroll_id: scrollId }) - ); - }); - - it('should not execute scroll if there are no hits from the search', async function () { - const runTask = runTaskFnFactory(mockReportingCore, mockLogger); - await runTask( - 'job456', - getBasePayload({ - headers: encryptedHeaders, - fields: [], - searchRequest: { index: null, body: null }, - }), - cancellationToken, - stream - ); - - expect(mockEsClient.search).toHaveBeenCalled(); - expect(mockEsClient.clearScroll).toHaveBeenCalled(); - }); - - it('should stop executing scroll if there are no hits', async function () { - mockEsClient.search.mockResolvedValueOnce({ - body: { - hits: { - hits: [{}], - }, - _scroll_id: 'scrollId', - }, - } as any); - mockEsClient.scroll.mockResolvedValueOnce({ - body: { - hits: { - hits: [], - }, - _scroll_id: 'scrollId', - }, - } as any); - - const runTask = runTaskFnFactory(mockReportingCore, mockLogger); - await runTask( - 'job456', - getBasePayload({ - headers: encryptedHeaders, - fields: [], - searchRequest: { index: null, body: null }, - }), - cancellationToken, - stream - ); - - expect(mockEsClient.search).toHaveBeenCalled(); - expect(mockEsClient.scroll).toHaveBeenCalled(); - expect(mockEsClient.clearScroll).toHaveBeenCalled(); - }); - - it('should call clearScroll with scrollId when there are no more hits', async function () { - const lastScrollId = getRandomScrollId(); - mockEsClient.search.mockResolvedValueOnce({ - body: { - hits: { - hits: [{}], - }, - _scroll_id: 'scrollId', - }, - } as any); - - mockEsClient.scroll.mockResolvedValueOnce({ - body: { - hits: { - hits: [], - }, - _scroll_id: lastScrollId, - }, - } as any); - - const runTask = runTaskFnFactory(mockReportingCore, mockLogger); - await runTask( - 'job456', - getBasePayload({ - headers: encryptedHeaders, - fields: [], - searchRequest: { index: null, body: null }, - }), - cancellationToken, - stream - ); - - expect(mockEsClient.clearScroll).toHaveBeenCalledWith( - expect.objectContaining({ scroll_id: lastScrollId }) - ); - }); - - it('calls clearScroll when there is an error iterating the hits', async function () { - const lastScrollId = getRandomScrollId(); - mockEsClient.search.mockResolvedValueOnce({ - body: { - hits: { - hits: [ - { - _source: { - one: 'foo', - two: 'bar', - }, - }, - ], - }, - _scroll_id: lastScrollId, - }, - } as any); - - const runTask = runTaskFnFactory(mockReportingCore, mockLogger); - const jobParams = getBasePayload({ - headers: encryptedHeaders, - fields: ['one', 'two'], - conflictedTypesFields: undefined, - searchRequest: { index: null, body: null }, - }); - await expect( - runTask('job123', jobParams, cancellationToken, stream) - ).rejects.toMatchInlineSnapshot( - `[TypeError: Cannot read properties of undefined (reading 'indexOf')]` - ); - - expect(mockEsClient.clearScroll).toHaveBeenCalledWith( - expect.objectContaining({ scroll_id: lastScrollId }) - ); - }); - }); - - describe('Warning when cells have formulas', () => { - it('returns `csv_contains_formulas` when cells contain formulas', async function () { - configGetStub.withArgs('csv', 'checkForFormulas').returns(true); - mockEsClient.search.mockResolvedValueOnce({ - body: { - hits: { - hits: [{ _source: { one: '=SUM(A1:A2)', two: 'bar' } }], - }, - _scroll_id: 'scrollId', - }, - } as any); - - const runTask = runTaskFnFactory(mockReportingCore, mockLogger); - const jobParams = getBasePayload({ - headers: encryptedHeaders, - fields: ['one', 'two'], - conflictedTypesFields: [], - searchRequest: { index: null, body: null }, - }); - const { csv_contains_formulas: csvContainsFormulas } = await runTask( - 'job123', - jobParams, - cancellationToken, - stream - ); - - expect(csvContainsFormulas).toEqual(true); - }); - - it('returns warnings when headings contain formulas', async function () { - configGetStub.withArgs('csv', 'checkForFormulas').returns(true); - mockEsClient.search.mockResolvedValueOnce({ - body: { - hits: { - hits: [{ _source: { '=SUM(A1:A2)': 'foo', two: 'bar' } }], - }, - _scroll_id: 'scrollId', - }, - } as any); - - const runTask = runTaskFnFactory(mockReportingCore, mockLogger); - const jobParams = getBasePayload({ - headers: encryptedHeaders, - fields: ['=SUM(A1:A2)', 'two'], - conflictedTypesFields: [], - searchRequest: { index: null, body: null }, - }); - const { csv_contains_formulas: csvContainsFormulas } = await runTask( - 'job123', - jobParams, - cancellationToken, - stream - ); - - expect(csvContainsFormulas).toEqual(true); - }); - - it('returns no warnings when cells have no formulas', async function () { - configGetStub.withArgs('csv', 'checkForFormulas').returns(true); - configGetStub.withArgs('csv', 'escapeFormulaValues').returns(false); - mockEsClient.search.mockResolvedValueOnce({ - body: { - hits: { - hits: [{ _source: { one: 'foo', two: 'bar' } }], - }, - _scroll_id: 'scrollId', - }, - } as any); - - const runTask = runTaskFnFactory(mockReportingCore, mockLogger); - const jobParams = getBasePayload({ - headers: encryptedHeaders, - fields: ['one', 'two'], - conflictedTypesFields: [], - searchRequest: { index: null, body: null }, - }); - const { csv_contains_formulas: csvContainsFormulas } = await runTask( - 'job123', - jobParams, - cancellationToken, - stream - ); - - expect(csvContainsFormulas).toEqual(false); - }); - - it('returns no warnings when cells have formulas but are escaped', async function () { - configGetStub.withArgs('csv', 'checkForFormulas').returns(true); - configGetStub.withArgs('csv', 'escapeFormulaValues').returns(true); - mockEsClient.search.mockResolvedValueOnce({ - body: { - hits: { - hits: [{ _source: { '=SUM(A1:A2)': 'foo', two: 'bar' } }], - }, - _scroll_id: 'scrollId', - }, - } as any); - - const runTask = runTaskFnFactory(mockReportingCore, mockLogger); - const jobParams = getBasePayload({ - headers: encryptedHeaders, - fields: ['=SUM(A1:A2)', 'two'], - conflictedTypesFields: [], - searchRequest: { index: null, body: null }, - }); - - const { csv_contains_formulas: csvContainsFormulas } = await runTask( - 'job123', - jobParams, - cancellationToken, - stream - ); - - expect(csvContainsFormulas).toEqual(false); - }); - - it('returns no warnings when configured not to', async () => { - configGetStub.withArgs('csv', 'checkForFormulas').returns(false); - mockEsClient.search.mockResolvedValueOnce({ - body: { - hits: { - hits: [{ _source: { one: '=SUM(A1:A2)', two: 'bar' } }], - }, - _scroll_id: 'scrollId', - }, - } as any); - - const runTask = runTaskFnFactory(mockReportingCore, mockLogger); - const jobParams = getBasePayload({ - headers: encryptedHeaders, - fields: ['one', 'two'], - conflictedTypesFields: [], - searchRequest: { index: null, body: null }, - }); - const { csv_contains_formulas: csvContainsFormulas } = await runTask( - 'job123', - jobParams, - cancellationToken, - stream - ); - - expect(csvContainsFormulas).toEqual(false); - }); - }); - - describe('Byte order mark encoding', () => { - it('encodes CSVs with BOM', async () => { - configGetStub.withArgs('csv', 'useByteOrderMarkEncoding').returns(true); - mockEsClient.search.mockResolvedValueOnce({ - body: { - hits: { - hits: [{ _source: { one: 'one', two: 'bar' } }], - }, - _scroll_id: 'scrollId', - }, - } as any); - - const runTask = runTaskFnFactory(mockReportingCore, mockLogger); - const jobParams = getBasePayload({ - headers: encryptedHeaders, - fields: ['one', 'two'], - conflictedTypesFields: [], - searchRequest: { index: null, body: null }, - }); - await runTask('job123', jobParams, cancellationToken, stream); - - expect(content).toEqual(`${CSV_BOM_CHARS}one,two\none,bar\n`); - }); - - it('encodes CSVs without BOM', async () => { - configGetStub.withArgs('csv', 'useByteOrderMarkEncoding').returns(false); - mockEsClient.search.mockResolvedValueOnce({ - body: { - hits: { - hits: [{ _source: { one: 'one', two: 'bar' } }], - }, - _scroll_id: 'scrollId', - }, - } as any); - - const runTask = runTaskFnFactory(mockReportingCore, mockLogger); - const jobParams = getBasePayload({ - headers: encryptedHeaders, - fields: ['one', 'two'], - conflictedTypesFields: [], - searchRequest: { index: null, body: null }, - }); - await runTask('job123', jobParams, cancellationToken, stream); - - expect(content).toEqual('one,two\none,bar\n'); - }); - }); - - describe('Escaping cells with formulas', () => { - it('escapes values with formulas', async () => { - configGetStub.withArgs('csv', 'escapeFormulaValues').returns(true); - mockEsClient.search.mockResolvedValueOnce({ - body: { - hits: { - hits: [{ _source: { one: `=cmd|' /C calc'!A0`, two: 'bar' } }], - }, - _scroll_id: 'scrollId', - }, - } as any); - - const runTask = runTaskFnFactory(mockReportingCore, mockLogger); - const jobParams = getBasePayload({ - headers: encryptedHeaders, - fields: ['one', 'two'], - conflictedTypesFields: [], - searchRequest: { index: null, body: null }, - }); - await runTask('job123', jobParams, cancellationToken, stream); - - expect(content).toEqual("one,two\n\"'=cmd|' /C calc'!A0\",bar\n"); - }); - - it('does not escapes values with formulas', async () => { - configGetStub.withArgs('csv', 'escapeFormulaValues').returns(false); - mockEsClient.search.mockResolvedValueOnce({ - body: { - hits: { - hits: [{ _source: { one: `=cmd|' /C calc'!A0`, two: 'bar' } }], - }, - _scroll_id: 'scrollId', - }, - } as any); - - const runTask = runTaskFnFactory(mockReportingCore, mockLogger); - const jobParams = getBasePayload({ - headers: encryptedHeaders, - fields: ['one', 'two'], - conflictedTypesFields: [], - searchRequest: { index: null, body: null }, - }); - await runTask('job123', jobParams, cancellationToken, stream); - - expect(content).toEqual('one,two\n"=cmd|\' /C calc\'!A0",bar\n'); - }); - }); - - describe('Elasticsearch call errors', function () { - it('should reject Promise if search call errors out', async function () { - mockEsClient.search.mockRejectedValueOnce(new Error()); - const runTask = runTaskFnFactory(mockReportingCore, mockLogger); - const jobParams = getBasePayload({ - headers: encryptedHeaders, - fields: [], - searchRequest: { index: null, body: null }, - }); - await expect( - runTask('job123', jobParams, cancellationToken, stream) - ).rejects.toMatchInlineSnapshot(`[Error]`); - }); - - it('should reject Promise if scroll call errors out', async function () { - mockEsClient.search.mockResolvedValueOnce({ - body: { - hits: { - hits: [{}], - }, - _scroll_id: 'scrollId', - }, - } as any); - mockEsClient.scroll.mockRejectedValueOnce(new Error()); - const runTask = runTaskFnFactory(mockReportingCore, mockLogger); - const jobParams = getBasePayload({ - headers: encryptedHeaders, - fields: [], - searchRequest: { index: null, body: null }, - }); - await expect( - runTask('job123', jobParams, cancellationToken, stream) - ).rejects.toMatchInlineSnapshot(`[Error]`); - }); - }); - - describe('invalid responses', function () { - it('should reject Promise if search returns hits but no _scroll_id', async function () { - mockEsClient.search.mockResolvedValueOnce({ - body: { - hits: { - hits: [{}], - }, - _scroll_id: undefined, - }, - } as any); - - const runTask = runTaskFnFactory(mockReportingCore, mockLogger); - const jobParams = getBasePayload({ - headers: encryptedHeaders, - fields: [], - searchRequest: { index: null, body: null }, - }); - await expect( - runTask('job123', jobParams, cancellationToken, stream) - ).rejects.toMatchInlineSnapshot( - `[Error: Expected _scroll_id in the following Elasticsearch response: {"hits":{"hits":[{}]}}]` - ); - }); - - it('should reject Promise if search returns no hits and no _scroll_id', async function () { - mockEsClient.search.mockResolvedValueOnce({ - body: { - hits: { - hits: [], - }, - _scroll_id: undefined, - }, - } as any); - - const runTask = runTaskFnFactory(mockReportingCore, mockLogger); - const jobParams = getBasePayload({ - headers: encryptedHeaders, - fields: [], - searchRequest: { index: null, body: null }, - }); - await expect( - runTask('job123', jobParams, cancellationToken, stream) - ).rejects.toMatchInlineSnapshot( - `[Error: Expected _scroll_id in the following Elasticsearch response: {"hits":{"hits":[]}}]` - ); - }); - - it('should reject Promise if scroll returns hits but no _scroll_id', async function () { - mockEsClient.search.mockResolvedValueOnce({ - body: { - hits: { - hits: [{}], - }, - _scroll_id: 'scrollId', - }, - } as any); - - mockEsClient.scroll.mockResolvedValueOnce({ - body: { - hits: { - hits: [{}], - }, - _scroll_id: undefined, - }, - } as any); - - const runTask = runTaskFnFactory(mockReportingCore, mockLogger); - const jobParams = getBasePayload({ - headers: encryptedHeaders, - fields: [], - searchRequest: { index: null, body: null }, - }); - await expect( - runTask('job123', jobParams, cancellationToken, stream) - ).rejects.toMatchInlineSnapshot( - `[Error: Expected _scroll_id in the following Elasticsearch response: {"hits":{"hits":[{}]}}]` - ); - }); - - it('should reject Promise if scroll returns no hits and no _scroll_id', async function () { - mockEsClient.search.mockResolvedValueOnce({ - body: { - hits: { - hits: [{}], - }, - _scroll_id: 'scrollId', - }, - } as any); - - mockEsClient.scroll.mockResolvedValueOnce({ - body: { - hits: { - hits: [], - }, - _scroll_id: undefined, - }, - } as any); - - const runTask = runTaskFnFactory(mockReportingCore, mockLogger); - const jobParams = getBasePayload({ - headers: encryptedHeaders, - fields: [], - searchRequest: { index: null, body: null }, - }); - await expect( - runTask('job123', jobParams, cancellationToken, stream) - ).rejects.toMatchInlineSnapshot( - `[Error: Expected _scroll_id in the following Elasticsearch response: {"hits":{"hits":[]}}]` - ); - }); - }); - - describe('cancellation', function () { - const scrollId = getRandomScrollId(); - - beforeEach(function () { - const searchStub = async () => { - await delay(1); - return { - body: { - hits: { - hits: [{}], - }, - _scroll_id: scrollId, - }, - }; - }; - - mockEsClient.search.mockImplementation(searchStub as typeof mockEsClient.search); - mockEsClient.scroll.mockImplementation(searchStub as typeof mockEsClient.scroll); - }); - - it('should stop calling Elasticsearch when cancellationToken.cancel is called', async function () { - const runTask = runTaskFnFactory(mockReportingCore, mockLogger); - runTask( - 'job345', - getBasePayload({ - headers: encryptedHeaders, - fields: [], - searchRequest: { index: null, body: null }, - }), - cancellationToken, - stream - ); - - await delay(250); - - expect(mockEsClient.search).toHaveBeenCalled(); - expect(mockEsClient.scroll).toHaveBeenCalled(); - expect(mockEsClient.clearScroll).not.toHaveBeenCalled(); - - cancellationToken.cancel(); - await delay(250); - - expect(mockEsClient.clearScroll).toHaveBeenCalled(); - }); - - it(`shouldn't call clearScroll if it never got a scrollId`, async function () { - const runTask = runTaskFnFactory(mockReportingCore, mockLogger); - runTask( - 'job345', - getBasePayload({ - headers: encryptedHeaders, - fields: [], - searchRequest: { index: null, body: null }, - }), - cancellationToken, - stream - ); - cancellationToken.cancel(); - - expect(mockEsClient.clearScroll).not.toHaveBeenCalled(); - }); - - it('should call clearScroll if it got a scrollId', async function () { - const runTask = runTaskFnFactory(mockReportingCore, mockLogger); - runTask( - 'job345', - getBasePayload({ - headers: encryptedHeaders, - fields: [], - searchRequest: { index: null, body: null }, - }), - cancellationToken, - stream - ); - await delay(100); - cancellationToken.cancel(); - await delay(100); - - expect(mockEsClient.clearScroll).toHaveBeenCalledWith( - expect.objectContaining({ scroll_id: scrollId }) - ); - }); - }); - - describe('csv content', function () { - it('should write column headers to output, even if there are no results', async function () { - const runTask = runTaskFnFactory(mockReportingCore, mockLogger); - const jobParams = getBasePayload({ - headers: encryptedHeaders, - fields: ['one', 'two'], - searchRequest: { index: null, body: null }, - }); - await runTask('job123', jobParams, cancellationToken, stream); - expect(content).toBe(`one,two\n`); - }); - - it('should use custom uiSettings csv:separator for header', async function () { - mockUiSettingsClient.get.withArgs(CSV_SEPARATOR_SETTING).returns(';'); - const runTask = runTaskFnFactory(mockReportingCore, mockLogger); - const jobParams = getBasePayload({ - headers: encryptedHeaders, - fields: ['one', 'two'], - searchRequest: { index: null, body: null }, - }); - await runTask('job123', jobParams, cancellationToken, stream); - expect(content).toBe(`one;two\n`); - }); - - it('should escape column headers if uiSettings csv:quoteValues is true', async function () { - mockUiSettingsClient.get.withArgs(CSV_QUOTE_VALUES_SETTING).returns(true); - const runTask = runTaskFnFactory(mockReportingCore, mockLogger); - const jobParams = getBasePayload({ - headers: encryptedHeaders, - fields: ['one and a half', 'two', 'three-and-four', 'five & six'], - searchRequest: { index: null, body: null }, - }); - await runTask('job123', jobParams, cancellationToken, stream); - expect(content).toBe(`"one and a half",two,"three-and-four","five & six"\n`); - }); - - it(`shouldn't escape column headers if uiSettings csv:quoteValues is false`, async function () { - mockUiSettingsClient.get.withArgs(CSV_QUOTE_VALUES_SETTING).returns(false); - const runTask = runTaskFnFactory(mockReportingCore, mockLogger); - const jobParams = getBasePayload({ - headers: encryptedHeaders, - fields: ['one and a half', 'two', 'three-and-four', 'five & six'], - searchRequest: { index: null, body: null }, - }); - await runTask('job123', jobParams, cancellationToken, stream); - expect(content).toBe(`one and a half,two,three-and-four,five & six\n`); - }); - - it('should write column headers to output, when there are results', async function () { - const runTask = runTaskFnFactory(mockReportingCore, mockLogger); - mockEsClient.search.mockResolvedValueOnce({ - body: { - hits: { - hits: [{ one: '1', two: '2' }], - }, - _scroll_id: 'scrollId', - }, - } as any); - - const jobParams = getBasePayload({ - headers: encryptedHeaders, - fields: ['one', 'two'], - searchRequest: { index: null, body: null }, - }); - await runTask('job123', jobParams, cancellationToken, stream); - expect(content).not.toBe(null); - const lines = content!.split('\n'); - const headerLine = lines[0]; - expect(headerLine).toBe('one,two'); - }); - - it('should use comma separated values of non-nested fields from _source', async function () { - const runTask = runTaskFnFactory(mockReportingCore, mockLogger); - mockEsClient.search.mockResolvedValueOnce({ - body: { - hits: { - hits: [{ _source: { one: 'foo', two: 'bar' } }], - }, - _scroll_id: 'scrollId', - }, - } as any); - - const jobParams = getBasePayload({ - headers: encryptedHeaders, - fields: ['one', 'two'], - conflictedTypesFields: [], - searchRequest: { index: null, body: null }, - }); - await runTask('job123', jobParams, cancellationToken, stream); - expect(content).not.toBe(null); - const lines = content!.split('\n'); - const valuesLine = lines[1]; - expect(valuesLine).toBe('foo,bar'); - }); - - it('should concatenate the hits from multiple responses', async function () { - const runTask = runTaskFnFactory(mockReportingCore, mockLogger); - mockEsClient.search.mockResolvedValueOnce({ - body: { - hits: { - hits: [{ _source: { one: 'foo', two: 'bar' } }], - }, - _scroll_id: 'scrollId', - }, - } as any); - mockEsClient.scroll.mockResolvedValueOnce({ - body: { - hits: { - hits: [{ _source: { one: 'baz', two: 'qux' } }], - }, - _scroll_id: 'scrollId', - }, - } as any); - - const jobParams = getBasePayload({ - headers: encryptedHeaders, - fields: ['one', 'two'], - conflictedTypesFields: [], - searchRequest: { index: null, body: null }, - }); - await runTask('job123', jobParams, cancellationToken, stream); - expect(content).not.toBe(null); - const lines = content!.split('\n'); - - expect(lines[1]).toBe('foo,bar'); - expect(lines[2]).toBe('baz,qux'); - }); - - it('should use field formatters to format fields', async function () { - const runTask = runTaskFnFactory(mockReportingCore, mockLogger); - mockEsClient.search.mockResolvedValueOnce({ - body: { - hits: { - hits: [{ _source: { one: 'foo', two: 'bar' } }], - }, - _scroll_id: 'scrollId', - }, - } as any); - - const jobParams = getBasePayload({ - headers: encryptedHeaders, - fields: ['one', 'two'], - conflictedTypesFields: [], - searchRequest: { index: null, body: null }, - indexPatternId: 'something', - }); - - mockDataView.fieldFormatMap = { one: { id: 'string', params: { transform: 'upper' } } }; - mockDataView.fields = [ - { name: 'one', type: 'string' }, - { name: 'two', type: 'string' }, - ] as typeof mockDataView.fields; - await runTask('job123', jobParams, cancellationToken, stream); - expect(content).not.toBe(null); - const lines = content!.split('\n'); - - expect(lines[1]).toBe('FOO,bar'); - }); - }); - - describe('maxSizeBytes', function () { - // The following tests use explicitly specified lengths. UTF-8 uses between one and four 8-bit bytes for each - // code-point. However, any character that can be represented by ASCII requires one-byte, so a majority of the - // tests use these 'simple' characters to make the math easier - - describe('when only the headers exceed the maxSizeBytes', function () { - let maxSizeReached: boolean | undefined; - - beforeEach(async function () { - configGetStub.withArgs('csv', 'maxSizeBytes').returns(1); - - const runTask = runTaskFnFactory(mockReportingCore, mockLogger); - const jobParams = getBasePayload({ - headers: encryptedHeaders, - fields: ['one', 'two'], - searchRequest: { index: null, body: null }, - }); - - ({ max_size_reached: maxSizeReached } = await runTask( - 'job123', - jobParams, - cancellationToken, - stream - )); - }); - - it('should return max_size_reached', function () { - expect(maxSizeReached).toBe(true); - }); - - it('should return empty content', function () { - expect(content).toBe(''); - }); - }); - - describe('when headers are equal to maxSizeBytes', function () { - let maxSizeReached: boolean | undefined; - - beforeEach(async function () { - configGetStub.withArgs('csv', 'maxSizeBytes').returns(9); - - const runTask = runTaskFnFactory(mockReportingCore, mockLogger); - const jobParams = getBasePayload({ - headers: encryptedHeaders, - fields: ['one', 'two'], - searchRequest: { index: null, body: null }, - }); - - ({ max_size_reached: maxSizeReached } = await runTask( - 'job123', - jobParams, - cancellationToken, - stream - )); - }); - - it(`shouldn't return max_size_reached`, function () { - expect(maxSizeReached).toBe(false); - }); - - it(`should return content`, function () { - expect(content).toBe('one,two\n'); - }); - }); - - describe('when the data exceeds the maxSizeBytes', function () { - let maxSizeReached: boolean | undefined; - - beforeEach(async function () { - configGetStub.withArgs('csv', 'maxSizeBytes').returns(9); - - mockEsClient.search.mockResolvedValueOnce({ - body: { - hits: { - hits: [{ _source: { one: 'foo', two: 'bar' } }], - }, - _scroll_id: 'scrollId', - }, - } as any); - - const runTask = runTaskFnFactory(mockReportingCore, mockLogger); - const jobParams = getBasePayload({ - headers: encryptedHeaders, - fields: ['one', 'two'], - conflictedTypesFields: [], - searchRequest: { index: null, body: null }, - }); - - ({ max_size_reached: maxSizeReached } = await runTask( - 'job123', - jobParams, - cancellationToken, - stream - )); - }); - - it(`should return max_size_reached`, function () { - expect(maxSizeReached).toBe(true); - }); - - it(`should return the headers in the content`, function () { - expect(content).toBe('one,two\n'); - }); - }); - - describe('when headers and data equal the maxSizeBytes', function () { - let maxSizeReached: boolean | undefined; - - beforeEach(async function () { - mockReportingCore.getUiSettingsServiceFactory = () => - Promise.resolve(mockUiSettingsClient as unknown as IUiSettingsClient); - configGetStub.withArgs('csv', 'maxSizeBytes').returns(18); - - mockEsClient.search.mockResolvedValueOnce({ - body: { - hits: { - hits: [{ _source: { one: 'foo', two: 'bar' } }], - }, - _scroll_id: 'scrollId', - }, - } as any); - - const runTask = runTaskFnFactory(mockReportingCore, mockLogger); - const jobParams = getBasePayload({ - headers: encryptedHeaders, - fields: ['one', 'two'], - conflictedTypesFields: [], - searchRequest: { index: null, body: null }, - }); - - ({ max_size_reached: maxSizeReached } = await runTask( - 'job123', - jobParams, - cancellationToken, - stream - )); - }); - - it(`shouldn't return max_size_reached`, async function () { - expect(maxSizeReached).toBe(false); - }); - - it('should return headers and data in content', function () { - expect(content).toBe('one,two\nfoo,bar\n'); - }); - }); - }); - - describe('scroll settings', function () { - it('passes scroll duration to initial search call', async function () { - const scrollDuration = 'test'; - configGetStub.withArgs('csv', 'scroll').returns({ duration: scrollDuration }); - - mockEsClient.search.mockResolvedValueOnce({ - body: { - hits: { - hits: [{}], - }, - _scroll_id: 'scrollId', - }, - } as any); - - const runTask = runTaskFnFactory(mockReportingCore, mockLogger); - const jobParams = getBasePayload({ - headers: encryptedHeaders, - fields: ['one', 'two'], - conflictedTypesFields: [], - searchRequest: { index: null, body: null }, - }); - - await runTask('job123', jobParams, cancellationToken, stream); - - expect(mockEsClient.search).toHaveBeenCalledWith( - expect.objectContaining({ scroll: scrollDuration }) - ); - }); - - it('passes scroll size to initial search call', async function () { - const scrollSize = 100; - configGetStub.withArgs('csv', 'scroll').returns({ size: scrollSize }); - - mockEsClient.search.mockResolvedValueOnce({ - body: { - hits: { - hits: [{}], - }, - _scroll_id: 'scrollId', - }, - } as any); - - const runTask = runTaskFnFactory(mockReportingCore, mockLogger); - const jobParams = getBasePayload({ - headers: encryptedHeaders, - fields: ['one', 'two'], - conflictedTypesFields: [], - searchRequest: { index: null, body: null }, - }); - - await runTask('job123', jobParams, cancellationToken, stream); - - expect(mockEsClient.search).toHaveBeenCalledWith( - expect.objectContaining({ size: scrollSize }) - ); - }); - - it('passes scroll duration to subsequent scroll call', async function () { - const scrollDuration = 'test'; - configGetStub.withArgs('csv', 'scroll').returns({ duration: scrollDuration }); - - mockEsClient.search.mockResolvedValueOnce({ - body: { - hits: { - hits: [{}], - }, - _scroll_id: 'scrollId', - }, - } as any); - - const runTask = runTaskFnFactory(mockReportingCore, mockLogger); - const jobParams = getBasePayload({ - headers: encryptedHeaders, - fields: ['one', 'two'], - conflictedTypesFields: [], - searchRequest: { index: null, body: null }, - }); - - await runTask('job123', jobParams, cancellationToken, stream); - - expect(mockEsClient.scroll).toHaveBeenCalledWith( - expect.objectContaining({ scroll: scrollDuration, scroll_id: 'scrollId' }) - ); - }); - }); -}); diff --git a/x-pack/plugins/reporting/server/export_types/csv/execute_job.ts b/x-pack/plugins/reporting/server/export_types/csv/execute_job.ts deleted file mode 100644 index a0075918219883..00000000000000 --- a/x-pack/plugins/reporting/server/export_types/csv/execute_job.ts +++ /dev/null @@ -1,48 +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 { CONTENT_TYPE_CSV } from '../../../common/constants'; -import { RunTaskFn, RunTaskFnFactory } from '../../types'; -import { decryptJobHeaders } from '../common'; -import { createGenerateCsv } from './generate_csv'; -import { TaskPayloadDeprecatedCSV } from './types'; - -export const runTaskFnFactory: RunTaskFnFactory> = - function executeJobFactoryFn(reporting, parentLogger) { - const config = reporting.getConfig(); - - return async function runTask(jobId, job, cancellationToken, stream) { - const elasticsearch = await reporting.getEsClient(); - const logger = parentLogger.clone([jobId]); - const generateCsv = createGenerateCsv(logger); - - const encryptionKey = config.get('encryptionKey'); - const headers = await decryptJobHeaders(encryptionKey, job.headers, logger); - const fakeRequest = reporting.getFakeRequest({ headers }, job.spaceId, logger); - const uiSettingsClient = await reporting.getUiSettingsClient(fakeRequest, logger); - const { asCurrentUser: elasticsearchClient } = elasticsearch.asScoped(fakeRequest); - const dataViews = await reporting.getDataViewsService(fakeRequest); - - const { maxSizeReached, csvContainsFormulas, warnings } = await generateCsv( - job, - config, - uiSettingsClient, - elasticsearchClient, - dataViews, - cancellationToken, - stream - ); - - // @TODO: Consolidate these one-off warnings into the warnings array (max-size reached and csv contains formulas) - return { - content_type: CONTENT_TYPE_CSV, - max_size_reached: maxSizeReached, - csv_contains_formulas: csvContainsFormulas, - warnings, - }; - }; - }; diff --git a/x-pack/plugins/reporting/server/export_types/csv/generate_csv/check_cells_for_formulas.test.ts b/x-pack/plugins/reporting/server/export_types/csv/generate_csv/check_cells_for_formulas.test.ts deleted file mode 100644 index 021cb6b1349e13..00000000000000 --- a/x-pack/plugins/reporting/server/export_types/csv/generate_csv/check_cells_for_formulas.test.ts +++ /dev/null @@ -1,98 +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 { checkIfRowsHaveFormulas } from './check_cells_for_formulas'; - -const formulaValues = ['=', '+', '-', '@']; -const nonRows = [null, undefined, 9, () => {}]; - -describe(`Check CSV Injected values`, () => { - it(`returns 'false' when there's no formula values in cells`, () => { - expect( - checkIfRowsHaveFormulas( - { - _doc: 'foo-bar', - value: 'cool', - title: 'nice', - }, - ['_doc', 'value', 'title'] - ) - ).toBe(false); - }); - - formulaValues.forEach((formula) => { - it(`returns 'true' when cells start with "${formula}"`, () => { - expect( - checkIfRowsHaveFormulas( - { - _doc: 'foo-bar', - value: formula, - title: 'nice', - }, - ['_doc', 'value', 'title'] - ) - ).toBe(true); - }); - - it(`returns 'false' when cells start with "${formula}" but aren't selected`, () => { - expect( - checkIfRowsHaveFormulas( - { - _doc: 'foo-bar', - value: formula, - title: 'nice', - }, - ['_doc', 'title'] - ) - ).toBe(false); - }); - }); - - formulaValues.forEach((formula) => { - it(`returns 'true' when headers start with "${formula}"`, () => { - expect( - checkIfRowsHaveFormulas( - { - _doc: 'foo-bar', - [formula]: 'baz', - title: 'nice', - }, - ['_doc', formula, 'title'] - ) - ).toBe(true); - }); - - it(`returns 'false' when headers start with "${formula}" but aren't selected in fields`, () => { - expect( - checkIfRowsHaveFormulas( - { - _doc: 'foo-bar', - [formula]: 'baz', - title: 'nice', - }, - ['_doc', 'title'] - ) - ).toBe(false); - }); - }); - - nonRows.forEach((nonRow) => { - it(`returns false when there's "${nonRow}" for rows`, () => { - expect( - checkIfRowsHaveFormulas( - { - _doc: 'foo-bar', - // need to assert non-string values still return false - value: nonRow as unknown as string, - title: 'nice', - }, - ['_doc', 'value', 'title'] - ) - ).toBe(false); - }); - }); -}); diff --git a/x-pack/plugins/reporting/server/export_types/csv/generate_csv/check_cells_for_formulas.ts b/x-pack/plugins/reporting/server/export_types/csv/generate_csv/check_cells_for_formulas.ts deleted file mode 100644 index 709c0ccd67e9ce..00000000000000 --- a/x-pack/plugins/reporting/server/export_types/csv/generate_csv/check_cells_for_formulas.ts +++ /dev/null @@ -1,20 +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 { pick, keys, values, some } from 'lodash'; -import { cellHasFormulas } from '../../../../../../../src/plugins/data/common'; - -interface IFlattened { - [header: string]: string; -} - -export const checkIfRowsHaveFormulas = (flattened: IFlattened, fields: string[]) => { - const pruned = pick(flattened, fields); - const cells = [...keys(pruned), ...(values(pruned) as string[])]; - - return some(cells, (cell) => cellHasFormulas(cell)); -}; diff --git a/x-pack/plugins/reporting/server/export_types/csv/generate_csv/field_format_map.test.ts b/x-pack/plugins/reporting/server/export_types/csv/generate_csv/field_format_map.test.ts deleted file mode 100644 index 67a3dd17894d14..00000000000000 --- a/x-pack/plugins/reporting/server/export_types/csv/generate_csv/field_format_map.test.ts +++ /dev/null @@ -1,56 +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 type { DataView } from 'src/plugins/data/common'; -import { - FieldFormatsGetConfigFn, - FieldFormatsRegistry, - BytesFormat, - NumberFormat, - FORMATS_UI_SETTINGS, -} from 'src/plugins/field_formats/common'; -import { fieldFormatMapFactory } from './field_format_map'; - -type ConfigValue = { number: { id: string; params: {} } } | string; - -describe('field format map', function () { - const dataView = { - fields: [ - { name: 'field1', type: 'number' }, - { name: 'field2', type: 'number' }, - ], - fieldFormatMap: { field1: { id: 'bytes', params: { pattern: '0,0.[0]b' } } }, - } as unknown as DataView; - const configMock: Record = {}; - configMock[FORMATS_UI_SETTINGS.FORMAT_DEFAULT_TYPE_MAP] = { - number: { id: 'number', params: {} }, - }; - configMock[FORMATS_UI_SETTINGS.FORMAT_NUMBER_DEFAULT_PATTERN] = '0,0.[000]'; - const getConfig = ((key: string) => configMock[key]) as FieldFormatsGetConfigFn; - const testValue = '4000'; - const mockTimezone = 'Browser'; - - const fieldFormatsRegistry = new FieldFormatsRegistry(); - fieldFormatsRegistry.init(getConfig, {}, [BytesFormat, NumberFormat]); - - const formatMap = fieldFormatMapFactory(dataView, fieldFormatsRegistry, mockTimezone); - - it('should build field format map with entry per data view field', function () { - expect(formatMap.has('field1')).to.be(true); - expect(formatMap.has('field2')).to.be(true); - expect(formatMap.has('field_not_in_index')).to.be(false); - }); - - it('should create custom FieldFormat for fields with configured field formatter', function () { - expect(formatMap.get('field1')!.convert(testValue)).to.be('3.9KB'); - }); - - it('should create default FieldFormat for fields with no field formatter', function () { - expect(formatMap.get('field2')!.convert(testValue)).to.be('4,000'); - }); -}); diff --git a/x-pack/plugins/reporting/server/export_types/csv/generate_csv/field_format_map.ts b/x-pack/plugins/reporting/server/export_types/csv/generate_csv/field_format_map.ts deleted file mode 100644 index 38a6cac3378615..00000000000000 --- a/x-pack/plugins/reporting/server/export_types/csv/generate_csv/field_format_map.ts +++ /dev/null @@ -1,59 +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 _ from 'lodash'; -import type { DataView, KBN_FIELD_TYPES } from 'src/plugins/data/common'; -import { - FieldFormat, - IFieldFormatsRegistry, - FieldFormatConfig, -} from 'src/plugins/field_formats/common'; -/** - * Create a map of FieldFormat instances for index pattern fields - * - * @param {DataView} dataView - * @param {FieldFormatsService} fieldFormats - * @return {Map} key: field name, value: FieldFormat instance - */ -export function fieldFormatMapFactory( - dataView: DataView | undefined, - fieldFormatsRegistry: IFieldFormatsRegistry, - timezone: string | undefined -) { - const formatsMap = new Map(); - - // From here, the browser timezone can't be determined, so we accept a - // timezone field from job params posted to the API. Here is where it gets used. - const serverDateParams = { timezone }; - - // Add FieldFormat instances for fields with custom formatters - if (dataView) { - Object.keys(dataView.fieldFormatMap).forEach((fieldName) => { - const formatConfig: FieldFormatConfig = dataView.fieldFormatMap[fieldName]; - const formatParams = { - ...formatConfig.params, - ...serverDateParams, - }; - - if (!_.isEmpty(formatConfig)) { - formatsMap.set(fieldName, fieldFormatsRegistry.getInstance(formatConfig.id, formatParams)); - } - }); - } - - // Add default FieldFormat instances for non-custom formatted fields - dataView?.fields.forEach((field) => { - if (!formatsMap.has(field.name)) { - formatsMap.set( - field.name, - fieldFormatsRegistry.getDefaultInstance(field.type as KBN_FIELD_TYPES, [], serverDateParams) - ); - } - }); - - return formatsMap; -} diff --git a/x-pack/plugins/reporting/server/export_types/csv/generate_csv/flatten_hit.test.ts b/x-pack/plugins/reporting/server/export_types/csv/generate_csv/flatten_hit.test.ts deleted file mode 100644 index c3130cfcdbb5de..00000000000000 --- a/x-pack/plugins/reporting/server/export_types/csv/generate_csv/flatten_hit.test.ts +++ /dev/null @@ -1,153 +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 { createFlattenHit } from './flatten_hit'; - -type Hit = Record; - -describe('flattenHit', function () { - let flattenHit: (hit: Hit) => Record; - let hit: Hit; - let metaFields: string[]; - - beforeEach(function () { - const fields = [ - 'tags.text', - 'tags.label', - 'message', - 'geo.coordinates', - 'geo.dest', - 'geo.src', - 'bytes', - '@timestamp', - 'team', - 'team.name', - 'team.role', - 'user', - 'user.name', - 'user.id', - 'delta', - ]; - - const conflictedFieldTypes = ['user', 'user.id']; - - metaFields = []; - - flattenHit = createFlattenHit(fields, metaFields, conflictedFieldTypes); - - hit = { - _source: { - message: 'Hello World', - geo: { - coordinates: { lat: 33.45, lon: 112.0667 }, - dest: 'US', - src: 'IN', - }, - bytes: 10039103, - '@timestamp': new Date().toString(), - tags: [ - { text: 'foo', label: ['FOO1', 'FOO2'] }, - { text: 'bar', label: 'BAR' }, - ], - groups: ['loners'], - noMapping: true, - team: [ - { name: 'foo', role: 'leader' }, - { name: 'bar', role: 'follower' }, - { name: 'baz', role: 'party boy' }, - ], - user: { name: 'smith', id: 123 }, - }, - fields: { - delta: [42], - random: [0.12345], - }, - }; - }); - - it('flattens keys as far down as the mapping goes', function () { - const flat = flattenHit(hit); - - expect(flat).to.have.property('geo.coordinates', hit._source.geo.coordinates); - expect(flat).to.not.have.property('geo.coordinates.lat'); - expect(flat).to.not.have.property('geo.coordinates.lon'); - expect(flat).to.have.property('geo.dest', 'US'); - expect(flat).to.have.property('geo.src', 'IN'); - expect(flat).to.have.property('@timestamp', hit._source['@timestamp']); - expect(flat).to.have.property('message', 'Hello World'); - expect(flat).to.have.property('bytes', 10039103); - }); - - it('flattens keys not in the mapping', function () { - const flat = flattenHit(hit); - - expect(flat).to.have.property('noMapping', true); - expect(flat).to.have.property('groups'); - expect(flat.groups).to.eql(['loners']); - }); - - it('flattens conflicting types in the mapping', function () { - const flat = flattenHit(hit); - - expect(flat).to.not.have.property('user'); - expect(flat).to.have.property('user.name', hit._source.user.name); - expect(flat).to.have.property('user.id', hit._source.user.id); - }); - - it('should preserve objects in arrays', function () { - const flat = flattenHit(hit); - - expect(flat).to.have.property('tags', hit._source.tags); - }); - - it('does not enter into nested fields', function () { - const flat = flattenHit(hit); - - expect(flat).to.have.property('team', hit._source.team); - expect(flat).to.not.have.property('team.name'); - expect(flat).to.not.have.property('team.role'); - expect(flat).to.not.have.property('team[0]'); - expect(flat).to.not.have.property('team.0'); - }); - - it('unwraps script fields', function () { - const flat = flattenHit(hit); - - expect(flat).to.have.property('delta', 42); - }); - - it('assumes that all fields are "computed fields"', function () { - const flat = flattenHit(hit); - - expect(flat).to.have.property('random', 0.12345); - }); - - describe('metaFields', function () { - beforeEach(function () { - metaFields.push('_metaKey'); - }); - - it('ignores fields that start with an _ and are not in the metaFields', function () { - hit.fields._notMetaKey = [100]; - const flat = flattenHit(hit); - expect(flat).to.not.have.property('_notMetaKey'); - }); - - it('includes underscore-prefixed keys that are in the metaFields', function () { - hit.fields._metaKey = [100]; - const flat = flattenHit(hit); - expect(flat).to.have.property('_metaKey', 100); - }); - - it('handles fields that are not arrays, like _timestamp', function () { - hit.fields._metaKey = 20000; - const flat = flattenHit(hit); - expect(flat).to.have.property('_metaKey', 20000); - }); - }); -}); diff --git a/x-pack/plugins/reporting/server/export_types/csv/generate_csv/flatten_hit.ts b/x-pack/plugins/reporting/server/export_types/csv/generate_csv/flatten_hit.ts deleted file mode 100644 index 8ccd3cdfcd4481..00000000000000 --- a/x-pack/plugins/reporting/server/export_types/csv/generate_csv/flatten_hit.ts +++ /dev/null @@ -1,66 +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 _ from 'lodash'; - -type Hit = Record; -type FlattenHitFn = (hit: Hit) => Record; -type FlatHits = Record; - -// TODO this logic should be re-used with Discover -export function createFlattenHit( - fields: string[], - metaFields: string[], - conflictedTypesFields: string[] -): FlattenHitFn { - const flattenSource = (flat: FlatHits, obj: object, keyPrefix = '') => { - keyPrefix = keyPrefix ? keyPrefix + '.' : ''; - _.forOwn(obj, (val, key) => { - key = keyPrefix + key; - - const hasValidMapping = fields.indexOf(key) >= 0 && conflictedTypesFields.indexOf(key) === -1; - const isValue = !_.isPlainObject(val); - - if (hasValidMapping || isValue) { - if (!flat[key]) { - flat[key] = val; - } else if (_.isArray(flat[key])) { - flat[key].push(val); - } else { - flat[key] = [flat[key], val] as any; - } - return; - } - - flattenSource(flat, val, key); - }); - }; - - const flattenMetaFields = (flat: Hit, hit: Hit) => { - _.each(metaFields, (meta) => { - if (meta === '_source') return; - flat[meta] = hit[meta]; - }); - }; - - const flattenFields = (flat: FlatHits, hitFields: string[]) => { - _.forOwn(hitFields, (val, key) => { - if (key) { - if (key[0] === '_' && !_.includes(metaFields, key)) return; - flat[key] = _.isArray(val) && val.length === 1 ? val[0] : val; - } - }); - }; - - return function flattenHit(hit) { - const flat = {}; - flattenSource(flat, hit._source); - flattenMetaFields(flat, hit); - flattenFields(flat, hit.fields); - return flat; - }; -} diff --git a/x-pack/plugins/reporting/server/export_types/csv/generate_csv/format_csv_values.test.ts b/x-pack/plugins/reporting/server/export_types/csv/generate_csv/format_csv_values.test.ts deleted file mode 100644 index f7a82697fb387b..00000000000000 --- a/x-pack/plugins/reporting/server/export_types/csv/generate_csv/format_csv_values.test.ts +++ /dev/null @@ -1,88 +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 { createFormatCsvValues } from './format_csv_values'; - -describe('formatCsvValues', function () { - const separator = ','; - const fields = ['foo', 'bar']; - const mockEscapeValue = (value: any, index: number, array: any[]) => value || ''; - describe('with _source as one of the fields', function () { - const formatsMap = new Map(); - const formatCsvValues = createFormatCsvValues( - mockEscapeValue, - separator, - ['foo', '_source'], - formatsMap - ); - it('should return full _source for _source field', function () { - const values = { - foo: 'baz', - }; - expect(formatCsvValues(values)).to.be('baz,{"foo":"baz"}'); - }); - }); - describe('without field formats', function () { - const formatsMap = new Map(); - const formatCsvValues = createFormatCsvValues(mockEscapeValue, separator, fields, formatsMap); - - it('should use the specified separator', function () { - expect(formatCsvValues({})).to.be(separator); - }); - - it('should replace null and undefined with empty strings', function () { - const values = { - foo: undefined, - bar: null, - }; - expect(formatCsvValues(values)).to.be(','); - }); - - it('should JSON.stringify objects', function () { - const values = { - foo: { - baz: 'qux', - }, - }; - expect(formatCsvValues(values)).to.be('{"baz":"qux"},'); - }); - - it('should concatenate strings', function () { - const values = { - foo: 'baz', - bar: 'qux', - }; - expect(formatCsvValues(values)).to.be('baz,qux'); - }); - }); - - describe('with field formats', function () { - const mockFieldFormat = { - convert: (val: string) => String(val).toUpperCase(), - }; - const formatsMap = new Map(); - formatsMap.set('bar', mockFieldFormat); - const formatCsvValues = createFormatCsvValues(mockEscapeValue, separator, fields, formatsMap); - - it('should replace null and undefined with empty strings', function () { - const values = { - foo: undefined, - bar: null, - }; - expect(formatCsvValues(values)).to.be(','); - }); - - it('should format value with appropriate FieldFormat', function () { - const values = { - foo: 'baz', - bar: 'qux', - }; - expect(formatCsvValues(values)).to.be('baz,QUX'); - }); - }); -}); diff --git a/x-pack/plugins/reporting/server/export_types/csv/generate_csv/format_csv_values.ts b/x-pack/plugins/reporting/server/export_types/csv/generate_csv/format_csv_values.ts deleted file mode 100644 index 006aa41c6a35e4..00000000000000 --- a/x-pack/plugins/reporting/server/export_types/csv/generate_csv/format_csv_values.ts +++ /dev/null @@ -1,46 +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 { isNull, isObject, isUndefined } from 'lodash'; -import { FieldFormat } from 'src/plugins/field_formats/common'; -import { RawValue } from '../types'; - -export function createFormatCsvValues( - escapeValue: (value: RawValue, index: number, array: RawValue[]) => string, - separator: string, - fields: string[], - formatsMap: Map -) { - return function formatCsvValues(values: Record) { - return fields - .map((field) => { - let value; - if (field === '_source') { - value = values; - } else { - value = values[field]; - } - if (isNull(value) || isUndefined(value)) { - return ''; - } - - let formattedValue = value; - if (formatsMap.has(field)) { - const formatter = formatsMap.get(field); - if (formatter) { - formattedValue = formatter.convert(value); - } - } - - return formattedValue; - }) - .map((value) => (isObject(value) ? JSON.stringify(value) : value)) - .map((value) => (value ? value.toString() : value)) - .map(escapeValue) - .join(separator); - }; -} diff --git a/x-pack/plugins/reporting/server/export_types/csv/generate_csv/get_ui_settings.ts b/x-pack/plugins/reporting/server/export_types/csv/generate_csv/get_ui_settings.ts deleted file mode 100644 index 0140aedf57c29e..00000000000000 --- a/x-pack/plugins/reporting/server/export_types/csv/generate_csv/get_ui_settings.ts +++ /dev/null @@ -1,59 +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 { i18n } from '@kbn/i18n'; -import { IUiSettingsClient } from 'kibana/server'; -import { - UI_SETTINGS_CSV_QUOTE_VALUES, - UI_SETTINGS_CSV_SEPARATOR, -} from '../../../../common/constants'; -import { ReportingConfig } from '../../../'; -import { LevelLogger } from '../../../lib'; - -export const getUiSettings = async ( - timezone: string | undefined, - client: IUiSettingsClient, - config: ReportingConfig, - logger: LevelLogger -) => { - // Timezone - let setTimezone: string; - // look for timezone in job params - if (timezone) { - setTimezone = timezone; - } else { - // if empty, look for timezone in settings - setTimezone = await client.get('dateFormat:tz'); - if (setTimezone === 'Browser') { - // if `Browser`, hardcode it to 'UTC' so the export has data that makes sense - logger.warn( - i18n.translate('xpack.reporting.exportTypes.csv.executeJob.dateFormateSetting', { - defaultMessage: - 'Kibana Advanced Setting "{dateFormatTimezone}" is set to "Browser". Dates will be formatted as UTC to avoid ambiguity.', - values: { dateFormatTimezone: 'dateFormat:tz' }, - }) - ); - setTimezone = 'UTC'; - } - } - - // Separator, QuoteValues - const [separator, quoteValues] = await Promise.all([ - client.get(UI_SETTINGS_CSV_SEPARATOR), - client.get(UI_SETTINGS_CSV_QUOTE_VALUES), - ]); - - return { - timezone: setTimezone, - separator, - quoteValues, - escapeFormulaValues: config.get('csv', 'escapeFormulaValues'), - maxSizeBytes: config.get('csv', 'maxSizeBytes'), - scroll: config.get('csv', 'scroll'), - checkForFormulas: config.get('csv', 'checkForFormulas'), - }; -}; diff --git a/x-pack/plugins/reporting/server/export_types/csv/generate_csv/hit_iterator.test.ts b/x-pack/plugins/reporting/server/export_types/csv/generate_csv/hit_iterator.test.ts deleted file mode 100644 index 6b1b7fc98a4b8c..00000000000000 --- a/x-pack/plugins/reporting/server/export_types/csv/generate_csv/hit_iterator.test.ts +++ /dev/null @@ -1,189 +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 sinon from 'sinon'; -import { elasticsearchServiceMock } from 'src/core/server/mocks'; -import { CancellationToken } from '../../../../common'; -import { createMockLevelLogger } from '../../../test_helpers/create_mock_levellogger'; -import { ScrollConfig } from '../../../types'; -import { createHitIterator } from './hit_iterator'; - -const { asInternalUser: mockEsClient } = elasticsearchServiceMock.createClusterClient(); -const mockLogger = createMockLevelLogger(); -const debugLogStub = sinon.stub(mockLogger, 'debug'); -const warnLogStub = sinon.stub(mockLogger, 'warn'); -const errorLogStub = sinon.stub(mockLogger, 'error'); - -const mockSearchRequest = {}; -const mockConfig: ScrollConfig = { duration: '2s', size: 123 }; -let realCancellationToken = new CancellationToken(); -let isCancelledStub: sinon.SinonStub<[], boolean>; - -describe('hitIterator', function () { - beforeEach(() => { - debugLogStub.resetHistory(); - warnLogStub.resetHistory(); - errorLogStub.resetHistory(); - - mockEsClient.search.mockClear(); - mockEsClient.search.mockResolvedValue({ - body: { - _scroll_id: '123blah', - hits: { hits: ['you found me'] }, - }, - } as any); - - mockEsClient.scroll.mockClear(); - for (let i = 0; i < 10; i++) { - mockEsClient.scroll.mockResolvedValueOnce({ - body: { - _scroll_id: '123blah', - hits: { hits: ['you found me'] }, - }, - } as any); - } - mockEsClient.scroll.mockResolvedValueOnce({ - body: { - _scroll_id: '123blah', - hits: {}, - }, - } as any); - - isCancelledStub = sinon.stub(realCancellationToken, 'isCancelled'); - isCancelledStub.returns(false); - }); - - afterEach(() => { - realCancellationToken = new CancellationToken(); - }); - - it('iterates hits', async () => { - // Begin - const hitIterator = createHitIterator(mockLogger); - const iterator = hitIterator( - mockConfig, - mockEsClient, - mockSearchRequest, - realCancellationToken - ); - - while (true) { - const { done: iterationDone, value: hit } = await iterator.next(); - if (iterationDone) { - break; - } - expect(hit).to.be('you found me'); - } - - expect(mockEsClient.scroll.mock.calls.length).to.be(11); - expect(debugLogStub.callCount).to.be(13); - expect(warnLogStub.callCount).to.be(0); - expect(errorLogStub.callCount).to.be(0); - }); - - it('stops searches after cancellation', async () => { - // Setup - isCancelledStub.onFirstCall().returns(false); - isCancelledStub.returns(true); - - // Begin - const hitIterator = createHitIterator(mockLogger); - const iterator = hitIterator( - mockConfig, - mockEsClient, - mockSearchRequest, - realCancellationToken - ); - - while (true) { - const { done: iterationDone, value: hit } = await iterator.next(); - if (iterationDone) { - break; - } - expect(hit).to.be('you found me'); - } - - expect(mockEsClient.scroll.mock.calls.length).to.be(1); - expect(debugLogStub.callCount).to.be(3); - expect(warnLogStub.callCount).to.be(1); - expect(errorLogStub.callCount).to.be(0); - - expect(warnLogStub.firstCall.lastArg).to.be( - 'Any remaining scrolling searches have been cancelled by the cancellation token.' - ); - }); - - it('handles time out', async () => { - // Setup - mockEsClient.scroll.mockReset(); - mockEsClient.scroll.mockResolvedValueOnce({ - body: { - _scroll_id: '123blah', - hits: { hits: ['you found me'] }, - }, - } as any); - mockEsClient.scroll.mockResolvedValueOnce({ body: { status: 404 } } as any); - - // Begin - const hitIterator = createHitIterator(mockLogger); - const iterator = hitIterator( - mockConfig, - mockEsClient, - mockSearchRequest, - realCancellationToken - ); - - let errorThrown = false; - try { - while (true) { - const { done: iterationDone, value: hit } = await iterator.next(); - if (iterationDone) { - break; - } - expect(hit).to.be('you found me'); - } - } catch (err) { - expect(err).to.eql( - new Error('Expected _scroll_id in the following Elasticsearch response: {"status":404}') - ); - errorThrown = true; - } - - expect(mockEsClient.scroll.mock.calls.length).to.be(2); - expect(debugLogStub.callCount).to.be(4); - expect(warnLogStub.callCount).to.be(0); - expect(errorLogStub.callCount).to.be(1); - expect(errorThrown).to.be(true); - }); - - it('handles scroll id could not be cleared', async () => { - // Setup - mockEsClient.clearScroll.mockRejectedValueOnce({ status: 404 }); - - // Begin - const hitIterator = createHitIterator(mockLogger); - const iterator = hitIterator( - mockConfig, - mockEsClient, - mockSearchRequest, - realCancellationToken - ); - - while (true) { - const { done: iterationDone, value: hit } = await iterator.next(); - if (iterationDone) { - break; - } - expect(hit).to.be('you found me'); - } - - expect(mockEsClient.scroll.mock.calls.length).to.be(11); - expect(warnLogStub.callCount).to.be(1); - expect(errorLogStub.callCount).to.be(1); - }); -}); diff --git a/x-pack/plugins/reporting/server/export_types/csv/generate_csv/hit_iterator.ts b/x-pack/plugins/reporting/server/export_types/csv/generate_csv/hit_iterator.ts deleted file mode 100644 index f2da8564bebbca..00000000000000 --- a/x-pack/plugins/reporting/server/export_types/csv/generate_csv/hit_iterator.ts +++ /dev/null @@ -1,110 +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 type { TransportResult } from '@elastic/elasticsearch'; -import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; -import { i18n } from '@kbn/i18n'; -import { ElasticsearchClient } from 'src/core/server'; -import { CancellationToken } from '../../../../common'; -import { LevelLogger } from '../../../lib'; -import { ScrollConfig } from '../../../types'; - -function parseResponse(response: TransportResult) { - if (!response?.body._scroll_id) { - throw new Error( - i18n.translate('xpack.reporting.exportTypes.csv.hitIterator.expectedScrollIdErrorMessage', { - defaultMessage: 'Expected {scrollId} in the following Elasticsearch response: {response}', - values: { response: JSON.stringify(response?.body), scrollId: '_scroll_id' }, - }) - ); - } - - if (!response?.body.hits) { - throw new Error( - i18n.translate('xpack.reporting.exportTypes.csv.hitIterator.expectedHitsErrorMessage', { - defaultMessage: 'Expected {hits} in the following Elasticsearch response: {response}', - values: { response: JSON.stringify(response?.body), hits: 'hits' }, - }) - ); - } - - return { - scrollId: response.body._scroll_id, - hits: response.body.hits.hits, - }; -} - -export function createHitIterator(logger: LevelLogger) { - return async function* hitIterator( - scrollSettings: ScrollConfig, - elasticsearchClient: ElasticsearchClient, - searchRequest: estypes.SearchRequest, - cancellationToken: CancellationToken - ) { - logger.debug('executing search request'); - async function search( - index: estypes.SearchRequest['index'], - body: estypes.SearchRequest['body'] - ) { - return parseResponse( - await elasticsearchClient.search({ - index, - body, - ignore_unavailable: true, // ignores if the index pattern contains any aliases that point to closed indices - scroll: scrollSettings.duration, - size: scrollSettings.size, - }) - ); - } - - async function scroll(scrollId: string) { - logger.debug('executing scroll request'); - return parseResponse( - await elasticsearchClient.scroll({ - scroll_id: scrollId, - scroll: scrollSettings.duration, - }) - ); - } - - async function clearScroll(scrollId: string | undefined) { - logger.debug('executing clearScroll request'); - try { - await elasticsearchClient.clearScroll({ - scroll_id: scrollId, - }); - } catch (err) { - // Do not throw the error, as the job can still be completed successfully - logger.warn('Scroll context can not be cleared!'); - logger.error(err); - } - } - - try { - let { scrollId, hits } = await search(searchRequest.index, searchRequest.body); - try { - while (hits && hits.length && !cancellationToken.isCancelled()) { - for (const hit of hits) { - yield hit; - } - - ({ scrollId, hits } = await scroll(scrollId)); - - if (cancellationToken.isCancelled()) { - logger.warn( - 'Any remaining scrolling searches have been cancelled by the cancellation token.' - ); - } - } - } finally { - await clearScroll(scrollId); - } - } catch (err) { - logger.error(err); - throw err; - } - }; -} diff --git a/x-pack/plugins/reporting/server/export_types/csv/generate_csv/index.ts b/x-pack/plugins/reporting/server/export_types/csv/generate_csv/index.ts deleted file mode 100644 index 2573ba14f22a56..00000000000000 --- a/x-pack/plugins/reporting/server/export_types/csv/generate_csv/index.ts +++ /dev/null @@ -1,163 +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 { Writable } from 'stream'; -import { i18n } from '@kbn/i18n'; -import { ElasticsearchClient, IUiSettingsClient } from 'src/core/server'; -import type { DataView, DataViewsService } from 'src/plugins/data/common'; -import { ReportingConfig } from '../../../'; -import { createEscapeValue } from '../../../../../../../src/plugins/data/common'; -import { CancellationToken } from '../../../../../../plugins/reporting/common'; -import { CSV_BOM_CHARS } from '../../../../common/constants'; -import { byteSizeValueToNumber } from '../../../../common/schema_utils'; -import { LevelLogger } from '../../../lib'; -import { getFieldFormats } from '../../../services'; -import { MaxSizeStringBuilder } from '../../csv_searchsource/generate_csv/max_size_string_builder'; -import { SavedSearchGeneratorResultDeprecatedCSV } from '../types'; -import { checkIfRowsHaveFormulas } from './check_cells_for_formulas'; -import { fieldFormatMapFactory } from './field_format_map'; -import { createFlattenHit } from './flatten_hit'; -import { createFormatCsvValues } from './format_csv_values'; -import { getUiSettings } from './get_ui_settings'; -import { createHitIterator } from './hit_iterator'; - -interface SearchRequest { - index: string; - body: - | { - _source: { excludes: string[]; includes: string[] }; - docvalue_fields: string[]; - query: { bool: { filter: any[]; must_not: any[]; should: any[]; must: any[] } } | any; - script_fields: any; - sort: Array<{ [key: string]: { order: string } }>; - stored_fields: string[]; - } - | any; -} - -export interface GenerateCsvParams { - browserTimezone?: string; - searchRequest: SearchRequest; - indexPatternId: string; - fields: string[]; - metaFields: string[]; - conflictedTypesFields: string[]; -} - -export function createGenerateCsv(logger: LevelLogger) { - const hitIterator = createHitIterator(logger); - - return async function generateCsv( - job: GenerateCsvParams, - config: ReportingConfig, - uiSettingsClient: IUiSettingsClient, - elasticsearchClient: ElasticsearchClient, - dataViews: DataViewsService, - cancellationToken: CancellationToken, - stream: Writable - ): Promise { - const settings = await getUiSettings(job.browserTimezone, uiSettingsClient, config, logger); - const escapeValue = createEscapeValue(settings.quoteValues, settings.escapeFormulaValues); - const bom = config.get('csv', 'useByteOrderMarkEncoding') ? CSV_BOM_CHARS : ''; - const builder = new MaxSizeStringBuilder( - stream, - byteSizeValueToNumber(settings.maxSizeBytes), - bom - ); - - const { fields, metaFields, conflictedTypesFields } = job; - const header = `${fields.map(escapeValue).join(settings.separator)}\n`; - const warnings: string[] = []; - - if (!builder.tryAppend(header)) { - return { - maxSizeReached: true, - warnings: [], - }; - } - - const iterator = hitIterator( - settings.scroll, - elasticsearchClient, - job.searchRequest, - cancellationToken - ); - let maxSizeReached = false; - let csvContainsFormulas = false; - - const flattenHit = createFlattenHit(fields, metaFields, conflictedTypesFields); - let dataView: DataView | undefined; - - try { - dataView = await dataViews.get(job.indexPatternId); - } catch (error) { - logger.error(`Failed to get the data view "${job.indexPatternId}": ${error}`); - } - - const formatsMap = await getFieldFormats() - .fieldFormatServiceFactory(uiSettingsClient) - .then((fieldFormats) => fieldFormatMapFactory(dataView, fieldFormats, settings.timezone)); - - const formatCsvValues = createFormatCsvValues( - escapeValue, - settings.separator, - fields, - formatsMap - ); - try { - while (true) { - const { done, value: hit } = await iterator.next(); - - if (!hit) { - break; - } - - if (done) { - break; - } - - if (cancellationToken.isCancelled()) { - break; - } - - const flattened = flattenHit(hit); - const rows = formatCsvValues(flattened); - const rowsHaveFormulas = - settings.checkForFormulas && checkIfRowsHaveFormulas(flattened, fields); - - if (rowsHaveFormulas) { - csvContainsFormulas = true; - } - - if (!builder.tryAppend(rows + '\n')) { - logger.warn('max Size Reached'); - maxSizeReached = true; - if (cancellationToken) { - cancellationToken.cancel(); - } - break; - } - } - } finally { - await iterator.return(); - } - - if (csvContainsFormulas && settings.escapeFormulaValues) { - warnings.push( - i18n.translate('xpack.reporting.exportTypes.csv.generateCsv.escapedFormulaValues', { - defaultMessage: 'CSV may contain formulas whose values have been escaped', - }) - ); - } - - return { - csvContainsFormulas: csvContainsFormulas && !settings.escapeFormulaValues, - maxSizeReached, - warnings, - }; - }; -} diff --git a/x-pack/plugins/reporting/server/export_types/csv/index.ts b/x-pack/plugins/reporting/server/export_types/csv/index.ts deleted file mode 100644 index 6fe2f7ac00ebce..00000000000000 --- a/x-pack/plugins/reporting/server/export_types/csv/index.ts +++ /dev/null @@ -1,40 +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 { - CSV_JOB_TYPE_DEPRECATED as jobType, - LICENSE_TYPE_BASIC, - LICENSE_TYPE_ENTERPRISE, - LICENSE_TYPE_GOLD, - LICENSE_TYPE_PLATINUM, - LICENSE_TYPE_STANDARD, - LICENSE_TYPE_TRIAL, -} from '../../../common/constants'; -import { CreateJobFn, ExportTypeDefinition, RunTaskFn } from '../../types'; -import { createJobFnFactory } from './create_job'; -import { runTaskFnFactory } from './execute_job'; -import { metadata } from './metadata'; -import { JobParamsDeprecatedCSV, TaskPayloadDeprecatedCSV } from './types'; - -export const getExportType = (): ExportTypeDefinition< - CreateJobFn, - RunTaskFn -> => ({ - ...metadata, - jobType, - jobContentExtension: 'csv', - createJobFnFactory, - runTaskFnFactory, - validLicenses: [ - LICENSE_TYPE_TRIAL, - LICENSE_TYPE_BASIC, - LICENSE_TYPE_STANDARD, - LICENSE_TYPE_GOLD, - LICENSE_TYPE_PLATINUM, - LICENSE_TYPE_ENTERPRISE, - ], -}); diff --git a/x-pack/plugins/reporting/server/export_types/csv/metadata.ts b/x-pack/plugins/reporting/server/export_types/csv/metadata.ts deleted file mode 100644 index 4717148aae821a..00000000000000 --- a/x-pack/plugins/reporting/server/export_types/csv/metadata.ts +++ /dev/null @@ -1,11 +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. - */ - -export const metadata = { - id: 'csv', - name: 'CSV', -}; diff --git a/x-pack/plugins/reporting/server/export_types/csv/types.ts b/x-pack/plugins/reporting/server/export_types/csv/types.ts deleted file mode 100644 index 5531f2d670128f..00000000000000 --- a/x-pack/plugins/reporting/server/export_types/csv/types.ts +++ /dev/null @@ -1,14 +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. - */ - -export type { - RawValue, - JobParamsDeprecatedCSV, - TaskPayloadDeprecatedCSV, - SearchRequestDeprecatedCSV, - SavedSearchGeneratorResultDeprecatedCSV, -} from '../../../common/types'; diff --git a/x-pack/plugins/reporting/server/lib/check_license.test.ts b/x-pack/plugins/reporting/server/lib/check_license.test.ts index 59743ce62639a6..5265c04eeada6e 100644 --- a/x-pack/plugins/reporting/server/lib/check_license.test.ts +++ b/x-pack/plugins/reporting/server/lib/check_license.test.ts @@ -22,7 +22,7 @@ describe('check_license', () => { describe('license information is not ready', () => { beforeEach(() => { exportTypesRegistry = { - getAll: () => [{ id: 'csv' }], + getAll: () => [{ id: 'csv_searchsource' }], } as unknown as ExportTypesRegistry; }); @@ -30,16 +30,18 @@ describe('check_license', () => { expect(checkLicense(exportTypesRegistry, undefined).management.showLinks).toEqual(true); }); - it('should set csv.showLinks to true', () => { - expect(checkLicense(exportTypesRegistry, undefined).csv.showLinks).toEqual(true); + it('should set csv_searchsource.showLinks to true', () => { + expect(checkLicense(exportTypesRegistry, undefined).csv_searchsource.showLinks).toEqual(true); }); it('should set management.enableLinks to false', () => { expect(checkLicense(exportTypesRegistry, undefined).management.enableLinks).toEqual(false); }); - it('should set csv.enableLinks to false', () => { - expect(checkLicense(exportTypesRegistry, undefined).csv.enableLinks).toEqual(false); + it('should set csv_searchsource.enableLinks to false', () => { + expect(checkLicense(exportTypesRegistry, undefined).csv_searchsource.enableLinks).toEqual( + false + ); }); it('should set management.jobTypes to undefined', () => { @@ -53,7 +55,7 @@ describe('check_license', () => { type: undefined, } as ILicense; exportTypesRegistry = { - getAll: () => [{ id: 'csv' }], + getAll: () => [{ id: 'csv_searchsource' }], } as unknown as ExportTypesRegistry; }); @@ -61,16 +63,18 @@ describe('check_license', () => { expect(checkLicense(exportTypesRegistry, license).management.showLinks).toEqual(true); }); - it('should set csv.showLinks to true', () => { - expect(checkLicense(exportTypesRegistry, license).csv.showLinks).toEqual(true); + it('should set csv_searchsource.showLinks to true', () => { + expect(checkLicense(exportTypesRegistry, license).csv_searchsource.showLinks).toEqual(true); }); it('should set management.enableLinks to false', () => { expect(checkLicense(exportTypesRegistry, license).management.enableLinks).toEqual(false); }); - it('should set csv.enableLinks to false', () => { - expect(checkLicense(exportTypesRegistry, license).csv.enableLinks).toEqual(false); + it('should set csv_searchsource.enableLinks to false', () => { + expect(checkLicense(exportTypesRegistry, license).csv_searchsource.enableLinks).toEqual( + false + ); }); it('should set management.jobTypes to undefined', () => { diff --git a/x-pack/plugins/reporting/server/lib/export_types_registry.ts b/x-pack/plugins/reporting/server/lib/export_types_registry.ts index 314d50e1315656..0c245bde667d3f 100644 --- a/x-pack/plugins/reporting/server/lib/export_types_registry.ts +++ b/x-pack/plugins/reporting/server/lib/export_types_registry.ts @@ -6,7 +6,6 @@ */ import { isString } from 'lodash'; -import { getExportType as getTypeCsvDeprecated } from '../export_types/csv'; import { getExportType as getTypeCsvFromSavedObject } from '../export_types/csv_searchsource_immediate'; import { getExportType as getTypeCsv } from '../export_types/csv_searchsource'; import { getExportType as getTypePng } from '../export_types/png'; @@ -88,7 +87,6 @@ export function getExportTypesRegistry(): ExportTypesRegistry { type RunFnType = any; // can not specify because ImmediateExecuteFn is not assignable to RunTaskFn const getTypeFns: Array<() => ExportTypeDefinition> = [ getTypeCsv, - getTypeCsvDeprecated, getTypeCsvFromSavedObject, getTypePng, getTypePngV2, diff --git a/x-pack/plugins/reporting/server/lib/store/store.test.ts b/x-pack/plugins/reporting/server/lib/store/store.test.ts index c67dc3fa2d992a..aa893baf72e1e0 100644 --- a/x-pack/plugins/reporting/server/lib/store/store.test.ts +++ b/x-pack/plugins/reporting/server/lib/store/store.test.ts @@ -189,7 +189,7 @@ describe('ReportingStore', () => { migration_version: 'X.0.0', created_at: 'some time', created_by: 'some security person', - jobtype: 'csv', + jobtype: 'csv_searchsource', status: 'pending', meta: { testMeta: 'meta' } as any, payload: { testPayload: 'payload' } as any, @@ -216,7 +216,7 @@ describe('ReportingStore', () => { "completed_at": undefined, "created_at": "some time", "created_by": "some security person", - "jobtype": "csv", + "jobtype": "csv_searchsource", "kibana_id": undefined, "kibana_name": undefined, "max_attempts": 1, diff --git a/x-pack/plugins/reporting/server/routes/lib/request_handler.test.ts b/x-pack/plugins/reporting/server/routes/lib/request_handler.test.ts index 6d73a3ec7ee744..00d0d28afd9daa 100644 --- a/x-pack/plugins/reporting/server/routes/lib/request_handler.test.ts +++ b/x-pack/plugins/reporting/server/routes/lib/request_handler.test.ts @@ -160,10 +160,14 @@ describe('Handle request to generate', () => { test('disallows unsupporting license', async () => { (reportingCore.getLicenseInfo as jest.Mock) = jest.fn(() => ({ - csv: { enableLinks: false, message: `seeing this means the license isn't supported` }, + csv_searchsource: { + enableLinks: false, + message: `seeing this means the license isn't supported`, + }, })); - expect(await requestHandler.handleGenerateRequest('csv', mockJobParams)).toMatchInlineSnapshot(` + expect(await requestHandler.handleGenerateRequest('csv_searchsource', mockJobParams)) + .toMatchInlineSnapshot(` Object { "body": "seeing this means the license isn't supported", } @@ -172,7 +176,7 @@ describe('Handle request to generate', () => { test('generates the download path', async () => { const response = (await requestHandler.handleGenerateRequest( - 'csv', + 'csv_searchsource', mockJobParams )) as unknown as { body: { job: ReportApiJSON } }; const { id, created_at: _created_at, ...snapObj } = response.body.job; @@ -182,12 +186,12 @@ describe('Handle request to generate', () => { "completed_at": undefined, "created_by": "testymcgee", "index": ".reporting-foo-index-234", - "jobtype": "csv", + "jobtype": "csv_searchsource", "kibana_id": undefined, "kibana_name": undefined, "max_attempts": undefined, "meta": Object { - "isDeprecated": true, + "isDeprecated": undefined, "layout": "preserve_layout", "objectType": "cool_object_type", }, @@ -195,7 +199,6 @@ describe('Handle request to generate', () => { "output": Object {}, "payload": Object { "browserTimezone": "UTC", - "isDeprecated": true, "layout": Object { "id": "preserve_layout", }, diff --git a/x-pack/plugins/reporting/server/usage/__snapshots__/reporting_usage_collector.test.ts.snap b/x-pack/plugins/reporting/server/usage/__snapshots__/reporting_usage_collector.test.ts.snap index 78bb9ab6df51f3..16596eb2cc0b1f 100644 --- a/x-pack/plugins/reporting/server/usage/__snapshots__/reporting_usage_collector.test.ts.snap +++ b/x-pack/plugins/reporting/server/usage/__snapshots__/reporting_usage_collector.test.ts.snap @@ -1970,7 +1970,7 @@ Object { }, "_all": 9, "available": true, - "csv": Object { + "csv_searchsource": Object { "app": Object { "canvas workpad": 0, "dashboard": 0, @@ -1987,23 +1987,6 @@ Object { "output_size": undefined, "total": 4, }, - "csv_searchsource": Object { - "app": Object { - "canvas workpad": 0, - "dashboard": 0, - "search": 0, - "visualization": 0, - }, - "available": true, - "deprecated": 0, - "layout": Object { - "canvas": 0, - "preserve_layout": 0, - "print": 0, - }, - "output_size": undefined, - "total": 5, - }, "csv_searchsource_immediate": Object { "app": Object { "canvas workpad": 0, @@ -2055,7 +2038,7 @@ Object { "total": 0, }, "_all": 9, - "csv": Object { + "csv_searchsource": Object { "app": Object { "canvas workpad": 0, "dashboard": 0, @@ -2072,23 +2055,6 @@ Object { "output_size": undefined, "total": 4, }, - "csv_searchsource": Object { - "app": Object { - "canvas workpad": 0, - "dashboard": 0, - "search": 0, - "visualization": 0, - }, - "available": true, - "deprecated": 0, - "layout": Object { - "canvas": 0, - "preserve_layout": 0, - "print": 0, - }, - "output_size": undefined, - "total": 5, - }, "csv_searchsource_immediate": Object { "app": Object { "canvas workpad": 0, @@ -2144,11 +2110,8 @@ Object { }, "statuses": Object { "completed": Object { - "csv": Object { - "search": 4, - }, "csv_searchsource": Object { - "search": 5, + "search": 4, }, }, }, @@ -2192,11 +2155,8 @@ Object { }, "statuses": Object { "completed": Object { - "csv": Object { - "search": 4, - }, "csv_searchsource": Object { - "search": 5, + "search": 4, }, }, }, @@ -2239,22 +2199,6 @@ Object { }, "_all": 0, "available": true, - "csv": Object { - "app": Object { - "canvas workpad": 0, - "dashboard": 0, - "search": 0, - "visualization": 0, - }, - "available": true, - "deprecated": 0, - "layout": Object { - "canvas": 0, - "preserve_layout": 0, - "print": 0, - }, - "total": 0, - }, "csv_searchsource": Object { "app": Object { "canvas workpad": 0, @@ -2322,22 +2266,6 @@ Object { "total": 0, }, "_all": 0, - "csv": Object { - "app": Object { - "canvas workpad": 0, - "dashboard": 0, - "search": 0, - "visualization": 0, - }, - "available": true, - "deprecated": 0, - "layout": Object { - "canvas": 0, - "preserve_layout": 0, - "print": 0, - }, - "total": 0, - }, "csv_searchsource": Object { "app": Object { "canvas workpad": 0, @@ -2487,23 +2415,6 @@ Object { }, "_all": 4, "available": true, - "csv": Object { - "app": Object { - "canvas workpad": 0, - "dashboard": 0, - "search": 0, - "visualization": 0, - }, - "available": true, - "deprecated": 1, - "layout": Object { - "canvas": 0, - "preserve_layout": 0, - "print": 0, - }, - "output_size": undefined, - "total": 1, - }, "csv_searchsource": Object { "app": Object { "canvas workpad": 0, @@ -2518,7 +2429,8 @@ Object { "preserve_layout": 0, "print": 0, }, - "total": 0, + "output_size": undefined, + "total": 1, }, "csv_searchsource_immediate": Object { "app": Object { @@ -2572,23 +2484,6 @@ Object { "total": 0, }, "_all": 4, - "csv": Object { - "app": Object { - "canvas workpad": 0, - "dashboard": 0, - "search": 0, - "visualization": 0, - }, - "available": true, - "deprecated": 1, - "layout": Object { - "canvas": 0, - "preserve_layout": 0, - "print": 0, - }, - "output_size": undefined, - "total": 1, - }, "csv_searchsource": Object { "app": Object { "canvas workpad": 0, @@ -2603,7 +2498,8 @@ Object { "preserve_layout": 0, "print": 0, }, - "total": 0, + "output_size": undefined, + "total": 1, }, "csv_searchsource_immediate": Object { "app": Object { @@ -2664,7 +2560,7 @@ Object { "PNG": Object { "dashboard": 1, }, - "csv": Object {}, + "csv_searchsource": Object {}, "printable_pdf": Object { "canvas workpad": 1, "dashboard": 1, @@ -2715,7 +2611,7 @@ Object { "PNG": Object { "dashboard": 1, }, - "csv": Object {}, + "csv_searchsource": Object {}, "printable_pdf": Object { "canvas workpad": 1, "dashboard": 1, @@ -2762,23 +2658,6 @@ Object { }, "_all": 11, "available": true, - "csv": Object { - "app": Object { - "canvas workpad": 0, - "dashboard": 0, - "search": 0, - "visualization": 0, - }, - "available": true, - "deprecated": 1, - "layout": Object { - "canvas": 0, - "preserve_layout": 0, - "print": 0, - }, - "output_size": undefined, - "total": 1, - }, "csv_searchsource": Object { "app": Object { "canvas workpad": 0, @@ -2794,7 +2673,7 @@ Object { "print": 0, }, "output_size": undefined, - "total": 3, + "total": 1, }, "csv_searchsource_immediate": Object { "app": Object { @@ -2847,22 +2726,6 @@ Object { "total": 0, }, "_all": 0, - "csv": Object { - "app": Object { - "canvas workpad": 0, - "dashboard": 0, - "search": 0, - "visualization": 0, - }, - "available": true, - "deprecated": 0, - "layout": Object { - "canvas": 0, - "preserve_layout": 0, - "print": 0, - }, - "total": 0, - }, "csv_searchsource": Object { "app": Object { "canvas workpad": 0, @@ -2976,11 +2839,8 @@ Object { }, "statuses": Object { "completed": Object { - "csv": Object { - "search": 1, - }, "csv_searchsource": Object { - "search": 3, + "search": 1, }, "printable_pdf": Object { "dashboard": 2, diff --git a/x-pack/plugins/reporting/server/usage/get_export_stats.test.ts b/x-pack/plugins/reporting/server/usage/get_export_stats.test.ts index f74e176e6f21d5..70edfb61a0c23d 100644 --- a/x-pack/plugins/reporting/server/usage/get_export_stats.test.ts +++ b/x-pack/plugins/reporting/server/usage/get_export_stats.test.ts @@ -22,7 +22,7 @@ const sizesAggResponse = { }; beforeEach(() => { - featureMap = { PNG: true, csv: true, csv_searchsource: true, printable_pdf: true }; + featureMap = { PNG: true, csv_searchsource: true, printable_pdf: true }; }); const exportTypesHandler = getExportTypesHandler(getExportTypesRegistry()); @@ -121,24 +121,6 @@ test('Model of jobTypes', () => { "total": 3, } `); - expect(result.csv).toMatchInlineSnapshot(` - Object { - "app": Object { - "canvas workpad": 0, - "dashboard": 0, - "search": 0, - "visualization": 0, - }, - "available": true, - "deprecated": 0, - "layout": Object { - "canvas": 0, - "preserve_layout": 0, - "print": 0, - }, - "total": 0, - } - `); expect(result.csv_searchsource).toMatchInlineSnapshot(` Object { "app": Object { @@ -236,45 +218,3 @@ test('PNG counts, provided count of deprecated jobs explicitly', () => { } `); }); - -test('CSV counts, provides all jobs implicitly deprecated due to jobtype', () => { - const result = getExportStats( - { - csv: { - available: true, - total: 15, - deprecated: 0, - sizes: sizesAggResponse, - }, - }, - featureMap, - exportTypesHandler - ); - expect(result.csv).toMatchInlineSnapshot(` - Object { - "app": Object { - "canvas workpad": 0, - "dashboard": 0, - "search": 0, - "visualization": 0, - }, - "available": true, - "deprecated": 15, - "layout": Object { - "canvas": 0, - "preserve_layout": 0, - "print": 0, - }, - "output_size": Object { - "1.0": 5093470, - "25.0": 5093470, - "5.0": 5093470, - "50.0": 8514532, - "75.0": 11935594, - "95.0": 11935594, - "99.0": 11935594, - }, - "total": 15, - } - `); -}); diff --git a/x-pack/plugins/reporting/server/usage/reporting_usage_collector.test.ts b/x-pack/plugins/reporting/server/usage/reporting_usage_collector.test.ts index 447085810cfd07..4ffdaa80577be5 100644 --- a/x-pack/plugins/reporting/server/usage/reporting_usage_collector.test.ts +++ b/x-pack/plugins/reporting/server/usage/reporting_usage_collector.test.ts @@ -90,8 +90,8 @@ describe('license checks', () => { expect(usageStats.enabled).toBe(true); }); - test('sets csv available to true', async () => { - expect(usageStats.csv.available).toBe(true); + test('sets csv_searchsource available to true', async () => { + expect(usageStats.csv_searchsource.available).toBe(true); }); test('sets pdf availability to false', async () => { @@ -119,8 +119,8 @@ describe('license checks', () => { expect(usageStats.enabled).toBe(true); }); - test('sets csv available to false', async () => { - expect(usageStats.csv.available).toBe(false); + test('sets csv_searchsource available to false', async () => { + expect(usageStats.csv_searchsource.available).toBe(false); }); test('sets pdf availability to false', async () => { @@ -148,8 +148,8 @@ describe('license checks', () => { expect(usageStats.enabled).toBe(true); }); - test('sets csv available to true', async () => { - expect(usageStats.csv.available).toBe(true); + test('sets csv_searchsource available to true', async () => { + expect(usageStats.csv_searchsource.available).toBe(true); }); test('sets pdf availability to true', async () => { @@ -177,8 +177,8 @@ describe('license checks', () => { expect(usageStats.enabled).toBe(true); }); - test('sets csv available to true', async () => { - expect(usageStats.csv.available).toBe(true); + test('sets csv_searchsource available to true', async () => { + expect(usageStats.csv_searchsource.available).toBe(true); }); }); }); @@ -209,10 +209,10 @@ describe('data modeling', () => { all: { doc_count: 11, layoutTypes: { doc_count: 6, pdf: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [ { key: 'preserve_layout', doc_count: 5 }, { key: 'print', doc_count: 1 }, ] } }, - statusByApp: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [ { key: 'completed', doc_count: 6, jobTypes: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [ { key: 'csv_searchsource', doc_count: 3, appNames: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [ { key: 'search', doc_count: 3 }, ] } }, { key: 'printable_pdf', doc_count: 2, appNames: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [ { key: 'dashboard', doc_count: 2 }, ] } }, { key: 'csv', doc_count: 1, appNames: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [ { key: 'search', doc_count: 1 }, ] } }, ] } }, { key: 'completed_with_warnings', doc_count: 2, jobTypes: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [ { key: 'PNG', doc_count: 1, appNames: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [ { key: 'dashboard', doc_count: 1 }, ] } }, { key: 'printable_pdf', doc_count: 1, appNames: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [ { key: 'dashboard', doc_count: 1 }, ] } }, ] } }, { key: 'failed', doc_count: 2, jobTypes: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [ { key: 'printable_pdf', doc_count: 2, appNames: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [ { key: 'dashboard', doc_count: 2 }, ] } }, ] } }, { key: 'pending', doc_count: 1, jobTypes: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [ { key: 'printable_pdf', doc_count: 1, appNames: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [ { key: 'dashboard', doc_count: 1 }, ] } }, ] } }, ] }, + statusByApp: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [ { key: 'completed', doc_count: 6, jobTypes: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [ { key: 'csv_searchsource', doc_count: 3, appNames: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [ { key: 'search', doc_count: 3 }, ] } }, { key: 'printable_pdf', doc_count: 2, appNames: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [ { key: 'dashboard', doc_count: 2 }, ] } }, { key: 'csv_searchsource', doc_count: 1, appNames: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [ { key: 'search', doc_count: 1 }, ] } }, ] } }, { key: 'completed_with_warnings', doc_count: 2, jobTypes: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [ { key: 'PNG', doc_count: 1, appNames: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [ { key: 'dashboard', doc_count: 1 }, ] } }, { key: 'printable_pdf', doc_count: 1, appNames: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [ { key: 'dashboard', doc_count: 1 }, ] } }, ] } }, { key: 'failed', doc_count: 2, jobTypes: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [ { key: 'printable_pdf', doc_count: 2, appNames: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [ { key: 'dashboard', doc_count: 2 }, ] } }, ] } }, { key: 'pending', doc_count: 1, jobTypes: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [ { key: 'printable_pdf', doc_count: 1, appNames: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [ { key: 'dashboard', doc_count: 1 }, ] } }, ] } }, ] }, objectTypes: { doc_count: 6, pdf: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [ { key: 'dashboard', doc_count: 6 }, ] } }, statusTypes: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [ { key: 'completed', doc_count: 6 }, { key: 'completed_with_warnings', doc_count: 2 }, { key: 'failed', doc_count: 2 }, { key: 'pending', doc_count: 1 }, ] }, - jobTypes: { meta: {}, doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [ { key: 'printable_pdf', doc_count: 6, isDeprecated: { meta: {}, doc_count: 0 }, sizeMax: { value: 1713303.0 }, sizeAvg: { value: 957215.0 }, sizeMin: { value: 43226.0 } }, { key: 'csv_searchsource', doc_count: 3, isDeprecated: { meta: {}, doc_count: 0 }, sizeMax: { value: 7557.0 }, sizeAvg: { value: 3684.6666666666665 }, sizeMin: { value: 204.0 } }, { key: 'PNG', doc_count: 1, isDeprecated: { meta: {}, doc_count: 0 }, sizeMax: { value: 37748.0 }, sizeAvg: { value: 37748.0 }, sizeMin: { value: 37748.0 } }, { key: 'csv', doc_count: 1, isDeprecated: { meta: {}, doc_count: 0 }, sizeMax: { value: 231.0 }, sizeAvg: { value: 231.0 }, sizeMin: { value: 231.0 } }, ] }, + jobTypes: { meta: {}, doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [ { key: 'printable_pdf', doc_count: 6, isDeprecated: { meta: {}, doc_count: 0 }, sizeMax: { value: 1713303.0 }, sizeAvg: { value: 957215.0 }, sizeMin: { value: 43226.0 } }, { key: 'csv_searchsource', doc_count: 3, isDeprecated: { meta: {}, doc_count: 0 }, sizeMax: { value: 7557.0 }, sizeAvg: { value: 3684.6666666666665 }, sizeMin: { value: 204.0 } }, { key: 'PNG', doc_count: 1, isDeprecated: { meta: {}, doc_count: 0 }, sizeMax: { value: 37748.0 }, sizeAvg: { value: 37748.0 }, sizeMin: { value: 37748.0 } }, { key: 'csv_searchsource', doc_count: 1, isDeprecated: { meta: {}, doc_count: 0 }, sizeMax: { value: 231.0 }, sizeAvg: { value: 231.0 }, sizeMin: { value: 231.0 } }, ] }, sizeMax: { value: 1713303.0 }, sizeMin: { value: 204.0 }, sizeAvg: { value: 365084.75 }, @@ -256,18 +256,18 @@ describe('data modeling', () => { all: { doc_count: 9, layoutTypes: { doc_count: 0, pdf: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [] } }, - statusByApp: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [ { key: 'completed', doc_count: 9, jobTypes: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [ { key: 'csv_searchsource', doc_count: 5, appNames: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [{ key: 'search', doc_count: 5 }] } }, { key: 'csv', doc_count: 4, appNames: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [{ key: 'search', doc_count: 4 }] } }, ] } }, ] }, + statusByApp: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [ { key: 'completed', doc_count: 9, jobTypes: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [ { key: 'csv_searchsource', doc_count: 5, appNames: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [{ key: 'search', doc_count: 5 }] } }, { key: 'csv_searchsource', doc_count: 4, appNames: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [{ key: 'search', doc_count: 4 }] } }, ] } }, ] }, objectTypes: { doc_count: 0, pdf: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [] } }, statusTypes: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [{ key: 'completed', doc_count: 9 }] }, - jobTypes: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [ { key: 'csv_searchsource', doc_count: 5, isDeprecated: { doc_count: 0 } }, { key: 'csv', doc_count: 4, isDeprecated: { doc_count: 4 } }, ] }, + jobTypes: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [ { key: 'csv_searchsource', doc_count: 5, isDeprecated: { doc_count: 0 } }, { key: 'csv_searchsource', doc_count: 4, isDeprecated: { doc_count: 4 } }, ] }, }, last7Days: { doc_count: 9, layoutTypes: { doc_count: 0, pdf: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [] } }, - statusByApp: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [ { key: 'completed', doc_count: 9, jobTypes: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [ { key: 'csv_searchsource', doc_count: 5, appNames: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [{ key: 'search', doc_count: 5 }] } }, { key: 'csv', doc_count: 4, appNames: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [{ key: 'search', doc_count: 4 }] } }, ] } }, ] }, + statusByApp: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [ { key: 'completed', doc_count: 9, jobTypes: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [ { key: 'csv_searchsource', doc_count: 5, appNames: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [{ key: 'search', doc_count: 5 }] } }, { key: 'csv_searchsource', doc_count: 4, appNames: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [{ key: 'search', doc_count: 4 }] } }, ] } }, ] }, objectTypes: { doc_count: 0, pdf: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [] } }, statusTypes: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [{ key: 'completed', doc_count: 9 }] }, - jobTypes: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [ { key: 'csv_searchsource', doc_count: 5, isDeprecated: { doc_count: 0 } }, { key: 'csv', doc_count: 4, isDeprecated: { doc_count: 4 } }, ] }, + jobTypes: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [ { key: 'csv_searchsource', doc_count: 5, isDeprecated: { doc_count: 0 } }, { key: 'csv_searchsource', doc_count: 4, isDeprecated: { doc_count: 4 } }, ] }, }, }, // prettier-ignore }, @@ -297,18 +297,18 @@ describe('data modeling', () => { all: { doc_count: 4, layoutTypes: { doc_count: 2, pdf: { buckets: [{ key: 'preserve_layout', doc_count: 2 }] } }, - statusByApp: { buckets: [ { key: 'completed', doc_count: 4, jobTypes: { buckets: [ { key: 'printable_pdf', doc_count: 2, appNames: { buckets: [ { key: 'canvas workpad', doc_count: 1 }, { key: 'dashboard', doc_count: 1 }, ] } }, { key: 'PNG', doc_count: 1, appNames: { buckets: [{ key: 'dashboard', doc_count: 1 }] } }, { key: 'csv', doc_count: 1, appNames: { buckets: [] } }, ] } }, ] }, + statusByApp: { buckets: [ { key: 'completed', doc_count: 4, jobTypes: { buckets: [ { key: 'printable_pdf', doc_count: 2, appNames: { buckets: [ { key: 'canvas workpad', doc_count: 1 }, { key: 'dashboard', doc_count: 1 }, ] } }, { key: 'PNG', doc_count: 1, appNames: { buckets: [{ key: 'dashboard', doc_count: 1 }] } }, { key: 'csv_searchsource', doc_count: 1, appNames: { buckets: [] } }, ] } }, ] }, objectTypes: { doc_count: 2, pdf: { buckets: [ { key: 'canvas workpad', doc_count: 1 }, { key: 'dashboard', doc_count: 1 }, ] } }, statusTypes: { buckets: [{ key: 'completed', doc_count: 4 }] }, - jobTypes: { buckets: [ { key: 'printable_pdf', doc_count: 2 }, { key: 'PNG', doc_count: 1 }, { key: 'csv', doc_count: 1 }, ] }, + jobTypes: { buckets: [ { key: 'printable_pdf', doc_count: 2 }, { key: 'PNG', doc_count: 1 }, { key: 'csv_searchsource', doc_count: 1 }, ] }, }, last7Days: { doc_count: 4, layoutTypes: { doc_count: 2, pdf: { buckets: [{ key: 'preserve_layout', doc_count: 2 }] } }, - statusByApp: { buckets: [ { key: 'completed', doc_count: 4, jobTypes: { buckets: [ { key: 'printable_pdf', doc_count: 2, appNames: { buckets: [ { key: 'canvas workpad', doc_count: 1 }, { key: 'dashboard', doc_count: 1 }, ] } }, { key: 'PNG', doc_count: 1, appNames: { buckets: [{ key: 'dashboard', doc_count: 1 }] } }, { key: 'csv', doc_count: 1, appNames: { buckets: [] } }, ] } }, ] }, + statusByApp: { buckets: [ { key: 'completed', doc_count: 4, jobTypes: { buckets: [ { key: 'printable_pdf', doc_count: 2, appNames: { buckets: [ { key: 'canvas workpad', doc_count: 1 }, { key: 'dashboard', doc_count: 1 }, ] } }, { key: 'PNG', doc_count: 1, appNames: { buckets: [{ key: 'dashboard', doc_count: 1 }] } }, { key: 'csv_searchsource', doc_count: 1, appNames: { buckets: [] } }, ] } }, ] }, objectTypes: { doc_count: 2, pdf: { buckets: [ { key: 'canvas workpad', doc_count: 1 }, { key: 'dashboard', doc_count: 1 }, ] } }, statusTypes: { buckets: [{ key: 'completed', doc_count: 4 }] }, - jobTypes: { buckets: [ { key: 'printable_pdf', doc_count: 2 }, { key: 'PNG', doc_count: 1 }, { key: 'csv', doc_count: 1 }, ] }, + jobTypes: { buckets: [ { key: 'printable_pdf', doc_count: 2 }, { key: 'PNG', doc_count: 1 }, { key: 'csv_searchsource', doc_count: 1 }, ] }, }, }, // prettier-ignore }, diff --git a/x-pack/plugins/reporting/server/usage/types.ts b/x-pack/plugins/reporting/server/usage/types.ts index e6695abc8da74f..dd3b768996b0ed 100644 --- a/x-pack/plugins/reporting/server/usage/types.ts +++ b/x-pack/plugins/reporting/server/usage/types.ts @@ -89,7 +89,6 @@ export interface AvailableTotal { // FIXME: find a way to get this from exportTypesHandler or common/constants type BaseJobTypes = - | 'csv' | 'csv_searchsource' | 'csv_searchsource_immediate' | 'PNG' diff --git a/x-pack/test/reporting_api_integration/reporting_and_security/generate_csv_discover_deprecated.ts b/x-pack/test/reporting_api_integration/reporting_and_security/generate_csv_discover_deprecated.ts deleted file mode 100644 index bd662fb391f152..00000000000000 --- a/x-pack/test/reporting_api_integration/reporting_and_security/generate_csv_discover_deprecated.ts +++ /dev/null @@ -1,75 +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 supertest from 'supertest'; -import { FtrProviderContext } from '../ftr_provider_context'; -import { JOB_PARAMS_RISON_CSV_DEPRECATED } from '../services/fixtures'; - -// eslint-disable-next-line import/no-default-export -export default function ({ getService }: FtrProviderContext) { - const supertestSvc = getService('supertest'); - const reportingAPI = getService('reportingAPI'); - - const generateAPI = { - getCsvFromParamsInPayload: async (jobParams: object = {}) => { - return await supertestSvc - .post(`/api/reporting/generate/csv`) - .set('kbn-xsrf', 'xxx') - .send(jobParams); - }, - getCsvFromParamsInQueryString: async (jobParams: string = '') => { - return await supertestSvc - .post(`/api/reporting/generate/csv?jobParams=${encodeURIComponent(jobParams)}`) - .set('kbn-xsrf', 'xxx'); - }, - }; - - describe('Generation from Legacy Job Params', () => { - before(async () => { - await reportingAPI.initLogs(); - }); - - after(async () => { - await reportingAPI.teardownLogs(); - await reportingAPI.deleteAllReports(); - }); - - it('Rejects bogus jobParams', async () => { - const { status: resStatus, text: resText } = (await generateAPI.getCsvFromParamsInPayload({ - jobParams: 0, - })) as supertest.Response; - - expect(resText).to.match(/expected value of type \[string\] but got \[number\]/); - expect(resStatus).to.eql(400); - }); - - it('Rejects empty jobParams', async () => { - const { status: resStatus, text: resText } = - (await generateAPI.getCsvFromParamsInPayload()) as supertest.Response; - - expect(resStatus).to.eql(400); - expect(resText).to.match(/jobParams RISON string is required/); - }); - - it('Accepts jobParams in POST payload', async () => { - const { status: resStatus, text: resText } = (await generateAPI.getCsvFromParamsInPayload({ - jobParams: JOB_PARAMS_RISON_CSV_DEPRECATED, - })) as supertest.Response; - expect(resText).to.match(/"jobtype":"csv"/); - expect(resStatus).to.eql(200); - }); - - it('Accepts jobParams in query string', async () => { - const { status: resStatus, text: resText } = (await generateAPI.getCsvFromParamsInQueryString( - JOB_PARAMS_RISON_CSV_DEPRECATED - )) as supertest.Response; - expect(resText).to.match(/"jobtype":"csv"/); - expect(resStatus).to.eql(200); - }); - }); -} diff --git a/x-pack/test/reporting_api_integration/reporting_and_security/index.ts b/x-pack/test/reporting_api_integration/reporting_and_security/index.ts index 6ea6de34825012..82a4756717d927 100644 --- a/x-pack/test/reporting_api_integration/reporting_and_security/index.ts +++ b/x-pack/test/reporting_api_integration/reporting_and_security/index.ts @@ -26,7 +26,6 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./security_roles_privileges')); loadTestFile(require.resolve('./download_csv_dashboard')); loadTestFile(require.resolve('./generate_csv_discover')); - loadTestFile(require.resolve('./generate_csv_discover_deprecated')); loadTestFile(require.resolve('./network_policy')); loadTestFile(require.resolve('./spaces')); loadTestFile(require.resolve('./usage')); diff --git a/x-pack/test/reporting_api_integration/reporting_without_security/index.ts b/x-pack/test/reporting_api_integration/reporting_without_security/index.ts index 258ae814f5789a..72cfc369475175 100644 --- a/x-pack/test/reporting_api_integration/reporting_without_security/index.ts +++ b/x-pack/test/reporting_api_integration/reporting_without_security/index.ts @@ -16,6 +16,5 @@ export default function ({ loadTestFile, getService }: FtrProviderContext) { }); this.tags('ciGroup13'); loadTestFile(require.resolve('./job_apis_csv')); - loadTestFile(require.resolve('./job_apis_csv_deprecated')); }); } diff --git a/x-pack/test/reporting_api_integration/reporting_without_security/job_apis_csv_deprecated.ts b/x-pack/test/reporting_api_integration/reporting_without_security/job_apis_csv_deprecated.ts deleted file mode 100644 index 5cd60653526492..00000000000000 --- a/x-pack/test/reporting_api_integration/reporting_without_security/job_apis_csv_deprecated.ts +++ /dev/null @@ -1,189 +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 { pick } from 'lodash'; -import { ReportApiJSON } from '../../../plugins/reporting/common/types'; -import { FtrProviderContext } from '../ftr_provider_context'; -import { JOB_PARAMS_RISON_CSV_DEPRECATED } from '../services/fixtures'; - -const apiResponseFields = [ - 'attempts', - 'created_by', - 'jobtype', - 'meta', - 'payload.isDeprecated', - 'payload.title', - 'payload.type', - 'status', -]; - -const parseApiJSON = (apiResponseText: string): { job: ReportApiJSON; path: string } => - JSON.parse(apiResponseText); - -// eslint-disable-next-line import/no-default-export -export default function ({ getService }: FtrProviderContext) { - const supertestNoAuth = getService('supertestWithoutAuth'); - const reportingAPI = getService('reportingAPI'); - - describe('Job Listing APIs: Deprecated CSV Export', () => { - before(async () => { - await reportingAPI.initLogs(); - }); - - after(async () => { - await reportingAPI.teardownLogs(); - }); - - afterEach(async () => { - await reportingAPI.deleteAllReports(); - }); - - it('Posted CSV job is visible in the job count', async () => { - const { status: resStatus, text: resText } = await supertestNoAuth - .post(`/api/reporting/generate/csv`) - .set('kbn-xsrf', 'xxx') - .send({ jobParams: JOB_PARAMS_RISON_CSV_DEPRECATED }); - expect(resStatus).to.be(200); - - const { job, path } = parseApiJSON(resText); - expectSnapshot(pick(job, apiResponseFields)).toMatchInline(` - Object { - "attempts": 0, - "created_by": false, - "jobtype": "csv", - "meta": Object { - "isDeprecated": true, - }, - "payload": Object { - "isDeprecated": true, - "title": "A Saved Search With a DATE FILTER", - "type": "search", - }, - "status": "pending", - } - `); - - // call the job count api - const { text: countText } = await supertestNoAuth - .get(`/api/reporting/jobs/count`) - .set('kbn-xsrf', 'xxx'); - - const countResult = JSON.parse(countText); - expect(countResult).to.be(1); - - await reportingAPI.waitForJobToFinish(path); - }); - - it('Posted CSV job is visible in the status check', async () => { - const { status: resStatus, text: resText } = await supertestNoAuth - .post(`/api/reporting/generate/csv`) - .set('kbn-xsrf', 'xxx') - .send({ jobParams: JOB_PARAMS_RISON_CSV_DEPRECATED }); - expect(resStatus).to.be(200); - - const { job, path } = parseApiJSON(resText); - // call the single job listing api (status check) - const { text: listText } = await supertestNoAuth - .get(`/api/reporting/jobs/list?page=0&ids=${job.id}`) - .set('kbn-xsrf', 'xxx'); - - const listingJobs: ReportApiJSON[] = JSON.parse(listText); - expect(listingJobs[0].id).to.be(job.id); - expectSnapshot(listingJobs.map((j) => pick(j, apiResponseFields))).toMatchInline(` - Array [ - Object { - "attempts": 0, - "created_by": false, - "jobtype": "csv", - "meta": Object { - "isDeprecated": true, - }, - "payload": Object { - "isDeprecated": true, - "title": "A Saved Search With a DATE FILTER", - "type": "search", - }, - "status": "pending", - }, - ] - `); - - await reportingAPI.waitForJobToFinish(path); - }); - - it('Posted CSV job is visible in the first page of jobs listing', async () => { - const { status: resStatus, text: resText } = await supertestNoAuth - .post(`/api/reporting/generate/csv`) - .set('kbn-xsrf', 'xxx') - .send({ jobParams: JOB_PARAMS_RISON_CSV_DEPRECATED }); - expect(resStatus).to.be(200); - - const { job, path } = parseApiJSON(resText); - // call the ALL job listing api - const { text: listText } = await supertestNoAuth - .get(`/api/reporting/jobs/list?page=0`) - .set('kbn-xsrf', 'xxx'); - - const listingJobs: ReportApiJSON[] = JSON.parse(listText); - expect(listingJobs[0].id).to.eql(job.id); - expectSnapshot(listingJobs.map((j) => pick(j, apiResponseFields))).toMatchInline(` - Array [ - Object { - "attempts": 0, - "created_by": false, - "jobtype": "csv", - "meta": Object { - "isDeprecated": true, - }, - "payload": Object { - "isDeprecated": true, - "title": "A Saved Search With a DATE FILTER", - "type": "search", - }, - "status": "pending", - }, - ] - `); - - await reportingAPI.waitForJobToFinish(path); - }); - - it('Posted CSV job details are visible in the info API', async () => { - const { status: resStatus, text: resText } = await supertestNoAuth - .post(`/api/reporting/generate/csv`) - .set('kbn-xsrf', 'xxx') - .send({ jobParams: JOB_PARAMS_RISON_CSV_DEPRECATED }); - expect(resStatus).to.be(200); - - const { job, path } = parseApiJSON(resText); - const { text: infoText } = await supertestNoAuth - .get(`/api/reporting/jobs/info/${job.id}`) - .set('kbn-xsrf', 'xxx'); - - const info = JSON.parse(infoText); - expectSnapshot(pick(info, apiResponseFields)).toMatchInline(` - Object { - "attempts": 0, - "created_by": false, - "jobtype": "csv", - "meta": Object { - "isDeprecated": true, - }, - "payload": Object { - "isDeprecated": true, - "title": "A Saved Search With a DATE FILTER", - "type": "search", - }, - "status": "pending", - } - `); - - await reportingAPI.waitForJobToFinish(path); - }); - }); -} diff --git a/x-pack/test/reporting_api_integration/services/fixtures.ts b/x-pack/test/reporting_api_integration/services/fixtures.ts deleted file mode 100644 index af87c84df97d0a..00000000000000 --- a/x-pack/test/reporting_api_integration/services/fixtures.ts +++ /dev/null @@ -1,42 +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. - */ - -// This concatenates lines of multi-line string into a single line. -// It is so long strings can be entered at short widths, making syntax highlighting easier on editors -function singleLine(literals: TemplateStringsArray): string { - return literals[0].split('\n').join(''); -} - -export const JOB_PARAMS_RISON_CSV_DEPRECATED = singleLine`(conflictedTypesFields:!(),fields:!('@ti -mestamp',clientip,extension),indexPatternId:'logstash-*',metaFields:!(_source,_id,_type,_ -index,_score),searchRequest:(body:(_source:(excludes:!(),includes:!('@timestamp',clientip -,extension)),docvalue_fields:!(),query:(bool:(filter:!((match_all:()),(range:('@timestamp -':(gte:'2015-09-20T10:19:40.307Z',lt:'2015-09-20T10:26:56.221Z'))),(range:('@timestamp':( -format:strict_date_optional_time,gte:'2004-09-17T21:19:34.213Z',lte:'2019-09-17T21:19:34. -213Z')))),must:!(),must_not:!(),should:!())),script_fields:(),sort:!(('@timestamp':(order -:desc,unmapped_type:boolean))),stored_fields:!('@timestamp',clientip,extension),version:! -t),index:'logstash-*'),title:'A Saved Search With a DATE FILTER',type:search)`; - -export const JOB_PARAMS_ECOM_MARKDOWN = singleLine`(browserTimezone:UTC,layout:(dimensions:(height:354.6000061035156,width:768),id:png),objectType:visualization,relativeUrl:\' - /app/visualize#/edit/4a36acd0-7ac3-11ea-b69c-cf0d7935cd67?_g=(filters:\u0021\u0021(),refreshInterval:(pause:\u0021\u0021t,value:0),time:(from:now-15m,to:no - w))&_a=(filters:\u0021\u0021(),linked:\u0021\u0021f,query:(language:kuery,query:\u0021\'\u0021\'),uiState:(),vis:(aggs:\u0021\u0021(),params:(fontSize:12,ma - rkdown:\u0021\'Ti%E1%BB%83u%20thuy%E1%BA%BFt%20l%C3%A0%20m%E1%BB%99t%20th%E1%BB%83%20lo%E1%BA%A1i%20v%C4%83n%20xu%C3%B4i%20c%C3%B3%20h%C6%B0%20c%E1%BA%A5u,% - 20th%C3%B4ng%20qua%20nh%C3%A2n%20v%E1%BA%ADt,%20ho%C3%A0n%20c%E1%BA%A3nh,%20s%E1%BB%B1%20vi%E1%BB%87c%20%C4%91%E1%BB%83%20ph%E1%BA%A3n%20%C3%A1nh%20b%E1%BB% - A9c%20tranh%20x%C3%A3%20h%E1%BB%99i%20r%E1%BB%99ng%20l%E1%BB%9Bn%20v%C3%A0%20nh%E1%BB%AFng%20v%E1%BA%A5n%20%C4%91%E1%BB%81%20c%E1%BB%A7a%20cu%E1%BB%99c%20s% - E1%BB%91ng%20con%20ng%C6%B0%E1%BB%9Di,%20bi%E1%BB%83u%20hi%E1%BB%87n%20t%C3%ADnh%20ch%E1%BA%A5t%20t%C6%B0%E1%BB%9Dng%20thu%E1%BA%ADt,%20t%C3%ADnh%20ch%E1%BA - %A5t%20k%E1%BB%83%20chuy%E1%BB%87n%20b%E1%BA%B1ng%20ng%C3%B4n%20ng%E1%BB%AF%20v%C4%83n%20xu%C3%B4i%20theo%20nh%E1%BB%AFng%20ch%E1%BB%A7%20%C4%91%E1%BB%81%20 - x%C3%A1c%20%C4%91%E1%BB%8Bnh.%0A%0ATrong%20m%E1%BB%99t%20c%C3%A1ch%20hi%E1%BB%83u%20kh%C3%A1c,%20nh%E1%BA%ADn%20%C4%91%E1%BB%8Bnh%20c%E1%BB%A7a%20Belinski:% - 20%22ti%E1%BB%83u%20thuy%E1%BA%BFt%20l%C3%A0%20s%E1%BB%AD%20thi%20c%E1%BB%A7a%20%C4%91%E1%BB%9Di%20t%C6%B0%22%20ch%E1%BB%89%20ra%20kh%C3%A1i%20qu%C3%A1t%20n - h%E1%BA%A5t%20v%E1%BB%81%20m%E1%BB%99t%20d%E1%BA%A1ng%20th%E1%BB%A9c%20t%E1%BB%B1%20s%E1%BB%B1,%20trong%20%C4%91%C3%B3%20s%E1%BB%B1%20tr%E1%BA%A7n%20thu%E1% - BA%ADt%20t%E1%BA%ADp%20trung%20v%C3%A0o%20s%E1%BB%91%20ph%E1%BA%ADn%20c%E1%BB%A7a%20m%E1%BB%99t%20c%C3%A1%20nh%C3%A2n%20trong%20qu%C3%A1%20tr%C3%ACnh%20h%C3 - %ACnh%20th%C3%A0nh%20v%C3%A0%20ph%C3%A1t%20tri%E1%BB%83n%20c%E1%BB%A7a%20n%C3%B3.%20S%E1%BB%B1%20tr%E1%BA%A7n%20thu%E1%BA%ADt%20%E1%BB%9F%20%C4%91%C3%A2y%20 - %C4%91%C6%B0%E1%BB%A3c%20khai%20tri%E1%BB%83n%20trong%20kh%C3%B4ng%20gian%20v%C3%A0%20th%E1%BB%9Di%20gian%20ngh%E1%BB%87%20thu%E1%BA%ADt%20%C4%91%E1%BA%BFn% - 20m%E1%BB%A9c%20%C4%91%E1%BB%A7%20%C4%91%E1%BB%83%20truy%E1%BB%81n%20%C4%91%E1%BA%A1t%20c%C6%A1%20c%E1%BA%A5u%20c%E1%BB%A7a%20nh%C3%A2n%20c%C3%A1ch%5B1%5D.% - 0A%0A%0A%5B1%5D%5E%20M%E1%BB%A5c%20t%E1%BB%AB%20Ti%E1%BB%83u%20thuy%E1%BA%BFt%20trong%20cu%E1%BB%91n%20150%20thu%E1%BA%ADt%20ng%E1%BB%AF%20v%C4%83n%20h%E1%B - B%8Dc,%20L%E1%BA%A1i%20Nguy%C3%AAn%20%C3%82n%20bi%C3%AAn%20so%E1%BA%A1n,%20Nh%C3%A0%20xu%E1%BA%A5t%20b%E1%BA%A3n%20%C4%90%E1%BA%A1i%20h%E1%BB%8Dc%20Qu%E1%BB - %91c%20gia%20H%C3%A0%20N%E1%BB%99i,%20in%20l%E1%BA%A7n%20th%E1%BB%A9%202%20c%C3%B3%20s%E1%BB%ADa%20%C4%91%E1%BB%95i%20b%E1%BB%95%20sung.%20H.%202003.%20Tran - g%20326.\u0021\',openLinksInNewTab:\u0021\u0021f),title:\u0021\'Ti%E1%BB%83u%20thuy%E1%BA%BFt\u0021\',type:markdown))\',title:\'Tiểu thuyết\')`; diff --git a/x-pack/test/reporting_functional/reporting_without_security/management.ts b/x-pack/test/reporting_functional/reporting_without_security/management.ts index b0088ccb9a9055..36589d375b0e03 100644 --- a/x-pack/test/reporting_functional/reporting_without_security/management.ts +++ b/x-pack/test/reporting_functional/reporting_without_security/management.ts @@ -6,9 +6,33 @@ */ import expect from '@kbn/expect'; -import { JOB_PARAMS_ECOM_MARKDOWN } from '../../reporting_api_integration/services/fixtures'; import { FtrProviderContext } from '../ftr_provider_context'; +// This concatenates lines of multi-line string into a single line. +// It is so long strings can be entered at short widths, making syntax highlighting easier on editors +function singleLine(literals: TemplateStringsArray): string { + return literals[0].split('\n').join(''); +} +const JOB_PARAMS_ECOM_MARKDOWN = singleLine`(browserTimezone:UTC,layout:(dimensions:(height:354.6000061035156,width:768),id:png),objectType:visualization,relativeUrl:\' + /app/visualize#/edit/4a36acd0-7ac3-11ea-b69c-cf0d7935cd67?_g=(filters:\u0021\u0021(),refreshInterval:(pause:\u0021\u0021t,value:0),time:(from:now-15m,to:no + w))&_a=(filters:\u0021\u0021(),linked:\u0021\u0021f,query:(language:kuery,query:\u0021\'\u0021\'),uiState:(),vis:(aggs:\u0021\u0021(),params:(fontSize:12,ma + rkdown:\u0021\'Ti%E1%BB%83u%20thuy%E1%BA%BFt%20l%C3%A0%20m%E1%BB%99t%20th%E1%BB%83%20lo%E1%BA%A1i%20v%C4%83n%20xu%C3%B4i%20c%C3%B3%20h%C6%B0%20c%E1%BA%A5u,% + 20th%C3%B4ng%20qua%20nh%C3%A2n%20v%E1%BA%ADt,%20ho%C3%A0n%20c%E1%BA%A3nh,%20s%E1%BB%B1%20vi%E1%BB%87c%20%C4%91%E1%BB%83%20ph%E1%BA%A3n%20%C3%A1nh%20b%E1%BB% + A9c%20tranh%20x%C3%A3%20h%E1%BB%99i%20r%E1%BB%99ng%20l%E1%BB%9Bn%20v%C3%A0%20nh%E1%BB%AFng%20v%E1%BA%A5n%20%C4%91%E1%BB%81%20c%E1%BB%A7a%20cu%E1%BB%99c%20s% + E1%BB%91ng%20con%20ng%C6%B0%E1%BB%9Di,%20bi%E1%BB%83u%20hi%E1%BB%87n%20t%C3%ADnh%20ch%E1%BA%A5t%20t%C6%B0%E1%BB%9Dng%20thu%E1%BA%ADt,%20t%C3%ADnh%20ch%E1%BA + %A5t%20k%E1%BB%83%20chuy%E1%BB%87n%20b%E1%BA%B1ng%20ng%C3%B4n%20ng%E1%BB%AF%20v%C4%83n%20xu%C3%B4i%20theo%20nh%E1%BB%AFng%20ch%E1%BB%A7%20%C4%91%E1%BB%81%20 + x%C3%A1c%20%C4%91%E1%BB%8Bnh.%0A%0ATrong%20m%E1%BB%99t%20c%C3%A1ch%20hi%E1%BB%83u%20kh%C3%A1c,%20nh%E1%BA%ADn%20%C4%91%E1%BB%8Bnh%20c%E1%BB%A7a%20Belinski:% + 20%22ti%E1%BB%83u%20thuy%E1%BA%BFt%20l%C3%A0%20s%E1%BB%AD%20thi%20c%E1%BB%A7a%20%C4%91%E1%BB%9Di%20t%C6%B0%22%20ch%E1%BB%89%20ra%20kh%C3%A1i%20qu%C3%A1t%20n + h%E1%BA%A5t%20v%E1%BB%81%20m%E1%BB%99t%20d%E1%BA%A1ng%20th%E1%BB%A9c%20t%E1%BB%B1%20s%E1%BB%B1,%20trong%20%C4%91%C3%B3%20s%E1%BB%B1%20tr%E1%BA%A7n%20thu%E1% + BA%ADt%20t%E1%BA%ADp%20trung%20v%C3%A0o%20s%E1%BB%91%20ph%E1%BA%ADn%20c%E1%BB%A7a%20m%E1%BB%99t%20c%C3%A1%20nh%C3%A2n%20trong%20qu%C3%A1%20tr%C3%ACnh%20h%C3 + %ACnh%20th%C3%A0nh%20v%C3%A0%20ph%C3%A1t%20tri%E1%BB%83n%20c%E1%BB%A7a%20n%C3%B3.%20S%E1%BB%B1%20tr%E1%BA%A7n%20thu%E1%BA%ADt%20%E1%BB%9F%20%C4%91%C3%A2y%20 + %C4%91%C6%B0%E1%BB%A3c%20khai%20tri%E1%BB%83n%20trong%20kh%C3%B4ng%20gian%20v%C3%A0%20th%E1%BB%9Di%20gian%20ngh%E1%BB%87%20thu%E1%BA%ADt%20%C4%91%E1%BA%BFn% + 20m%E1%BB%A9c%20%C4%91%E1%BB%A7%20%C4%91%E1%BB%83%20truy%E1%BB%81n%20%C4%91%E1%BA%A1t%20c%C6%A1%20c%E1%BA%A5u%20c%E1%BB%A7a%20nh%C3%A2n%20c%C3%A1ch%5B1%5D.% + 0A%0A%0A%5B1%5D%5E%20M%E1%BB%A5c%20t%E1%BB%AB%20Ti%E1%BB%83u%20thuy%E1%BA%BFt%20trong%20cu%E1%BB%91n%20150%20thu%E1%BA%ADt%20ng%E1%BB%AF%20v%C4%83n%20h%E1%B + B%8Dc,%20L%E1%BA%A1i%20Nguy%C3%AAn%20%C3%82n%20bi%C3%AAn%20so%E1%BA%A1n,%20Nh%C3%A0%20xu%E1%BA%A5t%20b%E1%BA%A3n%20%C4%90%E1%BA%A1i%20h%E1%BB%8Dc%20Qu%E1%BB + %91c%20gia%20H%C3%A0%20N%E1%BB%99i,%20in%20l%E1%BA%A7n%20th%E1%BB%A9%202%20c%C3%B3%20s%E1%BB%ADa%20%C4%91%E1%BB%95i%20b%E1%BB%95%20sung.%20H.%202003.%20Tran + g%20326.\u0021\',openLinksInNewTab:\u0021\u0021f),title:\u0021\'Ti%E1%BB%83u%20thuy%E1%BA%BFt\u0021\',type:markdown))\',title:\'Tiểu thuyết\')`; + // eslint-disable-next-line import/no-default-export export default ({ getPageObjects, getService }: FtrProviderContext) => { const PageObjects = getPageObjects(['common', 'reporting']); From 331998cef8cdc4da8b790f8e0ee5e9ad546a0aae Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Thu, 16 Dec 2021 12:52:13 -0700 Subject: [PATCH 05/13] fix a11y test --- x-pack/test/accessibility/apps/reporting.ts | 25 ++++++++++++--------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/x-pack/test/accessibility/apps/reporting.ts b/x-pack/test/accessibility/apps/reporting.ts index 91356ef85972bd..be4fb78682c171 100644 --- a/x-pack/test/accessibility/apps/reporting.ts +++ b/x-pack/test/accessibility/apps/reporting.ts @@ -7,14 +7,11 @@ import { FtrProviderContext } from '../ftr_provider_context'; -import { JOB_PARAMS_RISON_CSV_DEPRECATED } from '../../reporting_api_integration/services/fixtures'; - export default function ({ getService, getPageObjects }: FtrProviderContext) { const { common } = getPageObjects(['common']); const retry = getService('retry'); const a11y = getService('a11y'); const testSubjects = getService('testSubjects'); - const supertestWithoutAuth = getService('supertestWithoutAuth'); const reporting = getService('reporting'); const security = getService('security'); @@ -32,7 +29,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }; before(async () => { - await reporting.initLogs(); + await reporting.initEcommerce(); await createReportingUser(); await reporting.loginReportingUser(); }); @@ -43,13 +40,19 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); beforeEach(async () => { - // Add one report - await supertestWithoutAuth - .post(`/api/reporting/generate/csv`) - .auth(reporting.REPORTING_USER_USERNAME, reporting.REPORTING_USER_PASSWORD) - .set('kbn-xsrf', 'xxx') - .send({ jobParams: JOB_PARAMS_RISON_CSV_DEPRECATED }) - .expect(200); + await reporting.generateCsv({ + title: 'CSV Report', + browserTimezone: 'UTC', + objectType: 'search', + version: '7.15.0', + searchSource: { + version: true, + query: { query: '', language: 'kuery' }, + index: '5193f870-d861-11e9-a311-0fa548c5f953', + fields: ['*'], + filter: [], + }, + }); await retry.waitFor('Reporting app', async () => { await common.navigateToApp('reporting'); From e0f196f1e8b9f7fbf7f8a9532652a837c75bc576 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Thu, 16 Dec 2021 12:53:03 -0700 Subject: [PATCH 06/13] fix bwc test --- .../reporting_and_security/bwc_generation_urls.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/x-pack/test/reporting_api_integration/reporting_and_security/bwc_generation_urls.ts b/x-pack/test/reporting_api_integration/reporting_and_security/bwc_generation_urls.ts index 03e1592df0818a..97626dae5b2814 100644 --- a/x-pack/test/reporting_api_integration/reporting_and_security/bwc_generation_urls.ts +++ b/x-pack/test/reporting_api_integration/reporting_and_security/bwc_generation_urls.ts @@ -53,7 +53,6 @@ export default function ({ getService }: FtrProviderContext) { const reportPaths = []; reportPaths.push(await reportingAPI.postJob(GenerationUrls.PDF_PRINT_DASHBOARD_6_2)); reportPaths.push(await reportingAPI.postJob(GenerationUrls.PDF_PRESERVE_VISUALIZATION_6_2)); - reportPaths.push(await reportingAPI.postJob(GenerationUrls.CSV_DISCOVER_FILTER_QUERY_6_2)); await reportingAPI.expectAllJobsToFinishSuccessfully(reportPaths); }).timeout(1540000); From b732be93c8386e691bc5793bb9b52cc67c91a3f8 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Thu, 16 Dec 2021 13:48:03 -0700 Subject: [PATCH 07/13] fix ts --- .../reporting/server/export_types/csv_searchsource/types.ts | 2 +- x-pack/plugins/reporting/server/usage/schema.ts | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/x-pack/plugins/reporting/server/export_types/csv_searchsource/types.ts b/x-pack/plugins/reporting/server/export_types/csv_searchsource/types.ts index 57e154eb2b26fc..bfba08cbeb0607 100644 --- a/x-pack/plugins/reporting/server/export_types/csv_searchsource/types.ts +++ b/x-pack/plugins/reporting/server/export_types/csv_searchsource/types.ts @@ -5,4 +5,4 @@ * 2.0. */ -export type { RawValue, JobParamsCSV, TaskPayloadCSV } from '../../../common/types'; +export type { JobParamsCSV, TaskPayloadCSV } from '../../../common/types'; diff --git a/x-pack/plugins/reporting/server/usage/schema.ts b/x-pack/plugins/reporting/server/usage/schema.ts index fc464903edaee6..6b4b7e265e3f1b 100644 --- a/x-pack/plugins/reporting/server/usage/schema.ts +++ b/x-pack/plugins/reporting/server/usage/schema.ts @@ -31,7 +31,6 @@ const layoutCountsSchema: MakeSchemaFrom = { }; const byAppCountsSchema: MakeSchemaFrom = { - csv: appCountsSchema, csv_searchsource: appCountsSchema, csv_searchsource_immediate: appCountsSchema, PNG: appCountsSchema, @@ -60,7 +59,6 @@ const availableTotalSchema: MakeSchemaFrom = { }; const jobTypesSchema: MakeSchemaFrom = { - csv: availableTotalSchema, csv_searchsource: availableTotalSchema, csv_searchsource_immediate: availableTotalSchema, PNG: availableTotalSchema, From 6cfa023f09b1a46798b3553d6a01e4edc1d6b9de Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Thu, 16 Dec 2021 14:55:04 -0700 Subject: [PATCH 08/13] fix test snapshot --- .../reporting_usage_collector.test.ts.snap | 258 ------------------ 1 file changed, 258 deletions(-) diff --git a/x-pack/plugins/reporting/server/usage/__snapshots__/reporting_usage_collector.test.ts.snap b/x-pack/plugins/reporting/server/usage/__snapshots__/reporting_usage_collector.test.ts.snap index 16596eb2cc0b1f..6275d10edc3d62 100644 --- a/x-pack/plugins/reporting/server/usage/__snapshots__/reporting_usage_collector.test.ts.snap +++ b/x-pack/plugins/reporting/server/usage/__snapshots__/reporting_usage_collector.test.ts.snap @@ -129,65 +129,6 @@ Object { "available": Object { "type": "boolean", }, - "csv": Object { - "app": Object { - "canvas workpad": Object { - "type": "long", - }, - "dashboard": Object { - "type": "long", - }, - "search": Object { - "type": "long", - }, - "visualization": Object { - "type": "long", - }, - }, - "available": Object { - "type": "boolean", - }, - "deprecated": Object { - "type": "long", - }, - "layout": Object { - "canvas": Object { - "type": "long", - }, - "preserve_layout": Object { - "type": "long", - }, - "print": Object { - "type": "long", - }, - }, - "sizes": Object { - "1.0": Object { - "type": "long", - }, - "25.0": Object { - "type": "long", - }, - "5.0": Object { - "type": "long", - }, - "50.0": Object { - "type": "long", - }, - "75.0": Object { - "type": "long", - }, - "95.0": Object { - "type": "long", - }, - "99.0": Object { - "type": "long", - }, - }, - "total": Object { - "type": "long", - }, - }, "csv_searchsource": Object { "app": Object { "canvas workpad": Object { @@ -431,65 +372,6 @@ Object { "_all": Object { "type": "long", }, - "csv": Object { - "app": Object { - "canvas workpad": Object { - "type": "long", - }, - "dashboard": Object { - "type": "long", - }, - "search": Object { - "type": "long", - }, - "visualization": Object { - "type": "long", - }, - }, - "available": Object { - "type": "boolean", - }, - "deprecated": Object { - "type": "long", - }, - "layout": Object { - "canvas": Object { - "type": "long", - }, - "preserve_layout": Object { - "type": "long", - }, - "print": Object { - "type": "long", - }, - }, - "sizes": Object { - "1.0": Object { - "type": "long", - }, - "25.0": Object { - "type": "long", - }, - "5.0": Object { - "type": "long", - }, - "50.0": Object { - "type": "long", - }, - "75.0": Object { - "type": "long", - }, - "95.0": Object { - "type": "long", - }, - "99.0": Object { - "type": "long", - }, - }, - "total": Object { - "type": "long", - }, - }, "csv_searchsource": Object { "app": Object { "canvas workpad": Object { @@ -796,20 +678,6 @@ Object { "type": "long", }, }, - "csv": Object { - "canvas workpad": Object { - "type": "long", - }, - "dashboard": Object { - "type": "long", - }, - "search": Object { - "type": "long", - }, - "visualization": Object { - "type": "long", - }, - }, "csv_searchsource": Object { "canvas workpad": Object { "type": "long", @@ -896,20 +764,6 @@ Object { "type": "long", }, }, - "csv": Object { - "canvas workpad": Object { - "type": "long", - }, - "dashboard": Object { - "type": "long", - }, - "search": Object { - "type": "long", - }, - "visualization": Object { - "type": "long", - }, - }, "csv_searchsource": Object { "canvas workpad": Object { "type": "long", @@ -996,20 +850,6 @@ Object { "type": "long", }, }, - "csv": Object { - "canvas workpad": Object { - "type": "long", - }, - "dashboard": Object { - "type": "long", - }, - "search": Object { - "type": "long", - }, - "visualization": Object { - "type": "long", - }, - }, "csv_searchsource": Object { "canvas workpad": Object { "type": "long", @@ -1096,20 +936,6 @@ Object { "type": "long", }, }, - "csv": Object { - "canvas workpad": Object { - "type": "long", - }, - "dashboard": Object { - "type": "long", - }, - "search": Object { - "type": "long", - }, - "visualization": Object { - "type": "long", - }, - }, "csv_searchsource": Object { "canvas workpad": Object { "type": "long", @@ -1196,20 +1022,6 @@ Object { "type": "long", }, }, - "csv": Object { - "canvas workpad": Object { - "type": "long", - }, - "dashboard": Object { - "type": "long", - }, - "search": Object { - "type": "long", - }, - "visualization": Object { - "type": "long", - }, - }, "csv_searchsource": Object { "canvas workpad": Object { "type": "long", @@ -1457,20 +1269,6 @@ Object { "type": "long", }, }, - "csv": Object { - "canvas workpad": Object { - "type": "long", - }, - "dashboard": Object { - "type": "long", - }, - "search": Object { - "type": "long", - }, - "visualization": Object { - "type": "long", - }, - }, "csv_searchsource": Object { "canvas workpad": Object { "type": "long", @@ -1557,20 +1355,6 @@ Object { "type": "long", }, }, - "csv": Object { - "canvas workpad": Object { - "type": "long", - }, - "dashboard": Object { - "type": "long", - }, - "search": Object { - "type": "long", - }, - "visualization": Object { - "type": "long", - }, - }, "csv_searchsource": Object { "canvas workpad": Object { "type": "long", @@ -1657,20 +1441,6 @@ Object { "type": "long", }, }, - "csv": Object { - "canvas workpad": Object { - "type": "long", - }, - "dashboard": Object { - "type": "long", - }, - "search": Object { - "type": "long", - }, - "visualization": Object { - "type": "long", - }, - }, "csv_searchsource": Object { "canvas workpad": Object { "type": "long", @@ -1757,20 +1527,6 @@ Object { "type": "long", }, }, - "csv": Object { - "canvas workpad": Object { - "type": "long", - }, - "dashboard": Object { - "type": "long", - }, - "search": Object { - "type": "long", - }, - "visualization": Object { - "type": "long", - }, - }, "csv_searchsource": Object { "canvas workpad": Object { "type": "long", @@ -1857,20 +1613,6 @@ Object { "type": "long", }, }, - "csv": Object { - "canvas workpad": Object { - "type": "long", - }, - "dashboard": Object { - "type": "long", - }, - "search": Object { - "type": "long", - }, - "visualization": Object { - "type": "long", - }, - }, "csv_searchsource": Object { "canvas workpad": Object { "type": "long", From cbf47c726a20cf7078545808237993f5ecb1f300 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Thu, 16 Dec 2021 15:00:19 -0700 Subject: [PATCH 09/13] fix test --- .../reporting_and_security/usage.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/x-pack/test/reporting_api_integration/reporting_and_security/usage.ts b/x-pack/test/reporting_api_integration/reporting_and_security/usage.ts index 4f17d753faf0e9..ec44ae1e82cccc 100644 --- a/x-pack/test/reporting_api_integration/reporting_and_security/usage.ts +++ b/x-pack/test/reporting_api_integration/reporting_and_security/usage.ts @@ -70,10 +70,7 @@ export default function ({ getService }: FtrProviderContext) { await esArchiver.load('x-pack/test/functional/es_archives/reporting/bwc/6_2'); const usage = await usageAPI.getUsageStats(); - reportingAPI.expectRecentJobTypeTotalStats(usage, 'csv', 0); reportingAPI.expectRecentJobTypeTotalStats(usage, 'printable_pdf', 0); - - reportingAPI.expectAllTimeJobTypeTotalStats(usage, 'csv', 1); reportingAPI.expectAllTimeJobTypeTotalStats(usage, 'printable_pdf', 7); // These statistics weren't tracked until 6.3 @@ -93,14 +90,12 @@ export default function ({ getService }: FtrProviderContext) { await esArchiver.load('x-pack/test/functional/es_archives/reporting/bwc/6_3'); const usage = await usageAPI.getUsageStats(); - reportingAPI.expectRecentJobTypeTotalStats(usage, 'csv', 0); reportingAPI.expectRecentJobTypeTotalStats(usage, 'printable_pdf', 0); reportingAPI.expectRecentPdfAppStats(usage, 'visualization', 0); reportingAPI.expectRecentPdfAppStats(usage, 'dashboard', 0); reportingAPI.expectRecentPdfLayoutStats(usage, 'preserve_layout', 0); reportingAPI.expectRecentPdfLayoutStats(usage, 'print', 0); - reportingAPI.expectAllTimeJobTypeTotalStats(usage, 'csv', 2); reportingAPI.expectAllTimeJobTypeTotalStats(usage, 'printable_pdf', 12); reportingAPI.expectAllTimePdfAppStats(usage, 'visualization', 3); reportingAPI.expectAllTimePdfAppStats(usage, 'dashboard', 3); From 3b66c8cd816e1571efead367e78abea1656f51ee Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Thu, 16 Dec 2021 15:03:05 -0700 Subject: [PATCH 10/13] fix telemetry mappings --- .../schema/xpack_plugins.json | 294 ------------------ 1 file changed, 294 deletions(-) diff --git a/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json b/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json index d7415221ab09f5..49404639208728 100644 --- a/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json +++ b/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json @@ -4925,73 +4925,6 @@ }, "reporting": { "properties": { - "csv": { - "properties": { - "available": { - "type": "boolean" - }, - "total": { - "type": "long" - }, - "deprecated": { - "type": "long" - }, - "sizes": { - "properties": { - "1.0": { - "type": "long" - }, - "5.0": { - "type": "long" - }, - "25.0": { - "type": "long" - }, - "50.0": { - "type": "long" - }, - "75.0": { - "type": "long" - }, - "95.0": { - "type": "long" - }, - "99.0": { - "type": "long" - } - } - }, - "app": { - "properties": { - "search": { - "type": "long" - }, - "canvas workpad": { - "type": "long" - }, - "dashboard": { - "type": "long" - }, - "visualization": { - "type": "long" - } - } - }, - "layout": { - "properties": { - "canvas": { - "type": "long" - }, - "print": { - "type": "long" - }, - "preserve_layout": { - "type": "long" - } - } - } - } - }, "csv_searchsource": { "properties": { "available": { @@ -5420,22 +5353,6 @@ "properties": { "completed": { "properties": { - "csv": { - "properties": { - "search": { - "type": "long" - }, - "canvas workpad": { - "type": "long" - }, - "dashboard": { - "type": "long" - }, - "visualization": { - "type": "long" - } - } - }, "csv_searchsource": { "properties": { "search": { @@ -5536,22 +5453,6 @@ }, "completed_with_warnings": { "properties": { - "csv": { - "properties": { - "search": { - "type": "long" - }, - "canvas workpad": { - "type": "long" - }, - "dashboard": { - "type": "long" - }, - "visualization": { - "type": "long" - } - } - }, "csv_searchsource": { "properties": { "search": { @@ -5652,22 +5553,6 @@ }, "failed": { "properties": { - "csv": { - "properties": { - "search": { - "type": "long" - }, - "canvas workpad": { - "type": "long" - }, - "dashboard": { - "type": "long" - }, - "visualization": { - "type": "long" - } - } - }, "csv_searchsource": { "properties": { "search": { @@ -5768,22 +5653,6 @@ }, "pending": { "properties": { - "csv": { - "properties": { - "search": { - "type": "long" - }, - "canvas workpad": { - "type": "long" - }, - "dashboard": { - "type": "long" - }, - "visualization": { - "type": "long" - } - } - }, "csv_searchsource": { "properties": { "search": { @@ -5884,22 +5753,6 @@ }, "processing": { "properties": { - "csv": { - "properties": { - "search": { - "type": "long" - }, - "canvas workpad": { - "type": "long" - }, - "dashboard": { - "type": "long" - }, - "visualization": { - "type": "long" - } - } - }, "csv_searchsource": { "properties": { "search": { @@ -6033,73 +5886,6 @@ }, "last7Days": { "properties": { - "csv": { - "properties": { - "available": { - "type": "boolean" - }, - "total": { - "type": "long" - }, - "deprecated": { - "type": "long" - }, - "sizes": { - "properties": { - "1.0": { - "type": "long" - }, - "5.0": { - "type": "long" - }, - "25.0": { - "type": "long" - }, - "50.0": { - "type": "long" - }, - "75.0": { - "type": "long" - }, - "95.0": { - "type": "long" - }, - "99.0": { - "type": "long" - } - } - }, - "app": { - "properties": { - "search": { - "type": "long" - }, - "canvas workpad": { - "type": "long" - }, - "dashboard": { - "type": "long" - }, - "visualization": { - "type": "long" - } - } - }, - "layout": { - "properties": { - "canvas": { - "type": "long" - }, - "print": { - "type": "long" - }, - "preserve_layout": { - "type": "long" - } - } - } - } - }, "csv_searchsource": { "properties": { "available": { @@ -6528,22 +6314,6 @@ "properties": { "completed": { "properties": { - "csv": { - "properties": { - "search": { - "type": "long" - }, - "canvas workpad": { - "type": "long" - }, - "dashboard": { - "type": "long" - }, - "visualization": { - "type": "long" - } - } - }, "csv_searchsource": { "properties": { "search": { @@ -6644,22 +6414,6 @@ }, "completed_with_warnings": { "properties": { - "csv": { - "properties": { - "search": { - "type": "long" - }, - "canvas workpad": { - "type": "long" - }, - "dashboard": { - "type": "long" - }, - "visualization": { - "type": "long" - } - } - }, "csv_searchsource": { "properties": { "search": { @@ -6760,22 +6514,6 @@ }, "failed": { "properties": { - "csv": { - "properties": { - "search": { - "type": "long" - }, - "canvas workpad": { - "type": "long" - }, - "dashboard": { - "type": "long" - }, - "visualization": { - "type": "long" - } - } - }, "csv_searchsource": { "properties": { "search": { @@ -6876,22 +6614,6 @@ }, "pending": { "properties": { - "csv": { - "properties": { - "search": { - "type": "long" - }, - "canvas workpad": { - "type": "long" - }, - "dashboard": { - "type": "long" - }, - "visualization": { - "type": "long" - } - } - }, "csv_searchsource": { "properties": { "search": { @@ -6992,22 +6714,6 @@ }, "processing": { "properties": { - "csv": { - "properties": { - "search": { - "type": "long" - }, - "canvas workpad": { - "type": "long" - }, - "dashboard": { - "type": "long" - }, - "visualization": { - "type": "long" - } - } - }, "csv_searchsource": { "properties": { "search": { From a3eb105cad96bbd8f05557eb256b958c7292ddf3 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Thu, 16 Dec 2021 15:42:21 -0700 Subject: [PATCH 11/13] fix a11y test --- x-pack/test/accessibility/apps/reporting.ts | 31 +++++++++++++-------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/x-pack/test/accessibility/apps/reporting.ts b/x-pack/test/accessibility/apps/reporting.ts index be4fb78682c171..24cb1b0ced86e5 100644 --- a/x-pack/test/accessibility/apps/reporting.ts +++ b/x-pack/test/accessibility/apps/reporting.ts @@ -14,6 +14,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const testSubjects = getService('testSubjects'); const reporting = getService('reporting'); const security = getService('security'); + const log = getService('log'); describe('Reporting', () => { const createReportingUser = async () => { @@ -40,19 +41,25 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); beforeEach(async () => { - await reporting.generateCsv({ - title: 'CSV Report', - browserTimezone: 'UTC', - objectType: 'search', - version: '7.15.0', - searchSource: { - version: true, - query: { query: '', language: 'kuery' }, - index: '5193f870-d861-11e9-a311-0fa548c5f953', - fields: ['*'], - filter: [], + // Add one report + const { body } = await reporting.generateCsv( + { + title: 'CSV Report', + browserTimezone: 'UTC', + objectType: 'search', + version: '7.15.0', + searchSource: { + version: true, + query: { query: '', language: 'kuery' }, + index: '5193f870-d861-11e9-a311-0fa548c5f953', + fields: ['*'], + }, }, - }); + reporting.REPORTING_USER_USERNAME, + reporting.REPORTING_USER_PASSWORD + ); + + log.info(`Queued report job: ${body.path}`); await retry.waitFor('Reporting app', async () => { await common.navigateToApp('reporting'); From 5e5a2e5d65348ba01f895787675bac5d9e59be3c Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Fri, 17 Dec 2021 08:05:33 -0700 Subject: [PATCH 12/13] fix unused t10s --- x-pack/plugins/translations/translations/ja-JP.json | 2 -- x-pack/plugins/translations/translations/zh-CN.json | 2 -- 2 files changed, 4 deletions(-) diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 86d059f13e85c7..ab20c5a0c0b3c9 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -19956,8 +19956,6 @@ "xpack.reporting.exportTypes.common.missingJobHeadersErrorMessage": "ジョブヘッダーがありません", "xpack.reporting.exportTypes.csv.executeJob.dateFormateSetting": "Kibana の高度な設定「{dateFormatTimezone}」が「ブラウザー」に設定されています。あいまいさを避けるために日付は UTC 形式に変換されます。", "xpack.reporting.exportTypes.csv.generateCsv.escapedFormulaValues": "CSVには、値がエスケープされた式が含まれる場合があります", - "xpack.reporting.exportTypes.csv.hitIterator.expectedHitsErrorMessage": "次の Elasticsearch からの応答で期待される {hits}:{response}", - "xpack.reporting.exportTypes.csv.hitIterator.expectedScrollIdErrorMessage": "次の Elasticsearch からの応答で期待される {scrollId}:{response}", "xpack.reporting.exportTypes.printablePdf.documentStreamIsNotgeneratedErrorMessage": "ドキュメントストリームが生成されていません。", "xpack.reporting.exportTypes.printablePdf.logoDescription": "Elastic 提供", "xpack.reporting.exportTypes.printablePdf.pagingDescription": "{pageCount} ページ中 {currentPage} ページ目", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index b31ba78246b3f3..fd1298b5fb3860 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -20248,8 +20248,6 @@ "xpack.reporting.exportTypes.common.missingJobHeadersErrorMessage": "作业标头缺失", "xpack.reporting.exportTypes.csv.executeJob.dateFormateSetting": "Kibana 高级设置“{dateFormatTimezone}”已设置为“浏览器”。日期将格式化为 UTC 以避免混淆。", "xpack.reporting.exportTypes.csv.generateCsv.escapedFormulaValues": "CSV 可能包含值已转义的公式", - "xpack.reporting.exportTypes.csv.hitIterator.expectedHitsErrorMessage": "在以下 Elasticsearch 响应中预期 {hits}:{response}", - "xpack.reporting.exportTypes.csv.hitIterator.expectedScrollIdErrorMessage": "在以下 Elasticsearch 响应中预期 {scrollId}:{response}", "xpack.reporting.exportTypes.printablePdf.documentStreamIsNotgeneratedErrorMessage": "尚未生成文档流", "xpack.reporting.exportTypes.printablePdf.logoDescription": "由 Elastic 提供支持", "xpack.reporting.exportTypes.printablePdf.pagingDescription": "第 {currentPage} 页,共 {pageCount} 页", From 0b5fe9ca8dbc818a4a2d860a8b127cbeb8c63508 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Tue, 21 Dec 2021 08:41:17 -0700 Subject: [PATCH 13/13] fix ts --- .../plugins/reporting/server/export_types/printable_pdf/types.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/x-pack/plugins/reporting/server/export_types/printable_pdf/types.ts b/x-pack/plugins/reporting/server/export_types/printable_pdf/types.ts index 30c567143d2644..f57d6a709fedba 100644 --- a/x-pack/plugins/reporting/server/export_types/printable_pdf/types.ts +++ b/x-pack/plugins/reporting/server/export_types/printable_pdf/types.ts @@ -8,5 +8,4 @@ export type { JobParamsPDF, TaskPayloadPDF, - JobParamsPDFLegacy, } from '../../../common/types/export_types/printable_pdf';