|
| 1 | +'use strict'; |
| 2 | + |
| 3 | +// A failed storage read reaches the API v1 read callbacks from a promise |
| 4 | +// handler (lib/storage/run-with-callback.js). A callback that reads the null |
| 5 | +// result there throws an unhandled rejection, which ends the process. These |
| 6 | +// tests fail the read the same way and check the request is answered and the |
| 7 | +// server keeps serving. |
| 8 | + |
| 9 | +var request = require('supertest'); |
| 10 | +require('should'); |
| 11 | +var language = require('../lib/language')(); |
| 12 | +var runWithCallback = require('../lib/storage/run-with-callback'); |
| 13 | + |
| 14 | +describe('API v1 reads when storage fails', function () { |
| 15 | + this.timeout(15000); |
| 16 | + var self = this; |
| 17 | + var known = 'b723e97aa97846eb92d5264f084b2823f57c4aa1'; |
| 18 | + |
| 19 | + before(function (done) { |
| 20 | + process.env.API_SECRET = 'this is my long pass phrase'; |
| 21 | + self.env = require('../lib/server/env')(); |
| 22 | + self.env.settings.authDefaultRoles = 'readable'; |
| 23 | + self.env.settings.enable = ['careportal', 'api']; |
| 24 | + self.app = require('express')(); |
| 25 | + self.app.enable('api'); |
| 26 | + require('../lib/server/bootevent')(self.env, language).boot(function booted (ctx) { |
| 27 | + self.ctx = ctx; |
| 28 | + self.ctx.ddata = require('../lib/data/ddata')(); |
| 29 | + self.app.use('/api', require('../lib/api/')(self.env, ctx)); |
| 30 | + done(); |
| 31 | + }); |
| 32 | + }); |
| 33 | + |
| 34 | + // Stands in for a storage call whose promise rejects, delivered the way the |
| 35 | + // storage modules deliver it. |
| 36 | + function failingRead () { |
| 37 | + var fn = Array.prototype.slice.call(arguments).find(function (arg) { return typeof arg === 'function'; }); |
| 38 | + return runWithCallback(function () { throw new Error('storage unavailable at db.internal:27017'); }, fn); |
| 39 | + } |
| 40 | + |
| 41 | + function expectAnsweredAndAlive (path, done) { |
| 42 | + request(self.app) |
| 43 | + .get(path) |
| 44 | + .set('api-secret', known) |
| 45 | + .timeout(5000) |
| 46 | + .expect(500) |
| 47 | + .end(function (err, res) { |
| 48 | + if (err) return done(err); |
| 49 | + JSON.stringify(res.body).should.not.match(/db\.internal|27017|storage unavailable/); |
| 50 | + request(self.app) |
| 51 | + .get('/api/status.json') |
| 52 | + .timeout(5000) |
| 53 | + .expect(200) |
| 54 | + .end(done); |
| 55 | + }); |
| 56 | + } |
| 57 | + |
| 58 | + describe('GET /api/v1/activity', function () { |
| 59 | + var original; |
| 60 | + before(function () { original = self.ctx.activity.list; self.ctx.activity.list = failingRead; }); |
| 61 | + after(function () { self.ctx.activity.list = original; }); |
| 62 | + |
| 63 | + it('answers 500 without the storage error text, and the server keeps serving', function (done) { |
| 64 | + expectAnsweredAndAlive('/api/activity/', done); |
| 65 | + }); |
| 66 | + }); |
| 67 | + |
| 68 | + describe('GET /api/v1/profile/current', function () { |
| 69 | + var original; |
| 70 | + before(function () { original = self.ctx.profile.last; self.ctx.profile.last = failingRead; }); |
| 71 | + after(function () { self.ctx.profile.last = original; }); |
| 72 | + |
| 73 | + it('answers 500 without the storage error text, and the server keeps serving', function (done) { |
| 74 | + expectAnsweredAndAlive('/api/profile/current', done); |
| 75 | + }); |
| 76 | + }); |
| 77 | +}); |
0 commit comments