Skip to content

Commit

Permalink
[Reporting] Fix error handling for job handler in route (elastic#60161)
Browse files Browse the repository at this point in the history
* fix bogus rison error

* add generate route test

* update test name
  • Loading branch information
tsullivan committed Mar 16, 2020
1 parent cc47e4d commit 7c9df30
Show file tree
Hide file tree
Showing 2 changed files with 147 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -74,16 +74,21 @@ export function registerGenerateFromJobParams(
}

const { exportType } = request.params;
let jobParams;
let response;
try {
const jobParams = rison.decode(jobParamsRison) as object | null;
jobParams = rison.decode(jobParamsRison) as object | null;
if (!jobParams) {
throw new Error('missing jobParams!');
}
response = await handler(exportType, jobParams, request, h);
} catch (err) {
throw boom.badRequest(`invalid rison: ${jobParamsRison}`);
}
try {
response = await handler(exportType, jobParams, request, h);
} catch (err) {
throw handleError(exportType, err);
}
return response;
},
});
Expand Down
140 changes: 140 additions & 0 deletions x-pack/legacy/plugins/reporting/server/routes/generation.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
/*
* 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 Hapi from 'hapi';
import { createMockReportingCore } from '../../test_helpers';
import { Logger, ServerFacade } from '../../types';
import { ReportingCore, ReportingSetupDeps } from '../../server/types';

jest.mock('./lib/authorized_user_pre_routing', () => ({
authorizedUserPreRoutingFactory: () => () => ({}),
}));
jest.mock('./lib/reporting_feature_pre_routing', () => ({
reportingFeaturePreRoutingFactory: () => () => () => ({
jobTypes: ['unencodedJobType', 'base64EncodedJobType'],
}),
}));

import { registerJobGenerationRoutes } from './generation';

let mockServer: Hapi.Server;
let mockReportingPlugin: ReportingCore;
const mockLogger = ({
error: jest.fn(),
debug: jest.fn(),
} as unknown) as Logger;

beforeEach(async () => {
mockServer = new Hapi.Server({
debug: false,
port: 8080,
routes: { log: { collect: true } },
});
mockServer.config = () => ({ get: jest.fn(), has: jest.fn() });
mockReportingPlugin = await createMockReportingCore();
mockReportingPlugin.getEnqueueJob = async () =>
jest.fn().mockImplementation(() => ({ toJSON: () => '{ "job": "data" }' }));
});

const mockPlugins = {
elasticsearch: {
adminClient: { callAsInternalUser: jest.fn() },
},
security: null,
};

const getErrorsFromRequest = (request: Hapi.Request) => {
// @ts-ignore error property doesn't exist on RequestLog
return request.logs.filter(log => log.tags.includes('error')).map(log => log.error); // NOTE: error stack is available
};

test(`returns 400 if there are no job params`, async () => {
registerJobGenerationRoutes(
mockReportingPlugin,
(mockServer as unknown) as ServerFacade,
(mockPlugins as unknown) as ReportingSetupDeps,
mockLogger
);

const options = {
method: 'POST',
url: '/api/reporting/generate/printablePdf',
};

const { payload, request } = await mockServer.inject(options);
expect(payload).toMatchInlineSnapshot(
`"{\\"statusCode\\":400,\\"error\\":\\"Bad Request\\",\\"message\\":\\"A jobParams RISON string is required\\"}"`
);

const errorLogs = getErrorsFromRequest(request);
expect(errorLogs).toMatchInlineSnapshot(`
Array [
[Error: A jobParams RISON string is required],
]
`);
});

test(`returns 400 if job params is invalid`, async () => {
registerJobGenerationRoutes(
mockReportingPlugin,
(mockServer as unknown) as ServerFacade,
(mockPlugins as unknown) as ReportingSetupDeps,
mockLogger
);

const options = {
method: 'POST',
url: '/api/reporting/generate/printablePdf',
payload: { jobParams: `foo:` },
};

const { payload, request } = await mockServer.inject(options);
expect(payload).toMatchInlineSnapshot(
`"{\\"statusCode\\":400,\\"error\\":\\"Bad Request\\",\\"message\\":\\"invalid rison: foo:\\"}"`
);

const errorLogs = getErrorsFromRequest(request);
expect(errorLogs).toMatchInlineSnapshot(`
Array [
[Error: invalid rison: foo:],
]
`);
});

test(`returns 500 if job handler throws an error`, async () => {
mockReportingPlugin.getEnqueueJob = async () =>
jest.fn().mockImplementation(() => ({
toJSON: () => {
throw new Error('you found me');
},
}));

registerJobGenerationRoutes(
mockReportingPlugin,
(mockServer as unknown) as ServerFacade,
(mockPlugins as unknown) as ReportingSetupDeps,
mockLogger
);

const options = {
method: 'POST',
url: '/api/reporting/generate/printablePdf',
payload: { jobParams: `abc` },
};

const { payload, request } = await mockServer.inject(options);
expect(payload).toMatchInlineSnapshot(
`"{\\"statusCode\\":500,\\"error\\":\\"Internal Server Error\\",\\"message\\":\\"An internal server error occurred\\"}"`
);

const errorLogs = getErrorsFromRequest(request);
expect(errorLogs).toMatchInlineSnapshot(`
Array [
[Error: you found me],
[Error: you found me],
]
`);
});

0 comments on commit 7c9df30

Please sign in to comment.