Skip to content

Commit

Permalink
Merge pull request #65 from Financial-Times/check-request-header-type
Browse files Browse the repository at this point in the history
Check the type for request headers passed via config
  • Loading branch information
simonplend authored Jul 13, 2018
2 parents fe0acc8 + 275f38e commit 0b80e83
Show file tree
Hide file tree
Showing 10 changed files with 146 additions and 9 deletions.
5 changes: 3 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ node_modules/@financial-times/n-gage/index.mk:

# The reason for passing --runInBand to jest in CI:
# https://facebook.github.io/jest/docs/en/troubleshooting.html#tests-are-extremely-slow-on-docker-and-or-continuous-integration-ci-server
test:
unit-test:
export TEST_SESSIONS_URL=https://fuhn0pye67.execute-api.eu-west-1.amazonaws.com/prod; \
export TEST_SESSIONS_API_KEY=mock-api-key; \
jest test/tasks/*.js --forceExit $(if $(CI), --ci --runInBand --testResultsProcessor="jest-junit", )
make verify

test: verify unit-test
7 changes: 7 additions & 0 deletions lib/errors/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const NTestError = require('./n-test-error');
const NTestConfigError = require('./n-test-config-error');

module.exports = {
NTestError,
NTestConfigError,
};
18 changes: 18 additions & 0 deletions lib/errors/n-test-config-error.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
const NTestError = require('./n-test-error');

class NTestConfigError extends NTestError {

constructor (...params) {
super(...params);

this.name = this.constructor.name;

// Maintains proper stack trace for where our error was thrown (only available on V8)
if (Error.captureStackTrace) {
Error.captureStackTrace(this, NTestConfigError);
}
}

}

module.exports = NTestConfigError;
16 changes: 16 additions & 0 deletions lib/errors/n-test-error.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
class NTestError extends Error {

constructor (...params) {
super(...params);

this.name = this.constructor.name;

// Maintains proper stack trace for where our error was thrown (only available on V8)
if (Error.captureStackTrace) {
Error.captureStackTrace(this, NTestError);
}
}

}

module.exports = NTestError;
15 changes: 13 additions & 2 deletions lib/smoke/puppeteer-page.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ const REDIRECT_CODES = [301, 302, 303, 307, 308];

const DIMENSIONS = require('../helpers/dimensions');

const { NTestConfigError } = require('../errors');

class PuppeteerPage {

constructor (options) {
Expand Down Expand Up @@ -69,9 +71,18 @@ class PuppeteerPage {

if(this.requestHeaders) {
for (const header in this.requestHeaders) {
if (this.requestHeaders.hasOwnProperty(header)) {
this.requestHeaders[header] = this.requestHeaders[header].toString();
if (!this.requestHeaders.hasOwnProperty(header)) {
continue;
}
let requestHeaderType = typeof this.requestHeaders[header];
if (this.requestHeaders[header] === null) {
requestHeaderType = 'null';
}

if (['null', 'undefined'].includes(requestHeaderType)) {
throw new NTestConfigError(`The configured request header ${header} has an invalid type (${requestHeaderType}), string expected`);
}
this.requestHeaders[header] = this.requestHeaders[header].toString();
}
}

Expand Down
8 changes: 8 additions & 0 deletions lib/smoke/verify-url.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
/* eslint-disable no-console */
const chalk = require('chalk');

const { NTestError } = require('../errors');

