Skip to content

Commit

Permalink
copy out export type ts changes
Browse files Browse the repository at this point in the history
  • Loading branch information
tsullivan committed Jul 8, 2020
1 parent f21d512 commit 9fc6f89
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 86 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,8 @@ import { JobParamsPanelCsv, SearchPanel } from '../types';
import { createGenerateCsv } from './lib';

/*
* The headers field is marked as optional (for now) in Immediate job params.
* Other than the job params, the run function receives the full request which
* provides the un-encrypted headers
* 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<ScheduledTaskParams<JobParamsPanelCsv>, 'headers'>;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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,
Expand All @@ -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);
}
})
Expand Down
99 changes: 51 additions & 48 deletions x-pack/plugins/reporting/server/routes/generation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,33 @@
* 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<ReturnType<typeof setupServer>>;

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 = {
get: jest.fn().mockImplementation((...args) => {
const key = args.join('.');
switch (key) {
case 'queue.indexInterval':
return 10000;
return 'year';
case 'queue.timeout':
return 10000;
case 'index':
Expand All @@ -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<LevelLogger>;
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<unknown, unknown, unknown, unknown>);
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();
});

Expand Down Expand Up @@ -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);

Expand All @@ -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),
});
});
});
});
45 changes: 26 additions & 19 deletions x-pack/plugins/reporting/server/routes/generation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,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({
Expand All @@ -87,9 +95,8 @@ 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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 || '',
},
});
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<HeadlessChromiumDriverFactory>
Expand All @@ -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() }) },
Expand Down

0 comments on commit 9fc6f89

Please sign in to comment.