Skip to content

Commit

Permalink
[Reporting] Remove boilerplate needed to get thegetScreenshots func…
Browse files Browse the repository at this point in the history
…tion (#64269)

* expose reportingCore in ReportingSetup for apps

* improve tests

Co-authored-by: Elastic Machine <[email protected]>
  • Loading branch information
tsullivan and elasticmachine authored Apr 27, 2020
1 parent 4c460b8 commit 54dc148
Show file tree
Hide file tree
Showing 12 changed files with 148 additions and 93 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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() }));

Expand All @@ -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);
Expand All @@ -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('.')],
Expand All @@ -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';
Expand All @@ -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',
Expand All @@ -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({});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 })),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -32,7 +28,7 @@ export function generatePngObservableFactory(
}

const layout = new PreserveLayout(layoutParams.dimensions);
const screenshots$ = screenshotsObservable({
const screenshots$ = getScreenshots({
logger,
urls: [url],
conditionalHeaders,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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(),
Expand Down Expand Up @@ -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(
Expand All @@ -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());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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,
Expand All @@ -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,
Expand Down
12 changes: 8 additions & 4 deletions x-pack/legacy/plugins/reporting/server/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down
Loading

0 comments on commit 54dc148

Please sign in to comment.