From e52c1d16fe1adcf76a0ac74deec75fac419f05c3 Mon Sep 17 00:00:00 2001 From: Jari Bakken Date: Fri, 5 Dec 2014 17:20:17 +0100 Subject: [PATCH] Begin work on running tests against the database: * Add Travis postgresql setup. * Replace "db mocks" with a before hook that creates the same data through the HTTP API. * Reset DB and re-create all fixtures for each test. We'll need something better here. * CAVEAT: no concept of a dev vs test database. Running tests will clear data from the currently configured database. --- .travis.yml | 5 ++ lib/strategyApi.js | 2 +- package.json | 1 - test/eventApiSpec.js | 7 +-- test/eventDbMock.js | 111 ---------------------------------------- test/eventStoreSpec.js | 26 ++-------- test/featureApiSpec.js | 22 +++++--- test/featureDbMock.js | 56 -------------------- test/routerSpec.js | 5 +- test/specHelper.js | 106 ++++++++++++++++++++++++++++---------- test/strategyApiSpec.js | 10 ++-- test/strategyDbMock.js | 41 --------------- 12 files changed, 113 insertions(+), 279 deletions(-) delete mode 100644 test/eventDbMock.js delete mode 100644 test/featureDbMock.js delete mode 100644 test/strategyDbMock.js diff --git a/.travis.yml b/.travis.yml index d661ea73c8..0bf89e16c2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,11 @@ language: node_js node_js: - "0.10" +env: DATABASE_URL=postgres://postgres@localhost:5432/unleash_test before_script: - echo '--timeout 10000' > test/mocha.opts +- psql -c 'create database unleash_test;' -U postgres +- ./node_modules/.bin/db-migrate up script: - npm install - npm test @@ -11,3 +14,5 @@ notifications: hipchat: rooms: secure: GiIDk52xccnUKnevjLE+w6eUXg0jfV7oOmagw5VnOV5jXGUxdzMk/Q9um+oSClEPE51IvF76zoFEKPIX/CNdjgalEr+CZADy1gene/YRGrNgrXmYYmiU1/dNzelpla1WpKPrY2pkbOgKxrCR9ScID+pMs6vzvJnPwK9vu66W61U= +addons: + postgresql: "9.3" \ No newline at end of file diff --git a/lib/strategyApi.js b/lib/strategyApi.js index 6a1e469d5e..3b11e82ed8 100644 --- a/lib/strategyApi.js +++ b/lib/strategyApi.js @@ -18,7 +18,7 @@ module.exports = function (app) { app.get('/strategies/:name', function (req, res) { strategyDb.getStrategy(req.params.name) .then(function (strategy) { res.json(strategy); }) - .catch(function () { res.json(404, {error: 'Could not find strategy'}); }); + .catch(function () { res.status(404).json({error: 'Could not find strategy'}); }); }); app.delete('/strategies/:name', function (req, res) { diff --git a/package.json b/package.json index 0bdd4ede95..aa773127f8 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,6 @@ "jshint": "2.5.2", "mocha": "1.20.1", "mocha-lcov-reporter": "0.0.1", - "mockery": "1.4.0", "pre-commit": "0.0.9", "react-tools": "^0.12.0", "supertest": "0.13.0", diff --git a/test/eventApiSpec.js b/test/eventApiSpec.js index 3191aef91a..76baa50d68 100644 --- a/test/eventApiSpec.js +++ b/test/eventApiSpec.js @@ -1,11 +1,6 @@ -var specHelper = require('./specHelper'); +var request = require('./specHelper').request; describe('The event api', function () { - var request; - - before(function () { request = specHelper.setupMockServer(); }); - after(specHelper.tearDownMockServer); - it('returns events', function (done) { request .get('/events') diff --git a/test/eventDbMock.js b/test/eventDbMock.js deleted file mode 100644 index 526505b0a4..0000000000 --- a/test/eventDbMock.js +++ /dev/null @@ -1,111 +0,0 @@ -var Promise = require("bluebird"); - -var events = [ - { - "id": 1, - "created_at": 1414159948677, - "type": "feature-create", - "created_by": "me", - "data": { - - } - }, - { - "id": 2, - "created_at": 1414159948677, - "type": "feature-create", - "created_by": "me", - "data": { - "foo": "bar" - } - }, - { - "id": 3, - "created_at": 1414159948677, - "type": "feature-create", - "created_by": "me", - "data": { - "foo": "rab", - "name": "myname" - } - } -]; - -var filterableEvents = [ - { - "id": 1, - "created_at": 1414159948677, - "type": "feature-create", - "created_by": "me", - "data": { - "name": "foo" - } - }, - { - "id": 2, - "created_at": 1414159948677, - "type": "feature-create", - "created_by": "me", - "data": { - "name": "bar" - } - }, - { - "id": 3, - "created_at": 1414159948677, - "type": "feature-create", - "created_by": "me", - "data": { - "name": "myname" - } - } -]; - - -function filterEventsByName(name) { - return filterableEvents.filter(function (n){return n.data.name===name;}); -} - -function getEvent(name) { - var eventFound; - events.forEach(function (event) { - if (event.name === name) { - eventFound = event; - } - }); - - return eventFound; -} - -function storeEvent() { - return new Promise(function (resolve) { - resolve(); - }); -} - - -module.exports = { - store: storeEvent, - - getEvents: function() { - return new Promise(function (resolve) { - resolve(events); - }); - }, - - getEventsFilterByName: function(name) { - return new Promise(function (resolve) { - resolve(filterEventsByName(name)); - }); - }, - - getEvent: function(name) { - var event = getEvent(name); - if(event) { - return Promise.resolve(event); - } else { - return Promise.reject("Event not found"); - } - } - -}; \ No newline at end of file diff --git a/test/eventStoreSpec.js b/test/eventStoreSpec.js index 7405581a0c..4a01d28ea8 100644 --- a/test/eventStoreSpec.js +++ b/test/eventStoreSpec.js @@ -1,28 +1,8 @@ -var assert = require('assert'), - mockery = require('mockery'), - eventType = require('../lib/eventType'), - eventStore; - +var assert = require('assert'), + eventType = require('../lib/eventType'), + eventStore = require('../lib/eventStore'); describe('EventStore', function () { - before(function () { - mockery.enable({ - warnOnReplace: false, - warnOnUnregistered: false, - useCleanCache: true - }); - - mockery.registerSubstitute('./eventDb', '../test/eventDbMock'); - mockery.registerSubstitute('./strategyDb', '../test/strategyDbMock'); - - eventStore = require('../lib/eventStore'); - }); - - after(function () { - mockery.disable(); - mockery.deregisterAll(); - }); - describe('#create()', function () { it('should emit event', function (done) { eventStore.once(eventType.featureCreated, function (x) { diff --git a/test/featureApiSpec.js b/test/featureApiSpec.js index 50a6cd2895..24ebcd4cd0 100644 --- a/test/featureApiSpec.js +++ b/test/featureApiSpec.js @@ -1,16 +1,26 @@ +var assert = require('assert'); var specHelper = require('./specHelper'); +var request = specHelper.request; +var stringify = function (o) { return JSON.stringify(o, null, ' '); }; describe('The features api', function () { - var request; + beforeEach(function (done) { + var d = function (err) { console.log('done', err); done.bind(null, err)(); }; - before(function () { request = specHelper.setupMockServer(); }); - after(specHelper.tearDownMockServer); + specHelper.db.resetAndSetup() + .then(d.bind(null, null)) + .catch(d); + }); - it('returns three mocked feature toggles', function (done) { + it('returns three feature toggles', function (done) { request .get('/features') .expect('Content-Type', /json/) - .expect(200, done); + .expect(200) + .end(function (err, res) { + assert(res.body.features.length === 3, "expected 3 features, got " + stringify(res.body)); + done(); + }); }); it('gets a feature by name', function (done) { @@ -23,7 +33,7 @@ describe('The features api', function () { it('creates new feature toggle', function (done) { request .post('/features') - .send({name: 'com.test.feature', 'enabled': false}) + .send({name: 'com.test.feature', enabled: false}) .set('Content-Type', 'application/json') .expect(201, done); }); diff --git a/test/featureDbMock.js b/test/featureDbMock.js deleted file mode 100644 index fcf9082ca4..0000000000 --- a/test/featureDbMock.js +++ /dev/null @@ -1,56 +0,0 @@ -var Promise = require("bluebird"); -var NotFoundError = require('../lib/error/NotFoundError'); - -var features = [ - { - "name": "featureX", - "description": "the #1 feature", - "enabled": true, - "strategy": "default" - }, - { - "name": "featureY", - "description": "soon to be the #1 feature", - "enabled": false, - "strategy": "baz", - "parameters": { - "foo": "bar" - } - }, - { - "name": "featureZ", - "description": "terrible feature", - "enabled": true, - "strategy": "baz", - "parameters": { - "foo": "rab" - } - } -]; - -function getFeature(name) { - var featureFound; - features.forEach(function (feature) { - if (feature.name === name) { - featureFound = feature; - } - }); - - return featureFound; -} - -module.exports = { - getFeatures: function() { - return new Promise(function (resolve) { - resolve(features); - }); - }, - getFeature: function(name) { - var feature = getFeature(name); - if(feature) { - return Promise.resolve(feature); - } else { - return Promise.reject(new NotFoundError("feature not found")); - } - } -}; \ No newline at end of file diff --git a/test/routerSpec.js b/test/routerSpec.js index 35ada85e1d..d66e897c65 100644 --- a/test/routerSpec.js +++ b/test/routerSpec.js @@ -1,10 +1,7 @@ var specHelper = require('./specHelper'); +var request = specHelper.request; describe('The routes', function () { - var request; - - before(function () { request = specHelper.setupMockServer(); }); - after(specHelper.tearDownMockServer); describe('healthcheck', function () { it('returns health good', function (done) { diff --git a/test/specHelper.js b/test/specHelper.js index 0323ff1658..9905fd80ff 100644 --- a/test/specHelper.js +++ b/test/specHelper.js @@ -1,37 +1,91 @@ -var request = require('supertest'); -var mockery = require('mockery'); - process.env.NODE_ENV = 'test'; -var server; +var Promise = require('bluebird'); +var request = require('supertest'); +var app = require('../app'); +var knex = require('../lib/dbPool'); -function setupMockServer() { - mockery.enable({ - warnOnReplace: false, - warnOnUnregistered: false, - useCleanCache: true +Promise.promisifyAll(request); +request = request(app); + +function createStrategies() { + return Promise.map([ + { + name: "default", + description: "Default on or off Strategy." + }, + { + name: "usersWithEmail", + description: "Active for users defined in the comma-separated emails-parameter.", + parametersTemplate: { + emails: "String" + } + } + ], function (strategy) { + return request + .post('/strategies').send(strategy) + .set('Content-Type', 'application/json') + .expect(201) + .endAsync(); }); - - mockery.registerSubstitute('./eventDb', '../test/eventDbMock'); - mockery.registerSubstitute('./featureDb', '../test/featureDbMock'); - mockery.registerSubstitute('./strategyDb', '../test/strategyDbMock'); - - var app = require('../app'); - - return request(app); } -function tearDownMockServer() { - mockery.disable(); - mockery.deregisterAll(); +function createFeatures() { + return Promise.map([ + { + "name": "featureX", + "description": "the #1 feature", + "enabled": true, + "strategy": "default" + }, + { + "name": "featureY", + "description": "soon to be the #1 feature", + "enabled": false, + "strategy": "baz", + "parameters": { + "foo": "bar" + } + }, + { + "name": "featureZ", + "description": "terrible feature", + "enabled": true, + "strategy": "baz", + "parameters": { + "foo": "rab" + } + } + ], function (feature) { + return request + .post('/features').send(feature) + .set('Content-Type', 'application/json') + .expect(201) + .endAsync(); + }); +} - if (server) { - server.server.close(); - server = null; - } +function destroyStrategies() { + return knex('strategies').del(); +} + +function destroyFeatures() { + return knex('features').del(); +} + +function resetDatabase() { + return Promise.all([destroyStrategies(), destroyFeatures()]); +} + +function setupDatabase() { + return Promise.all([createStrategies(), createFeatures()]); } module.exports = { - setupMockServer: setupMockServer, - tearDownMockServer: tearDownMockServer + request: request, + db: { + reset: resetDatabase, + setup: setupDatabase, + resetAndSetup: function () { return resetDatabase().then(setupDatabase); } + } }; \ No newline at end of file diff --git a/test/strategyApiSpec.js b/test/strategyApiSpec.js index 78f9cba6aa..579e897448 100644 --- a/test/strategyApiSpec.js +++ b/test/strategyApiSpec.js @@ -1,10 +1,12 @@ var specHelper = require('./specHelper'); +var request = specHelper.request; describe('The strategy api', function () { - var request; - - before(function () { request = specHelper.setupMockServer(); }); - after(specHelper.tearDownMockServer); + beforeEach(function (done) { + specHelper.db.resetAndSetup() + .then(done.bind(null, null)) + .catch(done); + }); it('gets all strategies', function (done) { request diff --git a/test/strategyDbMock.js b/test/strategyDbMock.js deleted file mode 100644 index 148e20620e..0000000000 --- a/test/strategyDbMock.js +++ /dev/null @@ -1,41 +0,0 @@ -var Promise = require("bluebird"); - -var strategies = [ - { - name: "default", - description: "Default on or off Strategy." - }, - { - name: "usersWithEmail", - description: "Active for users defined in the comma-separated emails-parameter.", - parametersTemplate: { - emails: "String" - } - }, - { - name: "deletable", - description: "deletable" - } -]; - -function byName(name) { - return strategies.filter(function(s) { - return s.name === name; - })[0]; -} - -module.exports = { - getStrategies: function() { - return new Promise(function (resolve) { - resolve(strategies); - }); - }, - getStrategy: function(name) { - var strategy = byName(name); - if(strategy) { - return Promise.resolve(strategy); - } else { - return Promise.reject("strategy not found"); - } - } -}; \ No newline at end of file