[Reporting] Remove boilerplate needed to get thegetScreenshots
function (#64269)
* expose reportingCore in ReportingSetup for apps * improve tests Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
parent
4c460b8c42
commit
54dc148226
12 changed files with 148 additions and 93 deletions
|
@ -4,4 +4,4 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
export { screenshotsObservableFactory } from './observable';
|
||||
export { screenshotsObservableFactory, ScreenshotsObservableFn } from './observable';
|
||||
|
|
|
@ -21,10 +21,18 @@ import { waitForVisualizations } from './wait_for_visualizations';
|
|||
const DEFAULT_SCREENSHOT_CLIP_HEIGHT = 1200;
|
||||
const DEFAULT_SCREENSHOT_CLIP_WIDTH = 1800;
|
||||
|
||||
export type ScreenshotsObservableFn = ({
|
||||
logger,
|
||||
urls,
|
||||
conditionalHeaders,
|
||||
layout,
|
||||
browserTimezone,
|
||||
}: ScreenshotObservableOpts) => Rx.Observable<ScreenshotResults[]>;
|
||||
|
||||
export function screenshotsObservableFactory(
|
||||
captureConfig: CaptureConfig,
|
||||
browserDriverFactory: HeadlessChromiumDriverFactory
|
||||
) {
|
||||
): ScreenshotsObservableFn {
|
||||
return function screenshotsObservable({
|
||||
logger,
|
||||
urls,
|
||||
|
|
|
@ -5,14 +5,14 @@
|
|||
*/
|
||||
|
||||
import * as Rx from 'rxjs';
|
||||
import { createMockReportingCore, createMockBrowserDriverFactory } from '../../../../test_helpers';
|
||||
import { cryptoFactory } from '../../../../server/lib/crypto';
|
||||
import { executeJobFactory } from './index';
|
||||
import { generatePngObservableFactory } from '../lib/generate_png';
|
||||
import { CancellationToken } from '../../../../common/cancellation_token';
|
||||
import { ReportingCore } from '../../../../server';
|
||||
import { LevelLogger } from '../../../../server/lib';
|
||||
import { ReportingCore, CaptureConfig } from '../../../../server/types';
|
||||
import { cryptoFactory } from '../../../../server/lib/crypto';
|
||||
import { createMockReportingCore } from '../../../../test_helpers';
|
||||
import { JobDocPayloadPNG } from '../../types';
|
||||
import { generatePngObservableFactory } from '../lib/generate_png';
|
||||
import { executeJobFactory } from './index';
|
||||
|
||||
jest.mock('../lib/generate_png', () => ({ generatePngObservableFactory: jest.fn() }));
|
||||
|
||||
|
@ -31,8 +31,6 @@ const mockLoggerFactory = {
|
|||
};
|
||||
const getMockLogger = () => new LevelLogger(mockLoggerFactory);
|
||||
|
||||
const captureConfig = {} as CaptureConfig;
|
||||
|
||||
const mockEncryptionKey = 'abcabcsecuresecret';
|
||||
const encryptHeaders = async (headers: Record<string, string>) => {
|
||||
const crypto = cryptoFactory(mockEncryptionKey);
|
||||
|
@ -46,10 +44,13 @@ beforeEach(async () => {
|
|||
'server.basePath': '/sbp',
|
||||
};
|
||||
const reportingConfig = {
|
||||
index: '.reporting-2018.10.10',
|
||||
encryptionKey: mockEncryptionKey,
|
||||
'kibanaServer.hostname': 'localhost',
|
||||
'kibanaServer.port': 5601,
|
||||
'kibanaServer.protocol': 'http',
|
||||
'queue.indexInterval': 'daily',
|
||||
'queue.timeout': Infinity,
|
||||
};
|
||||
const mockReportingConfig = {
|
||||
get: (...keys: string[]) => (reportingConfig as any)[keys.join('.')],
|
||||
|
@ -74,13 +75,8 @@ afterEach(() => (generatePngObservableFactory as jest.Mock).mockReset());
|
|||
|
||||
test(`passes browserTimezone to generatePng`, async () => {
|
||||
const encryptedHeaders = await encryptHeaders({});
|
||||
const mockBrowserDriverFactory = await createMockBrowserDriverFactory(getMockLogger());
|
||||
|
||||
const generatePngObservable = generatePngObservableFactory(
|
||||
captureConfig,
|
||||
mockBrowserDriverFactory
|
||||
);
|
||||
(generatePngObservable as jest.Mock).mockReturnValue(Rx.of(Buffer.from('')));
|
||||
const generatePngObservable = (await generatePngObservableFactory(mockReporting)) as jest.Mock;
|
||||
generatePngObservable.mockReturnValue(Rx.of(Buffer.from('')));
|
||||
|
||||
const executeJob = await executeJobFactory(mockReporting, getMockLogger());
|
||||
const browserTimezone = 'UTC';
|
||||
|
@ -94,26 +90,43 @@ test(`passes browserTimezone to generatePng`, async () => {
|
|||
cancellationToken
|
||||
);
|
||||
|
||||
expect(generatePngObservable).toBeCalledWith(
|
||||
expect.any(LevelLogger),
|
||||
'http://localhost:5601/sbp/app/kibana#/something',
|
||||
browserTimezone,
|
||||
expect.anything(),
|
||||
undefined
|
||||
);
|
||||
expect(generatePngObservable.mock.calls).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
Array [
|
||||
LevelLogger {
|
||||
"_logger": Object {
|
||||
"get": [MockFunction],
|
||||
},
|
||||
"_tags": Array [
|
||||
"PNG",
|
||||
"execute",
|
||||
"pngJobId",
|
||||
],
|
||||
"warning": [Function],
|
||||
},
|
||||
"http://localhost:5601/sbp/app/kibana#/something",
|
||||
"UTC",
|
||||
Object {
|
||||
"conditions": Object {
|
||||
"basePath": "/sbp",
|
||||
"hostname": "localhost",
|
||||
"port": 5601,
|
||||
"protocol": "http",
|
||||
},
|
||||
"headers": Object {},
|
||||
},
|
||||
undefined,
|
||||
],
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
test(`returns content_type of application/png`, async () => {
|
||||
const executeJob = await executeJobFactory(mockReporting, getMockLogger());
|
||||
const encryptedHeaders = await encryptHeaders({});
|
||||
|
||||
const mockBrowserDriverFactory = await createMockBrowserDriverFactory(getMockLogger());
|
||||
|
||||
const generatePngObservable = generatePngObservableFactory(
|
||||
captureConfig,
|
||||
mockBrowserDriverFactory
|
||||
);
|
||||
(generatePngObservable as jest.Mock).mockReturnValue(Rx.of(Buffer.from('')));
|
||||
const generatePngObservable = (await generatePngObservableFactory(mockReporting)) as jest.Mock;
|
||||
generatePngObservable.mockReturnValue(Rx.of(Buffer.from('')));
|
||||
|
||||
const { content_type: contentType } = await executeJob(
|
||||
'pngJobId',
|
||||
|
@ -126,13 +139,8 @@ test(`returns content_type of application/png`, async () => {
|
|||
test(`returns content of generatePng getBuffer base64 encoded`, async () => {
|
||||
const testContent = 'test content';
|
||||
|
||||
const mockBrowserDriverFactory = await createMockBrowserDriverFactory(getMockLogger());
|
||||
|
||||
const generatePngObservable = generatePngObservableFactory(
|
||||
captureConfig,
|
||||
mockBrowserDriverFactory
|
||||
);
|
||||
(generatePngObservable as jest.Mock).mockReturnValue(Rx.of({ buffer: Buffer.from(testContent) }));
|
||||
const generatePngObservable = (await generatePngObservableFactory(mockReporting)) as jest.Mock;
|
||||
generatePngObservable.mockReturnValue(Rx.of({ buffer: Buffer.from(testContent) }));
|
||||
|
||||
const executeJob = await executeJobFactory(mockReporting, getMockLogger());
|
||||
const encryptedHeaders = await encryptHeaders({});
|
||||
|
|
|
@ -25,13 +25,11 @@ export const executeJobFactory: QueuedPngExecutorFactory = async function execut
|
|||
parentLogger: Logger
|
||||
) {
|
||||
const config = reporting.getConfig();
|
||||
const captureConfig = config.get('capture');
|
||||
const encryptionKey = config.get('encryptionKey');
|
||||
const logger = parentLogger.clone([PNG_JOB_TYPE, 'execute']);
|
||||
|
||||
return async function executeJob(jobId: string, job: JobDocPayloadPNG, cancellationToken: any) {
|
||||
const browserDriverFactory = await reporting.getBrowserDriverFactory();
|
||||
const generatePngObservable = generatePngObservableFactory(captureConfig, browserDriverFactory);
|
||||
const generatePngObservable = await generatePngObservableFactory(reporting);
|
||||
const jobLogger = logger.clone([jobId]);
|
||||
const process$: Rx.Observable<JobDocOutput> = Rx.of(1).pipe(
|
||||
mergeMap(() => decryptJobHeaders({ encryptionKey, job, logger })),
|
||||
|
|
|
@ -6,19 +6,15 @@
|
|||
|
||||
import * as Rx from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { ReportingCore } from '../../../../server';
|
||||
import { LevelLogger } from '../../../../server/lib';
|
||||
import { CaptureConfig } from '../../../../server/types';
|
||||
import { ConditionalHeaders, HeadlessChromiumDriverFactory } from '../../../../types';
|
||||
import { ConditionalHeaders } from '../../../../types';
|
||||
import { LayoutParams } from '../../../common/layouts/layout';
|
||||
import { PreserveLayout } from '../../../common/layouts/preserve_layout';
|
||||
import { screenshotsObservableFactory } from '../../../common/lib/screenshots';
|
||||
import { ScreenshotResults } from '../../../common/lib/screenshots/types';
|
||||
|
||||
export function generatePngObservableFactory(
|
||||
captureConfig: CaptureConfig,
|
||||
browserDriverFactory: HeadlessChromiumDriverFactory
|
||||
) {
|
||||
const screenshotsObservable = screenshotsObservableFactory(captureConfig, browserDriverFactory);
|
||||
export async function generatePngObservableFactory(reporting: ReportingCore) {
|
||||
const getScreenshots = await reporting.getScreenshotsObservable();
|
||||
|
||||
return function generatePngObservable(
|
||||
logger: LevelLogger,
|
||||
|
@ -32,7 +28,7 @@ export function generatePngObservableFactory(
|
|||
}
|
||||
|
||||
const layout = new PreserveLayout(layoutParams.dimensions);
|
||||
const screenshots$ = screenshotsObservable({
|
||||
const screenshots$ = getScreenshots({
|
||||
logger,
|
||||
urls: [url],
|
||||
conditionalHeaders,
|
||||
|
|
|
@ -5,11 +5,11 @@
|
|||
*/
|
||||
|
||||
import * as Rx from 'rxjs';
|
||||
import { createMockReportingCore, createMockBrowserDriverFactory } from '../../../../test_helpers';
|
||||
import { createMockReportingCore } from '../../../../test_helpers';
|
||||
import { cryptoFactory } from '../../../../server/lib/crypto';
|
||||
import { LevelLogger } from '../../../../server/lib';
|
||||
import { CancellationToken } from '../../../../types';
|
||||
import { ReportingCore, CaptureConfig } from '../../../../server/types';
|
||||
import { ReportingCore } from '../../../../server';
|
||||
import { generatePdfObservableFactory } from '../lib/generate_pdf';
|
||||
import { JobDocPayloadPDF } from '../../types';
|
||||
import { executeJobFactory } from './index';
|
||||
|
@ -22,8 +22,6 @@ const cancellationToken = ({
|
|||
on: jest.fn(),
|
||||
} as unknown) as CancellationToken;
|
||||
|
||||
const captureConfig = {} as CaptureConfig;
|
||||
|
||||
const mockLoggerFactory = {
|
||||
get: jest.fn().mockImplementation(() => ({
|
||||
error: jest.fn(),
|
||||
|
@ -72,16 +70,64 @@ beforeEach(async () => {
|
|||
|
||||
afterEach(() => (generatePdfObservableFactory as jest.Mock).mockReset());
|
||||
|
||||
test(`passes browserTimezone to generatePdf`, async () => {
|
||||
const encryptedHeaders = await encryptHeaders({});
|
||||
const generatePdfObservable = (await generatePdfObservableFactory(mockReporting)) as jest.Mock;
|
||||
generatePdfObservable.mockReturnValue(Rx.of(Buffer.from('')));
|
||||
|
||||
const executeJob = await executeJobFactory(mockReporting, getMockLogger());
|
||||
const browserTimezone = 'UTC';
|
||||
await executeJob(
|
||||
'pdfJobId',
|
||||
getJobDocPayload({
|
||||
relativeUrl: '/app/kibana#/something',
|
||||
browserTimezone,
|
||||
headers: encryptedHeaders,
|
||||
}),
|
||||
cancellationToken
|
||||
);
|
||||
|
||||
expect(generatePdfObservable.mock.calls).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
Array [
|
||||
LevelLogger {
|
||||
"_logger": Object {
|
||||
"get": [MockFunction],
|
||||
},
|
||||
"_tags": Array [
|
||||
"printable_pdf",
|
||||
"execute",
|
||||
"pdfJobId",
|
||||
],
|
||||
"warning": [Function],
|
||||
},
|
||||
undefined,
|
||||
Array [
|
||||
"http://localhost:5601/sbp/app/kibana#/something",
|
||||
],
|
||||
"UTC",
|
||||
Object {
|
||||
"conditions": Object {
|
||||
"basePath": "/sbp",
|
||||
"hostname": "localhost",
|
||||
"port": 5601,
|
||||
"protocol": "http",
|
||||
},
|
||||
"headers": Object {},
|
||||
},
|
||||
undefined,
|
||||
false,
|
||||
],
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
test(`returns content_type of application/pdf`, async () => {
|
||||
const logger = getMockLogger();
|
||||
const executeJob = await executeJobFactory(mockReporting, logger);
|
||||
const mockBrowserDriverFactory = await createMockBrowserDriverFactory(logger);
|
||||
const encryptedHeaders = await encryptHeaders({});
|
||||
|
||||
const generatePdfObservable = generatePdfObservableFactory(
|
||||
captureConfig,
|
||||
mockBrowserDriverFactory
|
||||
);
|
||||
const generatePdfObservable = await generatePdfObservableFactory(mockReporting);
|
||||
(generatePdfObservable as jest.Mock).mockReturnValue(Rx.of(Buffer.from('')));
|
||||
|
||||
const { content_type: contentType } = await executeJob(
|
||||
|
@ -94,12 +140,7 @@ test(`returns content_type of application/pdf`, async () => {
|
|||
|
||||
test(`returns content of generatePdf getBuffer base64 encoded`, async () => {
|
||||
const testContent = 'test content';
|
||||
const mockBrowserDriverFactory = await createMockBrowserDriverFactory(getMockLogger());
|
||||
|
||||
const generatePdfObservable = generatePdfObservableFactory(
|
||||
captureConfig,
|
||||
mockBrowserDriverFactory
|
||||
);
|
||||
const generatePdfObservable = await generatePdfObservableFactory(mockReporting);
|
||||
(generatePdfObservable as jest.Mock).mockReturnValue(Rx.of({ buffer: Buffer.from(testContent) }));
|
||||
|
||||
const executeJob = await executeJobFactory(mockReporting, getMockLogger());
|
||||
|
|
|
@ -26,14 +26,12 @@ export const executeJobFactory: QueuedPdfExecutorFactory = async function execut
|
|||
parentLogger: Logger
|
||||
) {
|
||||
const config = reporting.getConfig();
|
||||
const captureConfig = config.get('capture');
|
||||
const encryptionKey = config.get('encryptionKey');
|
||||
|
||||
const logger = parentLogger.clone([PDF_JOB_TYPE, 'execute']);
|
||||
|
||||
return async function executeJob(jobId: string, job: JobDocPayloadPDF, cancellationToken: any) {
|
||||
const browserDriverFactory = await reporting.getBrowserDriverFactory();
|
||||
const generatePdfObservable = generatePdfObservableFactory(captureConfig, browserDriverFactory);
|
||||
const generatePdfObservable = await generatePdfObservableFactory(reporting);
|
||||
|
||||
const jobLogger = logger.clone([jobId]);
|
||||
const process$: Rx.Observable<JobDocOutput> = Rx.of(1).pipe(
|
||||
|
|
|
@ -7,12 +7,11 @@
|
|||
import { groupBy } from 'lodash';
|
||||
import * as Rx from 'rxjs';
|
||||
import { mergeMap } from 'rxjs/operators';
|
||||
import { ReportingCore } from '../../../../server';
|
||||
import { LevelLogger } from '../../../../server/lib';
|
||||
import { CaptureConfig } from '../../../../server/types';
|
||||
import { ConditionalHeaders, HeadlessChromiumDriverFactory } from '../../../../types';
|
||||
import { ConditionalHeaders } from '../../../../types';
|
||||
import { createLayout } from '../../../common/layouts';
|
||||
import { LayoutInstance, LayoutParams } from '../../../common/layouts/layout';
|
||||
import { screenshotsObservableFactory } from '../../../common/lib/screenshots';
|
||||
import { ScreenshotResults } from '../../../common/lib/screenshots/types';
|
||||
// @ts-ignore untyped module
|
||||
import { pdf } from './pdf';
|
||||
|
@ -27,11 +26,10 @@ const getTimeRange = (urlScreenshots: ScreenshotResults[]) => {
|
|||
return null;
|
||||
};
|
||||
|
||||
export function generatePdfObservableFactory(
|
||||
captureConfig: CaptureConfig,
|
||||
browserDriverFactory: HeadlessChromiumDriverFactory
|
||||
) {
|
||||
const screenshotsObservable = screenshotsObservableFactory(captureConfig, browserDriverFactory);
|
||||
export async function generatePdfObservableFactory(reporting: ReportingCore) {
|
||||
const config = reporting.getConfig();
|
||||
const captureConfig = config.get('capture');
|
||||
const getScreenshots = await reporting.getScreenshotsObservable();
|
||||
|
||||
return function generatePdfObservable(
|
||||
logger: LevelLogger,
|
||||
|
@ -43,7 +41,7 @@ export function generatePdfObservableFactory(
|
|||
logo?: string
|
||||
): Rx.Observable<{ buffer: Buffer; warnings: string[] }> {
|
||||
const layout = createLayout(captureConfig, layoutParams) as LayoutInstance;
|
||||
const screenshots$ = screenshotsObservable({
|
||||
const screenshots$ = getScreenshots({
|
||||
logger,
|
||||
urls,
|
||||
conditionalHeaders,
|
||||
|
|
|
@ -24,6 +24,10 @@ import { ReportingConfig, ReportingConfigType } from './config';
|
|||
import { checkLicenseFactory, getExportTypesRegistry, LevelLogger } from './lib';
|
||||
import { registerRoutes } from './routes';
|
||||
import { ReportingSetupDeps } from './types';
|
||||
import {
|
||||
screenshotsObservableFactory,
|
||||
ScreenshotsObservableFn,
|
||||
} from '../export_types/common/lib/screenshots';
|
||||
|
||||
interface ReportingInternalSetup {
|
||||
browserDriverFactory: HeadlessChromiumDriverFactory;
|
||||
|
@ -95,13 +99,13 @@ export class ReportingCore {
|
|||
return (await this.getPluginStartDeps()).enqueueJob;
|
||||
}
|
||||
|
||||
public async getBrowserDriverFactory(): Promise<HeadlessChromiumDriverFactory> {
|
||||
return (await this.getPluginSetupDeps()).browserDriverFactory;
|
||||
}
|
||||
|
||||
public getConfig(): ReportingConfig {
|
||||
return this.config;
|
||||
}
|
||||
public async getScreenshotsObservable(): Promise<ScreenshotsObservableFn> {
|
||||
const { browserDriverFactory } = await this.getPluginSetupDeps();
|
||||
return screenshotsObservableFactory(this.config.get('capture'), browserDriverFactory);
|
||||
}
|
||||
|
||||
/*
|
||||
* Outside dependencies
|
||||
|
|
|
@ -14,3 +14,5 @@ export const plugin = (context: PluginInitializerContext, config: ReportingConfi
|
|||
|
||||
export { ReportingPlugin } from './plugin';
|
||||
export { ReportingConfig, ReportingCore };
|
||||
|
||||
export { PreserveLayout, PrintLayout } from '../export_types/common/layouts';
|
||||
|
|
|
@ -16,21 +16,23 @@ export async function createQueueFactory<JobParamsType, JobPayloadType>(
|
|||
logger: Logger
|
||||
): Promise<ESQueueInstance> {
|
||||
const config = reporting.getConfig();
|
||||
const queueConfig = config.get('queue');
|
||||
const index = config.get('index');
|
||||
const elasticsearch = await reporting.getElasticsearchService();
|
||||
const queueIndexInterval = config.get('queue', 'indexInterval');
|
||||
const queueTimeout = config.get('queue', 'timeout');
|
||||
const queueIndex = config.get('index');
|
||||
const isPollingEnabled = config.get('queue', 'pollEnabled');
|
||||
|
||||
const elasticsearch = await reporting.getElasticsearchService();
|
||||
const queueOptions = {
|
||||
interval: queueConfig.indexInterval,
|
||||
timeout: queueConfig.timeout,
|
||||
interval: queueIndexInterval,
|
||||
timeout: queueTimeout,
|
||||
dateSeparator: '.',
|
||||
client: elasticsearch.dataClient,
|
||||
logger: createTaggedLogger(logger, ['esqueue', 'queue-worker']),
|
||||
};
|
||||
|
||||
const queue: ESQueueInstance = new Esqueue(index, queueOptions);
|
||||
const queue: ESQueueInstance = new Esqueue(queueIndex, queueOptions);
|
||||
|
||||
if (queueConfig.pollEnabled) {
|
||||
if (isPollingEnabled) {
|
||||
// create workers to poll the index for idle jobs waiting to be claimed and executed
|
||||
const createWorker = createWorkerFactory(reporting, logger);
|
||||
await createWorker(queue);
|
||||
|
|
|
@ -26,12 +26,12 @@ interface ConfirmedJob {
|
|||
}
|
||||
|
||||
export function enqueueJobFactory(reporting: ReportingCore, parentLogger: Logger): EnqueueJobFn {
|
||||
const logger = parentLogger.clone(['queue-job']);
|
||||
const config = reporting.getConfig();
|
||||
const captureConfig = config.get('capture');
|
||||
const queueConfig = config.get('queue');
|
||||
const browserType = captureConfig.browser.type;
|
||||
const maxAttempts = captureConfig.maxAttempts;
|
||||
const queueTimeout = config.get('queue', 'timeout');
|
||||
const browserType = config.get('capture', 'browser', 'type');
|
||||
const maxAttempts = config.get('capture', 'maxAttempts');
|
||||
|
||||
const logger = parentLogger.clone(['queue-job']);
|
||||
|
||||
return async function enqueueJob<JobParamsType>(
|
||||
exportTypeId: string,
|
||||
|
@ -53,7 +53,7 @@ export function enqueueJobFactory(reporting: ReportingCore, parentLogger: Logger
|
|||
const payload = await createJob(jobParams, headers, request);
|
||||
|
||||
const options = {
|
||||
timeout: queueConfig.timeout,
|
||||
timeout: queueTimeout,
|
||||
created_by: get(user, 'username', false),
|
||||
browser_type: browserType,
|
||||
max_attempts: maxAttempts,
|
||||
|
|
Loading…
Reference in a new issue