diff --git a/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/index.ts b/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/index.ts index 961a046c846e4..9a9f445de0b13 100644 --- a/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/index.ts +++ b/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/index.ts @@ -28,9 +28,9 @@ export { runTaskFnFactory } from './server/execute_job'; export const getExportType = (): ExportTypeDefinition< JobParamsPanelCsv, - ImmediateCreateJobFn, + ImmediateCreateJobFn, JobParamsPanelCsv, - ImmediateExecuteFn + ImmediateExecuteFn > => ({ ...metadata, jobType: CSV_FROM_SAVEDOBJECT_JOB_TYPE, diff --git a/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/server/create_job/index.ts b/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/server/create_job/index.ts index dafac04017607..da9810b03aff6 100644 --- a/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/server/create_job/index.ts +++ b/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/server/create_job/index.ts @@ -20,15 +20,15 @@ import { } from '../../types'; import { createJobSearch } from './create_job_search'; -export type ImmediateCreateJobFn = ( - jobParams: JobParamsType, +export type ImmediateCreateJobFn = ( + jobParams: JobParamsPanelCsv, headers: KibanaRequest['headers'], context: RequestHandlerContext, req: KibanaRequest ) => Promise<{ type: string | null; title: string; - jobParams: JobParamsType; + jobParams: JobParamsPanelCsv; }>; interface VisData { @@ -37,9 +37,10 @@ interface VisData { panel: SearchPanel; } -export const scheduleTaskFnFactory: ScheduleTaskFnFactory> = function createJobFactoryFn(reporting, parentLogger) { +export const scheduleTaskFnFactory: ScheduleTaskFnFactory = function createJobFactoryFn( + reporting, + parentLogger +) { const config = reporting.getConfig(); const crypto = cryptoFactory(config.get('encryptionKey')); const logger = parentLogger.clone([CSV_FROM_SAVEDOBJECT_JOB_TYPE, 'create-job']); diff --git a/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/server/execute_job.ts b/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/server/execute_job.ts index 26b7a24907f40..912ae0809cf92 100644 --- a/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/server/execute_job.ts +++ b/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/server/execute_job.ts @@ -7,39 +7,43 @@ import { i18n } from '@kbn/i18n'; import { KibanaRequest, RequestHandlerContext } from 'src/core/server'; import { CONTENT_TYPE_CSV, CSV_FROM_SAVEDOBJECT_JOB_TYPE } from '../../../../common/constants'; -import { cryptoFactory } from '../../../lib'; import { RunTaskFnFactory, ScheduledTaskParams, TaskRunResult } from '../../../types'; import { CsvResultFromSearch } from '../../csv/types'; -import { FakeRequest, JobParamsPanelCsv, SearchPanel } from '../types'; +import { JobParamsPanelCsv, SearchPanel } from '../types'; import { createGenerateCsv } from './lib'; +/* + * The run function receives the full request which provides the un-encrypted + * headers, so encrypted headers are not part of these kind of job params + */ +type ImmediateJobParams = Omit, 'headers'>; + /* * ImmediateExecuteFn receives the job doc payload because the payload was * generated in the ScheduleFn */ -export type ImmediateExecuteFn = ( +export type ImmediateExecuteFn = ( jobId: null, - job: ScheduledTaskParams, + job: ImmediateJobParams, context: RequestHandlerContext, req: KibanaRequest ) => Promise; -export const runTaskFnFactory: RunTaskFnFactory> = function executeJobFactoryFn(reporting, parentLogger) { - const config = reporting.getConfig(); - const crypto = cryptoFactory(config.get('encryptionKey')); +export const runTaskFnFactory: RunTaskFnFactory = function executeJobFactoryFn( + reporting, + parentLogger +) { const logger = parentLogger.clone([CSV_FROM_SAVEDOBJECT_JOB_TYPE, 'execute-job']); const generateCsv = createGenerateCsv(reporting, parentLogger); - return async function runTask(jobId: string | null, job, context, req) { + return async function runTask(jobId: string | null, job, context, request) { // There will not be a jobID for "immediate" generation. // jobID is only for "queued" jobs // Use the jobID as a logging tag or "immediate" const jobLogger = logger.clone([jobId === null ? 'immediate' : jobId]); const { jobParams } = job; - const { isImmediate, panel, visType } = jobParams as JobParamsPanelCsv & { panel: SearchPanel }; + const { panel, visType } = jobParams as JobParamsPanelCsv & { panel: SearchPanel }; if (!panel) { i18n.translate( @@ -50,54 +54,13 @@ export const runTaskFnFactory: RunTaskFnFactory; - const serializedEncryptedHeaders = job.headers; - try { - if (typeof serializedEncryptedHeaders !== 'string') { - throw new Error( - i18n.translate( - 'xpack.reporting.exportTypes.csv_from_savedobject.executeJob.missingJobHeadersErrorMessage', - { - defaultMessage: 'Job headers are missing', - } - ) - ); - } - decryptedHeaders = (await crypto.decrypt(serializedEncryptedHeaders)) as Record< - string, - unknown - >; - } catch (err) { - jobLogger.error(err); - throw new Error( - i18n.translate( - 'xpack.reporting.exportTypes.csv_from_savedobject.executeJob.failedToDecryptReportJobDataErrorMessage', - { - defaultMessage: - 'Failed to decrypt report job data. Please ensure that {encryptionKey} is set and re-generate this report. {err}', - values: { encryptionKey: 'xpack.reporting.encryptionKey', err }, - } - ) - ); - } - - requestObject = { headers: decryptedHeaders }; - } - let content: string; let maxSizeReached = false; let size = 0; try { const generateResults: CsvResultFromSearch = await generateCsv( context, - requestObject, + request, visType as string, panel, jobParams diff --git a/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/types.d.ts b/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/types.d.ts index 835b352953dfe..c182fe49a31f6 100644 --- a/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/types.d.ts +++ b/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/types.d.ts @@ -23,10 +23,6 @@ export interface JobParamsPanelCsv { visType?: string; } -export interface ScheduledTaskParamsPanelCsv extends ScheduledTaskParams { - jobParams: JobParamsPanelCsv; -} - export interface SavedObjectServiceError { statusCode: number; error?: string; diff --git a/x-pack/plugins/reporting/server/routes/generate_from_savedobject.ts b/x-pack/plugins/reporting/server/routes/generate_from_savedobject.ts deleted file mode 100644 index b8326406743b7..0000000000000 --- a/x-pack/plugins/reporting/server/routes/generate_from_savedobject.ts +++ /dev/null @@ -1,85 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { schema } from '@kbn/config-schema'; -import { get } from 'lodash'; -import { HandlerErrorFunction, HandlerFunction, QueuedJobPayload } from './types'; -import { ReportingCore } from '../'; -import { API_BASE_GENERATE_V1, CSV_FROM_SAVEDOBJECT_JOB_TYPE } from '../../common/constants'; -import { getJobParamsFromRequest } from '../export_types/csv_from_savedobject/server/lib/get_job_params_from_request'; -import { authorizedUserPreRoutingFactory } from './lib/authorized_user_pre_routing'; - -/* - * This function registers API Endpoints for queuing Reporting jobs. The API inputs are: - * - saved object type and ID - * - time range and time zone - * - application state: - * - filters - * - query bar - * - local (transient) changes the user made to the saved object - */ -export function registerGenerateCsvFromSavedObject( - reporting: ReportingCore, - handleRoute: HandlerFunction, - handleRouteError: HandlerErrorFunction -) { - const setupDeps = reporting.getPluginSetupDeps(); - const userHandler = authorizedUserPreRoutingFactory(reporting); - const { router } = setupDeps; - router.post( - { - path: `${API_BASE_GENERATE_V1}/csv/saved-object/{savedObjectType}:{savedObjectId}`, - validate: { - params: schema.object({ - savedObjectType: schema.string({ minLength: 2 }), - savedObjectId: schema.string({ minLength: 2 }), - }), - body: schema.object({ - state: schema.object({}), - timerange: schema.object({ - timezone: schema.string({ defaultValue: 'UTC' }), - min: schema.nullable(schema.oneOf([schema.number(), schema.string({ minLength: 5 })])), - max: schema.nullable(schema.oneOf([schema.number(), schema.string({ minLength: 5 })])), - }), - }), - }, - }, - userHandler(async (user, context, req, res) => { - /* - * 1. Build `jobParams` object: job data that execution will need to reference in various parts of the lifecycle - * 2. Pass the jobParams and other common params to `handleRoute`, a shared function to enqueue the job with the params - * 3. Ensure that details for a queued job were returned - */ - let result: QueuedJobPayload; - try { - const jobParams = getJobParamsFromRequest(req, { isImmediate: false }); - result = await handleRoute( - user, - CSV_FROM_SAVEDOBJECT_JOB_TYPE, - jobParams, - context, - req, - res - ); - } catch (err) { - return handleRouteError(res, err); - } - - if (get(result, 'source.job') == null) { - return res.badRequest({ - body: `The Export handler is expected to return a result with job info! ${result}`, - }); - } - - return res.ok({ - body: result, - headers: { - 'content-type': 'application/json', - }, - }); - }) - ); -} diff --git a/x-pack/plugins/reporting/server/routes/generate_from_savedobject_immediate.ts b/x-pack/plugins/reporting/server/routes/generate_from_savedobject_immediate.ts index 7d93a36c85bc8..97441bba70984 100644 --- a/x-pack/plugins/reporting/server/routes/generate_from_savedobject_immediate.ts +++ b/x-pack/plugins/reporting/server/routes/generate_from_savedobject_immediate.ts @@ -10,7 +10,6 @@ import { API_BASE_GENERATE_V1 } from '../../common/constants'; import { scheduleTaskFnFactory } from '../export_types/csv_from_savedobject/server/create_job'; import { runTaskFnFactory } from '../export_types/csv_from_savedobject/server/execute_job'; import { getJobParamsFromRequest } from '../export_types/csv_from_savedobject/server/lib/get_job_params_from_request'; -import { ScheduledTaskParamsPanelCsv } from '../export_types/csv_from_savedobject/types'; import { LevelLogger as Logger } from '../lib'; import { TaskRunResult } from '../types'; import { authorizedUserPreRoutingFactory } from './lib/authorized_user_pre_routing'; @@ -64,12 +63,8 @@ export function registerGenerateCsvFromSavedObjectImmediate( const runTaskFn = runTaskFnFactory(reporting, logger); try { - const jobDocPayload: ScheduledTaskParamsPanelCsv = await scheduleTaskFn( - jobParams, - req.headers, - context, - req - ); + // FIXME: no scheduleTaskFn for immediate download + const jobDocPayload = await scheduleTaskFn(jobParams, req.headers, context, req); const { content_type: jobOutputContentType, content: jobOutputContent, @@ -91,11 +86,12 @@ export function registerGenerateCsvFromSavedObjectImmediate( return res.ok({ body: jobOutputContent || '', headers: { - 'content-type': jobOutputContentType, + 'content-type': jobOutputContentType ? jobOutputContentType : [], 'accept-ranges': 'none', }, }); } catch (err) { + logger.error(err); return handleError(res, err); } }) diff --git a/x-pack/plugins/reporting/server/routes/generation.test.ts b/x-pack/plugins/reporting/server/routes/generation.test.ts index 7de7c68122125..c73c443d2390b 100644 --- a/x-pack/plugins/reporting/server/routes/generation.test.ts +++ b/x-pack/plugins/reporting/server/routes/generation.test.ts @@ -4,16 +4,16 @@ * you may not use this file except in compliance with the Elastic License. */ -import supertest from 'supertest'; import { UnwrapPromise } from '@kbn/utility-types'; +import { of } from 'rxjs'; +import sinon from 'sinon'; import { setupServer } from 'src/core/server/test_utils'; -import { registerJobGenerationRoutes } from './generation'; -import { createMockReportingCore } from '../test_helpers'; +import supertest from 'supertest'; import { ReportingCore } from '..'; import { ExportTypesRegistry } from '../lib/export_types_registry'; -import { ExportTypeDefinition } from '../types'; -import { LevelLogger } from '../lib'; -import { of } from 'rxjs'; +import { createMockReportingCore } from '../test_helpers'; +import { createMockLevelLogger } from '../test_helpers/create_mock_levellogger'; +import { registerJobGenerationRoutes } from './generation'; type setupServerReturn = UnwrapPromise>; @@ -21,7 +21,8 @@ describe('POST /api/reporting/generate', () => { const reportingSymbol = Symbol('reporting'); let server: setupServerReturn['server']; let httpSetup: setupServerReturn['httpSetup']; - let exportTypesRegistry: ExportTypesRegistry; + let mockExportTypesRegistry: ExportTypesRegistry; + let callClusterStub: any; let core: ReportingCore; const config = { @@ -29,7 +30,7 @@ describe('POST /api/reporting/generate', () => { const key = args.join('.'); switch (key) { case 'queue.indexInterval': - return 10000; + return 'year'; case 'queue.timeout': return 10000; case 'index': @@ -42,56 +43,45 @@ describe('POST /api/reporting/generate', () => { }), kbnConfig: { get: jest.fn() }, }; - const mockLogger = ({ - error: jest.fn(), - debug: jest.fn(), - } as unknown) as jest.Mocked; + const mockLogger = createMockLevelLogger(); beforeEach(async () => { ({ server, httpSetup } = await setupServer(reportingSymbol)); httpSetup.registerRouteHandlerContext(reportingSymbol, 'reporting', () => ({})); - const mockDeps = ({ + + callClusterStub = sinon.stub().resolves({}); + + const mockSetupDeps = ({ elasticsearch: { - legacy: { - client: { callAsInternalUser: jest.fn() }, - }, + legacy: { client: { callAsInternalUser: callClusterStub } }, }, security: { - license: { - isEnabled: () => true, - }, + license: { isEnabled: () => true }, authc: { - getCurrentUser: () => ({ - id: '123', - roles: ['superuser'], - username: 'Tom Riddle', - }), + getCurrentUser: () => ({ id: '123', roles: ['superuser'], username: 'Tom Riddle' }), }, }, router: httpSetup.createRouter(''), - licensing: { - license$: of({ - isActive: true, - isAvailable: true, - type: 'gold', - }), - }, + licensing: { license$: of({ isActive: true, isAvailable: true, type: 'gold' }) }, } as unknown) as any; - core = await createMockReportingCore(config, mockDeps); - exportTypesRegistry = new ExportTypesRegistry(); - exportTypesRegistry.register({ + + core = await createMockReportingCore(config, mockSetupDeps); + + mockExportTypesRegistry = new ExportTypesRegistry(); + mockExportTypesRegistry.register({ id: 'printablePdf', + name: 'not sure why this field exists', jobType: 'printable_pdf', jobContentEncoding: 'base64', jobContentExtension: 'pdf', validLicenses: ['basic', 'gold'], - } as ExportTypeDefinition); - core.getExportTypesRegistry = () => exportTypesRegistry; + scheduleTaskFnFactory: () => () => ({ scheduleParamsTest: { test1: 'yes' } }), + runTaskFnFactory: () => () => ({ runParamsTest: { test2: 'yes' } }), + }); + core.getExportTypesRegistry = () => mockExportTypesRegistry; }); afterEach(async () => { - mockLogger.debug.mockReset(); - mockLogger.error.mockReset(); await server.stop(); }); @@ -147,14 +137,9 @@ describe('POST /api/reporting/generate', () => { ); }); - it('returns 400 if job handler throws an error', async () => { - const errorText = 'you found me'; - core.getEnqueueJob = async () => - jest.fn().mockImplementation(() => ({ - toJSON: () => { - throw new Error(errorText); - }, - })); + it('returns 500 if job handler throws an error', async () => { + // throw an error from enqueueJob + core.getEnqueueJob = jest.fn().mockRejectedValue('Sorry, this tests says no'); registerJobGenerationRoutes(core, mockLogger); @@ -163,9 +148,27 @@ describe('POST /api/reporting/generate', () => { await supertest(httpSetup.server.listener) .post('/api/reporting/generate/printablePdf') .send({ jobParams: `abc` }) - .expect(400) + .expect(500); + }); + + it(`returns 200 if job handler doesn't error`, async () => { + callClusterStub.withArgs('index').resolves({ _id: 'foo', _index: 'foo-index' }); + + registerJobGenerationRoutes(core, mockLogger); + + await server.start(); + + await supertest(httpSetup.server.listener) + .post('/api/reporting/generate/printablePdf') + .send({ jobParams: `abc` }) + .expect(200) .then(({ body }) => { - expect(body.message).toMatchInlineSnapshot(`"${errorText}"`); + expect(body).toMatchObject({ + job: { + id: expect.any(String), + }, + path: expect.any(String), + }); }); }); }); diff --git a/x-pack/plugins/reporting/server/routes/generation.ts b/x-pack/plugins/reporting/server/routes/generation.ts index 69097c2080cdc..2b58f21565f26 100644 --- a/x-pack/plugins/reporting/server/routes/generation.ts +++ b/x-pack/plugins/reporting/server/routes/generation.ts @@ -11,7 +11,6 @@ import { ReportingCore } from '../'; import { API_BASE_URL } from '../../common/constants'; import { LevelLogger as Logger } from '../lib'; import { registerGenerateFromJobParams } from './generate_from_jobparams'; -import { registerGenerateCsvFromSavedObject } from './generate_from_savedobject'; import { registerGenerateCsvFromSavedObjectImmediate } from './generate_from_savedobject_immediate'; import { registerLegacy } from './legacy'; import { HandlerFunction } from './types'; @@ -44,24 +43,32 @@ export function registerJobGenerationRoutes(reporting: ReportingCore, logger: Lo return res.forbidden({ body: licenseResults.message }); } - const enqueueJob = await reporting.getEnqueueJob(); - const job = await enqueueJob(exportTypeId, jobParams, user, context, req); - - // return the queue's job information - const jobJson = job.toJSON(); - const downloadBaseUrl = getDownloadBaseUrl(reporting); - - return res.ok({ - headers: { - 'content-type': 'application/json', - }, - body: { - path: `${downloadBaseUrl}/${jobJson.id}`, - job: jobJson, - }, - }); + try { + const enqueueJob = await reporting.getEnqueueJob(); + const job = await enqueueJob(exportTypeId, jobParams, user, context, req); + + // return the queue's job information + const jobJson = job.toJSON(); + const downloadBaseUrl = getDownloadBaseUrl(reporting); + + return res.ok({ + headers: { + 'content-type': 'application/json', + }, + body: { + path: `${downloadBaseUrl}/${jobJson.id}`, + job: jobJson, + }, + }); + } catch (err) { + logger.error(err); + throw err; + } }; + /* + * Error should already have been logged by the time we get here + */ function handleError(res: typeof kibanaResponseFactory, err: Error | Boom) { if (err instanceof Boom) { return res.customError({ @@ -88,13 +95,11 @@ export function registerJobGenerationRoutes(reporting: ReportingCore, logger: Lo }); } - return res.badRequest({ - body: err.message, - }); + // unknown error, can't convert to 4xx + throw err; } registerGenerateFromJobParams(reporting, handler, handleError); registerLegacy(reporting, handler, handleError, logger); // 7.x only - registerGenerateCsvFromSavedObject(reporting, handler, handleError); // FIXME: remove this https://github.com/elastic/kibana/issues/62986 registerGenerateCsvFromSavedObjectImmediate(reporting, handleError, logger); } diff --git a/x-pack/plugins/reporting/server/routes/lib/job_response_handler.ts b/x-pack/plugins/reporting/server/routes/lib/job_response_handler.ts index a8492481e6b13..651f1c34fee6c 100644 --- a/x-pack/plugins/reporting/server/routes/lib/job_response_handler.ts +++ b/x-pack/plugins/reporting/server/routes/lib/job_response_handler.ts @@ -46,20 +46,20 @@ export function downloadJobResponseHandlerFactory(reporting: ReportingCore) { }); } - const response = getDocumentPayload(doc); + const payload = getDocumentPayload(doc); - if (!WHITELISTED_JOB_CONTENT_TYPES.includes(response.contentType)) { + if (!payload.contentType || !WHITELISTED_JOB_CONTENT_TYPES.includes(payload.contentType)) { return res.badRequest({ - body: `Unsupported content-type of ${response.contentType} specified by job output`, + body: `Unsupported content-type of ${payload.contentType} specified by job output`, }); } return res.custom({ - body: typeof response.content === 'string' ? Buffer.from(response.content) : response.content, - statusCode: response.statusCode, + body: typeof payload.content === 'string' ? Buffer.from(payload.content) : payload.content, + statusCode: payload.statusCode, headers: { - ...response.headers, - 'content-type': response.contentType, + ...payload.headers, + 'content-type': payload.contentType || '', }, }); }; diff --git a/x-pack/plugins/reporting/server/test_helpers/create_mock_reportingplugin.ts b/x-pack/plugins/reporting/server/test_helpers/create_mock_reportingplugin.ts index 427a6362a7258..95b06aa39f07e 100644 --- a/x-pack/plugins/reporting/server/test_helpers/create_mock_reportingplugin.ts +++ b/x-pack/plugins/reporting/server/test_helpers/create_mock_reportingplugin.ts @@ -22,6 +22,7 @@ import { ReportingInternalSetup, ReportingInternalStart } from '../core'; import { ReportingStartDeps } from '../types'; import { ReportingStore } from '../lib'; import { createMockLevelLogger } from './create_mock_levellogger'; +import { Report } from '../lib/store'; (initializeBrowserDriverFactory as jest.Mock< Promise @@ -47,7 +48,7 @@ const createMockPluginStart = ( const store = new ReportingStore(mockReportingCore, logger); return { browserDriverFactory: startMock.browserDriverFactory, - enqueueJob: startMock.enqueueJob, + enqueueJob: startMock.enqueueJob || jest.fn().mockResolvedValue(new Report({} as any)), esqueue: startMock.esqueue, savedObjects: startMock.savedObjects || { getScopedClient: jest.fn() }, uiSettings: startMock.uiSettings || { asScopedToClient: () => ({ get: jest.fn() }) }, diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 5c9b07f7d2855..394d3050476b8 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -12413,8 +12413,6 @@ "xpack.reporting.exportTypes.common.failedToDecryptReportJobDataErrorMessage": "レポートジョブデータの解読に失敗しました。{encryptionKey}が設定されていることを確認してこのレポートを再生成してください。{err}", "xpack.reporting.exportTypes.common.missingJobHeadersErrorMessage": "ジョブヘッダーがありません", "xpack.reporting.exportTypes.csv_from_savedobject.executeJob.failedToAccessPanel": "ジョブ実行のパネルメタデータにアクセスできませんでした", - "xpack.reporting.exportTypes.csv_from_savedobject.executeJob.failedToDecryptReportJobDataErrorMessage": "レポートジョブデータの解読に失敗しました{encryptionKey} が設定されていることを確認してこのレポートを再生成してください。{err}", - "xpack.reporting.exportTypes.csv_from_savedobject.executeJob.missingJobHeadersErrorMessage": "ジョブヘッダーがありません", "xpack.reporting.exportTypes.csv.executeJob.dateFormateSetting": "Kibana の高度な設定「{dateFormatTimezone}」が「ブラウザー」に設定されていますあいまいさを避けるために日付は UTC 形式に変換されます。", "xpack.reporting.exportTypes.csv.executeJob.failedToDecryptReportJobDataErrorMessage": "レポートジョブデータの解読に失敗しました{encryptionKey} が設定されていることを確認してこのレポートを再生成してください。{err}", "xpack.reporting.exportTypes.csv.executeJob.missingJobHeadersErrorMessage": "ジョブヘッダーがありません", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index d7315e7d8bb67..608467bd22a53 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -12418,8 +12418,6 @@ "xpack.reporting.exportTypes.common.failedToDecryptReportJobDataErrorMessage": "无法解密报告作业数据。请确保已设置 {encryptionKey},然后重新生成此报告。{err}", "xpack.reporting.exportTypes.common.missingJobHeadersErrorMessage": "作业标头缺失", "xpack.reporting.exportTypes.csv_from_savedobject.executeJob.failedToAccessPanel": "无法访问用于作业执行的面板元数据", - "xpack.reporting.exportTypes.csv_from_savedobject.executeJob.failedToDecryptReportJobDataErrorMessage": "无法解密报告作业数据。请确保已设置 {encryptionKey},然后重新生成此报告。{err}", - "xpack.reporting.exportTypes.csv_from_savedobject.executeJob.missingJobHeadersErrorMessage": "作业标头缺失", "xpack.reporting.exportTypes.csv.executeJob.dateFormateSetting": "Kibana 高级设置“{dateFormatTimezone}”已设置为“浏览器”。日期将格式化为 UTC 以避免混淆。", "xpack.reporting.exportTypes.csv.executeJob.failedToDecryptReportJobDataErrorMessage": "无法解密报告作业数据。请确保已设置 {encryptionKey},然后重新生成此报告。{err}", "xpack.reporting.exportTypes.csv.executeJob.missingJobHeadersErrorMessage": "作业标头缺失", diff --git a/x-pack/test/reporting_api_integration/reporting/csv_saved_search.ts b/x-pack/test/reporting_api_integration/reporting/csv_saved_search.ts index 3ec2efcb8f88c..c24e5d325e378 100644 --- a/x-pack/test/reporting_api_integration/reporting/csv_saved_search.ts +++ b/x-pack/test/reporting_api_integration/reporting/csv_saved_search.ts @@ -339,101 +339,5 @@ export default function ({ getService }: FtrProviderContext) { await esArchiver.unload('reporting/ecommerce_kibana'); }); }); - - // FLAKY: https://github.com/elastic/kibana/issues/37471 - describe.skip('Non-Immediate', () => { - it('using queries in job params', async () => { - // load test data that contains a saved search and documents - await esArchiver.load('reporting/scripted_small'); - - const params = { - searchId: 'search:f34bf440-5014-11e9-bce7-4dabcb8bef24', - postPayload: { - timerange: { timezone: 'UTC', min: '1979-01-01T10:00:00Z', max: '1981-01-01T10:00:00Z' }, // prettier-ignore - state: { query: { bool: { filter: [ { bool: { filter: [ { bool: { minimum_should_match: 1, should: [{ query_string: { fields: ['name'], query: 'Fe*' } }] } } ] } } ] } } } // prettier-ignore - }, - isImmediate: false, - }; - const { - status: resStatus, - text: resText, - type: resType, - } = (await generateAPI.getCsvFromSavedSearch( - params.searchId, - params.postPayload, - params.isImmediate - )) as supertest.Response; - - expect(resStatus).to.eql(200); - expect(resType).to.eql('application/json'); - const { - path: jobDownloadPath, - job: { index: jobIndex, jobtype: jobType, created_by: jobCreatedBy, payload: jobPayload }, - } = JSON.parse(resText); - - expect(jobDownloadPath.slice(0, 29)).to.equal('/api/reporting/jobs/download/'); - expect(jobIndex.slice(0, 11)).to.equal('.reporting-'); - expect(jobType).to.be('csv_from_savedobject'); - expect(jobCreatedBy).to.be('elastic'); - - const { - title: payloadTitle, - objects: payloadObjects, - jobParams: payloadParams, - } = jobPayload; - expect(payloadTitle).to.be('EVERYBABY2'); - expect(payloadObjects).to.be(null); // value for non-immediate - expect(payloadParams.savedObjectType).to.be('search'); - expect(payloadParams.savedObjectId).to.be('f34bf440-5014-11e9-bce7-4dabcb8bef24'); - expect(payloadParams.isImmediate).to.be(false); - - const { state: postParamState, timerange: postParamTimerange } = payloadParams.post; - expect(postParamState).to.eql({ - query: { bool: { filter: [ { bool: { filter: [ { bool: { minimum_should_match: 1, should: [{ query_string: { fields: ['name'], query: 'Fe*' } }] } } ] } } ] } } // prettier-ignore - }); - expect(postParamTimerange).to.eql({ - max: '1981-01-01T10:00:00.000Z', - min: '1979-01-01T10:00:00.000Z', - timezone: 'UTC', - }); - - const { - indexPatternSavedObjectId: payloadPanelIndexPatternSavedObjectId, - timerange: payloadPanelTimerange, - } = payloadParams.panel; - expect(payloadPanelIndexPatternSavedObjectId).to.be('89655130-5013-11e9-bce7-4dabcb8bef24'); - expect(payloadPanelTimerange).to.eql({ - timezone: 'UTC', - min: '1979-01-01T10:00:00.000Z', - max: '1981-01-01T10:00:00.000Z', - }); - - expect(payloadParams.visType).to.be('search'); - - // check the resource at jobDownloadPath - const downloadFromPath = async (downloadPath: string) => { - const { status, text, type } = await supertestSvc - .get(downloadPath) - .set('kbn-xsrf', 'xxx'); - return { - status, - text, - type, - }; - }; - - await new Promise((resolve) => { - setTimeout(async () => { - const { status, text, type } = await downloadFromPath(jobDownloadPath); - expect(status).to.eql(200); - expect(type).to.eql('text/csv'); - expect(text).to.eql(CSV_RESULT_SCRIPTED_REQUERY); - resolve(); - }, 5000); // x-pack/test/functional/config settings are inherited, uses 3 seconds for polling interval. - }); - - await esArchiver.unload('reporting/scripted_small'); - }); - }); }); }