/** * @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.' }); }); }); }); }); });