const verifyUrl = (testPage, browser, tests) => async () => {

let results = {
Expand Down Expand Up @@ -44,6 +46,12 @@ const verifyUrl = (testPage, browser, tests) => async () => {
});

} catch(err) {

// We want n-test to stop running if we've thrown an NTestError
if (err instanceof NTestError) {
throw err;
}

//Sometimes selenium times out. if so - ignore.
console.warn(err);
results.errors++;
Expand Down
4 changes: 2 additions & 2 deletions tasks/smoke.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ module.exports = (program) => {
.option('-a, --auth', 'Authenticate with FT_NEXT_BACKEND_KEY')
.option('-b, --browsers [value]', 'Selenium browsers to run the test against')
.option('-H, --host [value]', 'Set the hostname to use for all tests')
.option('-c, --config [value]', 'Path to config file used to test. Defaults to ./test/smoke.json')
.option('-c, --config [value]', 'Path to config file used to test. Defaults to ./test/smoke.js')
.option('-i, --interactive [value]', 'Interactively choose which tests to run. Defaults to false')
.option('--header [value]', 'Request headers to be sent with every request. e.g. "X-Api-Key: 1234"', collectHeaders, [])
.description('Tests that a given set of urls for an app respond as expected. Expects the config file ./test/smoke.json to exist')
.description('Tests that a given set of urls for an app respond as expected. Expects the config file ./test/smoke.js to exist')
.action((sets, opts) => {
const globalHeaders = {};
opts.header.forEach(header => {
Expand Down
23 changes: 23 additions & 0 deletions test/fixtures/smoke-invalid-header.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
module.exports = [
{
// All valid headers
headers: {
'ft-valid-header-number': 1,
'ft-valid-header-string': 'some-string',
},
urls: {
'/status?1': 200
}
},
{
// Contains an invalid header (undefined)
headers: {
'ft-valid-header-number': 1,
'ft-valid-header-string': 'some-string',
'ft-invalid-header-undefined': process.env.UNDEFINED_HEADER_VARIABLE,
},
urls: {
'/status?2': 200
}
},
];
11 changes: 11 additions & 0 deletions test/fixtures/smoke-valid-headers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module.exports = [
{
headers: {
'ft-valid-header-number': 1,
'ft-valid-header-string': 'some-string',
},
urls: {
'/status/200?1': 200,
}
}
];
48 changes: 45 additions & 3 deletions test/tasks/smoke.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

const server = require('../server/app');
const SmokeTest = require('../../lib/smoke/smoke-test');
const { NTestConfigError } = require('../../lib/errors');
const { spawn } = require('child_process');

describe('Smoke Tests of the Smoke', () => {
Expand All @@ -11,7 +12,8 @@ describe('Smoke Tests of the Smoke', () => {
server.listen(3004);
});

describe('status checks', () => {
describe('Status checks', () => {

test('tests should pass if all the urls return the correct status', (done) => {
const smoke = new SmokeTest({
host: 'http://localhost:3004',
Expand All @@ -38,9 +40,10 @@ describe('Smoke Tests of the Smoke', () => {
done();
});
}, 10000);

});

describe('tests that error', () => {
describe('Tests that error', () => {

test('should handle non-assertion errors gracefully beyond a threshold', (done) => {
const smoke = new SmokeTest({
Expand Down Expand Up @@ -72,10 +75,10 @@ describe('Smoke Tests of the Smoke', () => {

});


});

describe('Adding custom checks', () => {

test('should allow adding custom assertions',(done) => {

const smoke = new SmokeTest({
Expand All @@ -99,10 +102,12 @@ describe('Smoke Tests of the Smoke', () => {
done();
});
});

});

//TODO: figure out how to test the www.ft.com bit!
describe('Session tokens', () => {

test('should not run user-based tests on localhost', () => {

const smoke = new SmokeTest({
Expand All @@ -119,6 +124,7 @@ describe('Smoke Tests of the Smoke', () => {
});

describe('CLI task', () => {

test('should exit with the correct code for a passing test', (done) => {
const proc = spawn('./bin/n-test.js', ['smoke', '--host', 'http://localhost:3004', '--config', 'test/fixtures/smoke-pass.js']);
proc.on('close', (code) => {
Expand All @@ -134,5 +140,41 @@ describe('Smoke Tests of the Smoke', () => {
done();
});
}, 10000);

});

describe('Config validation', () => {

test('tests should run and pass when all headers in a config are valid', (done) => {

const smoke = new SmokeTest({
host: 'http://localhost:3004',
config: 'test/fixtures/smoke-valid-headers.js'
});

return smoke.run().then((results) => {
expect(results.passed.length).toEqual(1);
expect(results.failed.length).toEqual(0);
done();
});

}, 10000);

test('should throw an NTestConfigError when config contains an invalid header', async () => {

const smoke = new SmokeTest({
host: 'http://localhost:3004',
config: 'test/fixtures/smoke-invalid-header.js'
});

await expect(smoke.run()).rejects.toThrowError(NTestConfigError);

}, 10000);

// TODO: Add test for a null header once functionality to pass config
// object has been added i.e. config for these validation tests can be
// multiple exports in one config file

});

});

0 comments on commit 0b80e83

Please sign in to comment.