bridge-node-server/node_server/dev_api/specs/rate-limiting.e2e.spec.js
Martin Donnelly 57bd6c8e6a init
2018-06-24 21:15:03 +01:00

141 lines
4.0 KiB
JavaScript

/**
* @fileOverview End-to-end testing of the swagger API security middleware
*/
'use strict';
/* eslint-disable max-nested-callbacks */
// eslint-disable-next-line no-unused-vars
const testGlobals = require('../../tools/test/testGlobals.js');
const _ = require('lodash');
const request = require('supertest');
const express = require('express');
const sinon = require('sinon');
const chai = require('chai');
const initDevApi = require('../dev_server.js');
const config = require(global.configFile);
/**
* Use fake timers so we can control the timing of the rate-limit window
*/
const fakeTimer = sinon.useFakeTimers();
const expect = chai.expect;
/**
* Test values
*/
const oldRateLimits = _.cloneDeep(config.rateLimits.api);
const TEST_RATE_WINDOW_MS = 500;
// Correct auth method (Bearer), correct token
const TOKEN_VALID = 'YTM2ZGQ1NzUtOWFmNS01MjMyLTg5MjYtM2NkZjA5ZDU2ZGU1';
const HEADER_VALID = 'Bearer ' + TOKEN_VALID;
/**
* Use supertest to make an authenticated request to the server
*
* @param {Object} app - The express app to make the request to
*
* @returns {Promise} - Promise for the result of making the request
*/
function makeAuthenticatedRequest(app) {
return request(app)
.get('/dev/v0/test')
.set('Accept', 'application/json')
.set('Authorization', HEADER_VALID);
}
/**
* Tests
*/
describe('E2E: rate limiting test', () => {
let app;
before(() => {
//
// Change the config to reduce the rate limit limits for testing
//
config.rateLimits.api.windowMs = TEST_RATE_WINDOW_MS;
config.rateLimits.api.max = 2;
//
// Initialise the test app
//
app = express();
const devApiRouter = initDevApi.init();
app.use('/dev', devApiRouter);
});
/**
* Put the old limits and real timers back after all the tests are complete
*/
after(() => {
_.merge(config.rateLimits.api, oldRateLimits);
fakeTimer.restore();
});
/**
* Advance the fakeTimer after each test so we get a new rate-limit window
*/
afterEach(() => {
fakeTimer.tick(TEST_RATE_WINDOW_MS + 1);
});
describe('requests that don\'t exceed the limit', () => {
it('are allowed', () => {
const req1 = makeAuthenticatedRequest(app)
.expect(200);
return req1.then(() => {
return makeAuthenticatedRequest(app)
.expect(200);
});
});
it('inform the caller how many requests are left', () => {
return makeAuthenticatedRequest(app)
.expect(200)
.expect('x-ratelimit-limit', '2')
.expect('x-ratelimit-remaining', '1');
});
});
describe('requests that exceed the limit', () => {
it('respond with 429 Too Many Requests', () => {
const req1 = makeAuthenticatedRequest(app)
.expect(200);
const req2 = req1.then(() => {
return makeAuthenticatedRequest(app)
.expect(200);
});
return req2.then(() => {
return makeAuthenticatedRequest(app)
.expect(429);
});
});
it('return an error code and description in the body', () => {
const req1 = makeAuthenticatedRequest(app)
.expect(200);
const req2 = req1.then(() => {
return makeAuthenticatedRequest(app)
.expect(200);
});
return req2.then(() => {
return makeAuthenticatedRequest(app)
.expect(429)
.then((response) => {
return expect(response.body).to.deep.equal({
code: 30500,
description: 'Rate limit reached. Please wait and try again.'
});
});
});
});
});
});