diff --git a/.gitignore b/.gitignore index 3f0dd79c56..5e30f281c2 100644 --- a/.gitignore +++ b/.gitignore @@ -39,3 +39,4 @@ unleash-server.tar.gz jsconfig.json typings .vscode +.nyc_output diff --git a/.travis.yml b/.travis.yml index 3a1fab33c9..1e6bca5c18 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,8 +8,8 @@ before_script: - psql -c 'create database unleash_test;' -U postgres script: - npm install -- npm run test - npm run test:coverage +after_success: - npm run test:coverage-report notifications: slack: diff --git a/README.md b/README.md index b5b5537baf..90e37ba38d 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # unleash -__Warning: We are in the process of splitting up unleash into multiple packages in this repository, if you want to test the previous package see [previous tag](https://github.com/finn-no/unleash/tree/v1.0.0-alpha.2) __ +__Warning: We are in the process of splitting up unleash into multiple packages in this repository, if you want to test the previous package see [previous tag](https://github.com/unleash/unleash/tree/v1.0.0-alpha.2) __ [![Build Status](https://travis-ci.org/Unleash/unleash.svg?branch=master)](https://travis-ci.org/Unleash/unleash) [![Coverage Status](https://coveralls.io/repos/github/Unleash/unleash/badge.svg?branch=master)](https://coveralls.io/github/Unleash/unleash?branch=master) @@ -12,11 +12,11 @@ __Warning: We are in the process of splitting up unleash into multiple packages This repo contains the unleash-server, which contains the admin UI and a place to ask for the status of features. In order to make use of unleash you will also need a client implementation. Known client implementations: -- [unleash-client-java](https://github.com/finn-no/unleash-client-java) -- [unleash-client-node](https://github.com/finn-no/unleash-client-node) +- [unleash-client-java](https://github.com/unleash/unleash-client-java) +- [unleash-client-node](https://github.com/unleash/unleash-client-node) ## Project details -- [Project Roadmap](https://github.com/finn-no/unleash/wiki/Roadmap) +- [Project Roadmap](https://github.com/unleash/unleash/wiki/Roadmap) ## Run with docker We have set up docker-compose to start postgres and the unleash server together. This makes it really fast to start up diff --git a/app.js b/app.js index 4d0d30cd71..3012293841 100644 --- a/app.js +++ b/app.js @@ -9,6 +9,7 @@ const log4js = require('log4js'); const logger = require('./lib/logger'); const routes = require('./lib/routes'); const path = require('path'); +const errorHandler = require('errorhandler'); module.exports = function (config) { const app = express(); @@ -47,7 +48,7 @@ module.exports = function (config) { app.use(baseUriPath, router); if (process.env.NODE_ENV !== 'production') { - app.use(require('errorhandler')()); + app.use(errorHandler()); } return app; diff --git a/lib/db/db-pool.js b/lib/db/db-pool.js index 086e44e6fd..9ecea4f695 100644 --- a/lib/db/db-pool.js +++ b/lib/db/db-pool.js @@ -2,12 +2,12 @@ const knex = require('knex'); -module.exports.createDb = function (databaseConnection, schema = 'public') { +module.exports.createDb = function ({ databaseUri, poolMin = 2, poolMax = 20, databaseSchema = 'public' }) { const db = knex({ client: 'pg', - connection: databaseConnection, - pool: { min: 2, max: 20 }, - searchPath: schema, + connection: databaseUri, + pool: { min: poolMin, max: poolMax }, + searchPath: databaseSchema, }); return db; diff --git a/lib/db/index.js b/lib/db/index.js index 58ca375b22..19af24c75b 100644 --- a/lib/db/index.js +++ b/lib/db/index.js @@ -9,7 +9,7 @@ const ClientMetricsStore = require('./client-metrics-store'); const ClientStrategyStore = require('./client-strategy-store'); module.exports.createStores = (config) => { - const db = createDb(config.databaseUri, config.databaseSchema); + const db = createDb(config); const eventStore = new EventStore(db); return { diff --git a/migrator.js b/migrator.js index b22b517969..39aeecc9c5 100644 --- a/migrator.js +++ b/migrator.js @@ -1,13 +1,12 @@ 'use strict'; -const DBMigrate = require('db-migrate'); -const path = require('path'); +const { getInstance } = require('db-migrate'); const parseDbUrl = require('parse-database-url'); -function migrateDb (dbUrl, schema = "public") { - const custom = parseDbUrl(dbUrl); - custom.schema = schema; - const dbmigrate = DBMigrate.getInstance(true, { +function migrateDb ({ databaseUri, databaseSchema = 'public' }) { + const custom = parseDbUrl(databaseUri); + custom.schema = databaseSchema; + const dbmigrate = getInstance(true, { cwd: __dirname, config: { custom }, env: 'custom' } @@ -15,4 +14,4 @@ function migrateDb (dbUrl, schema = "public") { return dbmigrate.up(); } -module.exports = migrateDb; \ No newline at end of file +module.exports = migrateDb; diff --git a/package.json b/package.json index 861fc5856b..af9e52e2a3 100644 --- a/package.json +++ b/package.json @@ -19,10 +19,10 @@ ], "repository": { "type": "git", - "url": "ssh://git@github.com:finn-no/unleash.git" + "url": "ssh://git@github.com:unleash/unleash.git" }, "bugs": { - "url": "https://github.com/finn-no/unleash/issues" + "url": "https://github.com/unleash/unleash/issues" }, "engines": { "node": "6" @@ -39,14 +39,13 @@ "start:dev:pg-chain": "export DATABASE_URL=postgres://$PGUSER:$PGPASSWORD@localhost:$PGPORT/postgres ; db-migrate up && npm run start:dev", "db-migrate": "db-migrate up", "db-migrate:down": "db-migrate down", - "test": "export PORT=4243 ; mocha --recursive test", - "test:unit": "mocha test/unit/**/*.js ", + "test": "PORT=4243 ava **/**test.js", "test:docker": "./scripts/docker-postgres.sh", - "test:watch": "mocha --watch test test/*", + "test:watch": "npm run test -- --watch", "test:pg-virtualenv": "pg_virtualenv npm run test:pg-virtualenv-chai", "test:pg-virtualenv-chain": "export TEST_DATABASE_URL=postgres://$PGUSER:$PGPASSWORD@localhost:$PGPORT/postgres ; npm run db-migrate-testdb && npm test", - "test:coverage": "istanbul cover ./node_modules/mocha/bin/_mocha test --report lcovonly -- -R spec --recursive", - "test:coverage-report": "cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js && rm -rf ./coverage" + "test:coverage": "nyc npm run test", + "test:coverage-report": "nyc report --reporter=text-lcov | coveralls" }, "dependencies": { "body-parser": "1.15.2", @@ -70,13 +69,13 @@ "yallist": "^2.0.0" }, "devDependencies": { + "@types/node": "^6.0.46", "ava": "^0.16.0", - "coveralls": "^2.11.14", - "istanbul": "^0.4.5", - "mocha": "^3.0.2", - "mocha-lcov-reporter": "1.2.0", + "coveralls": "^2.11.15", + "nyc": "^8.4.0", "sinon": "^1.17.5", - "supertest": "^2.0.0", + "superagent": "^2.3.0", + "supertest": "^2.0.1", "supervisor": "^0.11.0", "unleash-frontend": "1.0.0-alpha.2" } diff --git a/server-impl.js b/server-impl.js index 4d723ab668..ca3b790648 100644 --- a/server-impl.js +++ b/server-impl.js @@ -3,6 +3,7 @@ const logger = require('./lib/logger'); const migrator = require('./migrator'); const { createStores } = require('./lib/db'); +const getApp = require('./app'); const DEFAULT_OPTIONS = { databaseUri: process.env.DATABASE_URL || 'postgres://unleash_user:passord@localhost:5432/unleash', @@ -21,7 +22,7 @@ function createApp (options) { stores, }; - const app = require('./app')(config); + const app = getApp(config); const server = app.listen(app.get('port'), () => { logger.info(`Unleash started on ${app.get('port')}`); }); diff --git a/test/.eslintrc b/test/.eslintrc deleted file mode 100644 index 4413073ce1..0000000000 --- a/test/.eslintrc +++ /dev/null @@ -1,6 +0,0 @@ -{ - "env": { - "browser": true, - "mocha": true - } -} diff --git a/test/e2e/event-api.test.js b/test/e2e/event-api.test.js index 265f6c1824..22a3221a25 100644 --- a/test/e2e/event-api.test.js +++ b/test/e2e/event-api.test.js @@ -1,27 +1,27 @@ 'use strict'; -const specHelper = require('./util/test-helper'); -let request; +const test = require('ava'); +const { setupApp } = require('./util/test-helper'); +const logger = require('../../lib/logger'); -describe('The event api', () => { - beforeEach(done => { - specHelper.setupApp().then((app) => { - request = app.request; - done(); - }); - }); - - it('returns events', done => { - request - .get('/api/events') - .expect('Content-Type', /json/) - .expect(200, done); - }); - - it('returns events given a name', done => { - request - .get('/api/events/myname') - .expect('Content-Type', /json/) - .expect(200, done); - }); +test.beforeEach(() => { + logger.setLevel('FATAL'); +}); + +test.serial('returns events', async (t) => { + const { request, destroy } = await setupApp('event_api_serial'); + return request + .get('/api/events') + .expect('Content-Type', /json/) + .expect(200) + .then(destroy); +}); + +test.serial('returns events given a name', async (t) => { + const { request, destroy } = await setupApp('event_api_serial'); + return request + .get('/api/events/myname') + .expect('Content-Type', /json/) + .expect(200) + .then(destroy); }); diff --git a/test/e2e/feature-api.test.js b/test/e2e/feature-api.test.js index dca3a3ee2c..a30bef0197 100644 --- a/test/e2e/feature-api.test.js +++ b/test/e2e/feature-api.test.js @@ -1,176 +1,190 @@ 'use strict'; +const { test } = require('ava'); +const { setupApp } = require('./util/test-helper'); const logger = require('../../lib/logger'); -const assert = require('assert'); -const specHelper = require('./util/test-helper'); -const stringify = function (o) { - return JSON.stringify(o, null, ' '); -}; -let request; - -describe('The features api', () => { - beforeEach(done => { - specHelper.setupApp().then((app) => { - request = app.request; - done(); - }); - }); - - it('returns three feature toggles', done => { - request - .get('/features') - .expect('Content-Type', /json/) - .expect(200) - .end((err, res) => { - assert(res.body.features.length === 3, `expected 3 features, got ${stringify(res.body)}`); - done(); - }); - }); - - it('gets a feature by name', done => { - request - .get('/features/featureX') - .expect('Content-Type', /json/) - .expect(200, done); - }); - - it('cant get feature that dose not exist', done => { - logger.setLevel('FATAL'); - request - .get('/features/myfeature') - .expect('Content-Type', /json/) - .expect(404, done); - }); - - it('creates new feature toggle', done => { - request - .post('/features') - .send({ name: 'com.test.feature', enabled: false }) - .set('Content-Type', 'application/json') - .expect(201, done); - }); - - it('creates new feature toggle with createdBy', done => { - logger.setLevel('FATAL'); - request - .post('/features') - .send({ name: 'com.test.Username', enabled: false }) - .set('Cookie', ['username=ivaosthu']) - .set('Content-Type', 'application/json') - .end(() => { - request - .get('/api/events') - .end((err, res) => { - assert.equal(res.body.events[0].createdBy, 'ivaosthu'); - done(); - }); - }); - }); - - it('require new feature toggle to have a name', done => { - logger.setLevel('FATAL'); - request - .post('/features') - .send({ name: '' }) - .set('Content-Type', 'application/json') - .expect(400, done); - }); - - it('can not change status of feature toggle that does not exist', done => { - logger.setLevel('FATAL'); - request - .put('/features/should-not-exist') - .send({ name: 'should-not-exist', enabled: false }) - .set('Content-Type', 'application/json') - .expect(404, done); - }); - - it('can change status of feature toggle that does exist', done => { - logger.setLevel('FATAL'); - request - .put('/features/featureY') - .send({ name: 'featureY', enabled: true }) - .set('Content-Type', 'application/json') - .expect(200, done); - }); - - it('archives a feature by name', done => { - request - .delete('/features/featureX') - .expect(200, done); - }); - - it('can not archive unknown feature', done => { - request - .delete('/features/featureUnknown') - .expect(404, done); - }); - - it('refuses to create a feature with an existing name', done => { - request - .post('/features') - .send({ name: 'featureX' }) - .set('Content-Type', 'application/json') - .expect(403, done); - }); - - it('refuses to validate a feature with an existing name', done => { - request - .post('/features-validate') - .send({ name: 'featureX' }) - .set('Content-Type', 'application/json') - .expect(403, done); - }); - - describe('new strategies api', () => { - it('automatically map existing strategy to strategies array', (done) => { - request - .get('/features/featureY') - .expect('Content-Type', /json/) - .end((err, res) => { - assert.equal(res.body.strategies.length, 1, 'expected strategy added to strategies'); - assert.equal(res.body.strategy, res.body.strategies[0].name); - assert.deepEqual(res.body.parameters, res.body.strategies[0].parameters); - done(); - }); - }); - - it('can add two strategies to a feature toggle', (done) => { - request - .put('/features/featureY') - .send({ - name: 'featureY', - description: 'soon to be the #14 feature', - enabled: false, - strategies: [ - { - name: 'baz', - parameters: { foo: 'bar' }, - }, - ] }) - .set('Content-Type', 'application/json') - .expect(200, done); - }); - - it('should not be allowed to post both strategy and strategies', (done) => { - logger.setLevel('FATAL'); - request - .post('/features') - .send({ - name: 'featureConfusing', - description: 'soon to be the #14 feature', - enabled: false, - strategy: 'baz', - parameters: {}, - strategies: [ - { - name: 'baz', - parameters: { foo: 'bar' }, - }, - ] }) - .set('Content-Type', 'application/json') - .expect(400, done); - }); - }); +test.beforeEach(() => { + logger.setLevel('FATAL'); }); + +test.serial('returns three feature toggles', async t => { + const { request, destroy } = await setupApp('feature_api_serial'); + return request + .get('/features') + .expect('Content-Type', /json/) + .expect(200) + .expect((res) => { + t.true(res.body.features.length === 3); + }) + .then(destroy); +}); + +test.serial('gets a feature by name', async t => { + const { request, destroy } = await setupApp('feature_api_serial'); + return request + .get('/features/featureX') + .expect('Content-Type', /json/) + .expect(200) + .then(destroy); +}); + +test.serial('cant get feature that dose not exist', async t => { + const { request, destroy } = await setupApp('feature_api_serial'); + logger.setLevel('FATAL'); + return request + .get('/features/myfeature') + .expect('Content-Type', /json/) + .expect(404) + .then(destroy); +}); + +test.serial('creates new feature toggle', async t => { + const { request, destroy } = await setupApp('feature_api_serial'); + return request + .post('/features') + .send({ name: 'com.test.feature', enabled: false }) + .set('Content-Type', 'application/json') + .expect(201) + .then(destroy); +}); + +test.serial('creates new feature toggle with createdBy', async t => { + const { request, destroy } = await setupApp('feature_api_serial'); + logger.setLevel('FATAL'); + request + .post('/features') + .send({ name: 'com.test.Username', enabled: false }) + .set('Cookie', ['username=ivaosthu']) + .set('Content-Type', 'application/json') + .end(() => { + return request + .get('/api/events') + .expect((res) => { + t.true(res.body.events[0].createdBy === 'ivaosthu'); + }) + .then(destroy); + }); +}); + +test.serial('require new feature toggle to have a name', async t => { + const { request, destroy } = await setupApp('feature_api_serial'); + logger.setLevel('FATAL'); + return request + .post('/features') + .send({ name: '' }) + .set('Content-Type', 'application/json') + .expect(400) + .then(destroy); +}); + +test.serial('can not change status of feature toggle that does not exist', async t => { + const { request, destroy } = await setupApp('feature_api_serial'); + logger.setLevel('FATAL'); + return request + .put('/features/should-not-exist') + .send({ name: 'should-not-exist', enabled: false }) + .set('Content-Type', 'application/json') + .expect(404).then(destroy); +}); + +test.serial('can change status of feature toggle that does exist', async t => { + const { request, destroy } = await setupApp('feature_api_serial'); + logger.setLevel('FATAL'); + return request + .put('/features/featureY') + .send({ name: 'featureY', enabled: true }) + .set('Content-Type', 'application/json') + .expect(200).then(destroy); +}); + +test.serial('archives a feature by name', async t => { + const { request, destroy } = await setupApp('feature_api_serial'); + return request + .delete('/features/featureX') + .expect(200).then(destroy); +}); + +test.serial('can not archive unknown feature', async t => { + const { request, destroy } = await setupApp('feature_api_serial'); + return request + .delete('/features/featureUnknown') + .expect(404).then(destroy); +}); + +test.serial('refuses to create a feature with an existing name', async t => { + const { request, destroy } = await setupApp('feature_api_serial'); + return request + .post('/features') + .send({ name: 'featureX' }) + .set('Content-Type', 'application/json') + .expect(403).then(destroy); +}); + +test.serial('refuses to validate a feature with an existing name', async t => { + const { request, destroy } = await setupApp('feature_api_serial'); + return request + .post('/features-validate') + .send({ name: 'featureX' }) + .set('Content-Type', 'application/json') + .expect(403).then(destroy); +}); + + +test.serial('new strategies api automatically map existing strategy to strategies array', async t => { + const { request, destroy } = await setupApp('feature_api_serial'); + t.plan(3); + return request + .get('/features/featureY') + .expect('Content-Type', /json/) + .expect((res) => { + t.true(res.body.strategies.length === 1, 'expected strategy added to strategies'); + t.true(res.body.strategy === res.body.strategies[0].name); + t.deepEqual(res.body.parameters, res.body.strategies[0].parameters); + }) + .then(destroy); +}); + +test.serial('new strategies api can add two strategies to a feature toggle', async t => { + const { request, destroy } = await setupApp('feature_api_serial'); + return request + .put('/features/featureY') + .send({ + name: 'featureY', + description: 'soon to be the #14 feature', + enabled: false, + strategies: [ + { + name: 'baz', + parameters: { foo: 'bar' }, + }, + ], + }) + .set('Content-Type', 'application/json') + .expect(200) + .then(destroy); +}); + +test.serial('new strategies api should not be allowed to post both strategy and strategies', async t => { + const { request, destroy } = await setupApp('feature_api_serial'); + logger.setLevel('FATAL'); + return request + .post('/features') + .send({ + name: 'featureConfusing', + description: 'soon to be the #14 feature', + enabled: false, + strategy: 'baz', + parameters: {}, + strategies: [ + { + name: 'baz', + parameters: { foo: 'bar' }, + }, + ], + }) + .set('Content-Type', 'application/json') + .expect(400) + .then(destroy); +}); + diff --git a/test/e2e/feature-archive-api.test.js b/test/e2e/feature-archive-api.test.js index 9e421cb0df..a3b5c95090 100644 --- a/test/e2e/feature-archive-api.test.js +++ b/test/e2e/feature-archive-api.test.js @@ -1,45 +1,40 @@ 'use strict'; -const assert = require('assert'); -const specHelper = require('./util/test-helper'); -const stringify = function (o) { - return JSON.stringify(o, null, ' '); -}; +const test = require('ava'); +const { setupApp } = require('./util/test-helper'); +const logger = require('../../lib/logger'); -let request; - -describe('The archive features api', () => { - beforeEach(done => { - specHelper.setupApp().then((app) => { - request = app.request; - done(); - }); - }); - - - it('returns three archived toggles', done => { - request - .get('/api/archive/features') - .expect('Content-Type', /json/) - .expect(200) - .end((err, res) => { - assert(res.body.features.length === 3, `expected 3 features, got ${stringify(res.body)}`); - done(); - }); - }); - - it('revives a feature by name', done => { - request - .post('/api/archive/revive') - .send({ name: 'featureArchivedX' }) - .set('Content-Type', 'application/json') - .expect(200, done); - }); - - it('must set name when reviving toggle', done => { - request - .post('/api/archive/revive') - .send({ name: '' }) - .expect(400, done); - }); +test.beforeEach(() => { + logger.setLevel('FATAL'); +}); + +test.serial('returns three archived toggles', async t => { + const { request, destroy } = await setupApp('archive_serial'); + return request + .get('/api/archive/features') + .expect('Content-Type', /json/) + .expect(200) + .expect((res) => { + t.true(res.body.features.length === 3); + }) + .then(destroy); +}); + +test.serial('revives a feature by name', async t => { + const { request, destroy } = await setupApp('archive_serial'); + return request + .post('/api/archive/revive') + .send({ name: 'featureArchivedX' }) + .set('Content-Type', 'application/json') + .expect(200) + .then(destroy); +}); + +test.serial('must set name when reviving toggle', async t => { + const { request, destroy } = await setupApp('archive_serial'); + return request + .post('/api/archive/revive') + .send({ name: '' }) + .expect(400) + .then(destroy); }); diff --git a/test/e2e/metrics-api.test.js b/test/e2e/metrics-api.test.js index 1d404a9ac7..b6f326607c 100644 --- a/test/e2e/metrics-api.test.js +++ b/test/e2e/metrics-api.test.js @@ -1,64 +1,65 @@ 'use strict'; +const test = require('ava'); +const { setupApp } = require('./util/test-helper'); +const logger = require('../../lib/logger'); -const specHelper = require('./util/test-helper'); -const assert = require('assert'); -let request; - -describe('The metrics api', () => { - beforeEach(done => { - specHelper.setupApp().then((app) => { - request = app.request; - done(); - }); - }); - - it('should register client', (done) => { - request - .post('/api/client/register') - .send({ - appName: 'demo', - instanceId: 'test', - strategies: ['default'], - started: Date.now(), - interval: 10 - }) - .expect(202, done); - }); - - it('should accept client metrics', (done) => { - request - .post('/api/client/metrics') - .send({ - appName: 'demo', - instanceId: '1', - bucket: { - start: Date.now(), - stop: Date.now(), - toggles: {} - } - }) - .expect(202, done) - }); - - it('should get client strategies', done => { - request - .get('/api/client/strategies') - .expect('Content-Type', /json/) - .end((err, res) => { - assert(res.status, 200); - assert(res.body.length === 1, `expected 1 registerd client, got ${res.body}`); - done(); - });; - }); - - it('should get client instances', done => { - request - .get('/api/client/instances') - .expect('Content-Type', /json/) - .end((err, res) => { - assert(res.status, 200); - assert(res.body.length === 1, `expected 1 registerd client, got ${res.body}`); - done(); - });; - }); +test.beforeEach(() => { + logger.setLevel('FATAL'); }); + +test.serial('should register client', async (t) => { + const { request, destroy } = await setupApp('metrics_serial'); + return request + .post('/api/client/register') + .send({ + appName: 'demo', + instanceId: 'test', + strategies: ['default'], + started: Date.now(), + interval: 10 + }) + .expect(202) + .then(destroy); +}); + +test.serial('should accept client metrics', async t => { + const { request, destroy } = await setupApp('metrics_serial'); + return request + .post('/api/client/metrics') + .send({ + appName: 'demo', + instanceId: '1', + bucket: { + start: Date.now(), + stop: Date.now(), + toggles: {} + } + }) + .expect(202) + .then(destroy); +}); + +test.serial('should get client strategies', async t => { + const { request, destroy } = await setupApp('metrics_serial'); + return request + .get('/api/client/strategies') + .expect('Content-Type', /json/) + .expect((res) => { + t.true(res.status === 200); + t.true(res.body.length === 1); + }) + .then(destroy); +}); + +test.serial('should get client instances', async t => { + const { request, destroy } = await setupApp('metrics_serial'); + return request + .get('/api/client/instances') + .expect('Content-Type', /json/) + .expect((res) => { + t.true(res.status === 200); + t.true(res.body.length === 1); + }) + .then(destroy); +}); + diff --git a/test/e2e/router.test.js b/test/e2e/router.test.js index 894ea80a8b..b56a1e710e 100644 --- a/test/e2e/router.test.js +++ b/test/e2e/router.test.js @@ -1,23 +1,18 @@ 'use strict'; -const specHelper = require('./util/test-helper'); +const test = require('ava'); +const { setupApp } = require('./util/test-helper'); +const logger = require('../../lib/logger'); -let request; - -describe('The routes', () => { - beforeEach(done => { - specHelper.setupApp().then((app) => { - request = app.request; - done(); - }); - }); - - describe('healthcheck', () => { - it('returns health good', done => { - request.get('/health') - .expect('Content-Type', /json/) - .expect(200) - .expect('{"health":"GOOD"}', done); - }); - }); +test.beforeEach(() => { + logger.setLevel('FATAL'); +}); + +test('returns health good', async (t) => { + const { request, destroy } = await setupApp('health'); + return request.get('/health') + .expect('Content-Type', /json/) + .expect(200) + .expect('{"health":"GOOD"}') + .then(destroy); }); diff --git a/test/e2e/strategy-api.test.js b/test/e2e/strategy-api.test.js index 3601c3eee6..53214e751c 100644 --- a/test/e2e/strategy-api.test.js +++ b/test/e2e/strategy-api.test.js @@ -1,70 +1,81 @@ 'use strict'; -const specHelper = require('./util/test-helper'); -let request; +const test = require('ava'); +const { setupApp } = require('./util/test-helper'); +const logger = require('../../lib/logger'); -describe('The strategy api', () => { - beforeEach(done => { - specHelper.setupApp().then((app) => { - request = app.request; - done(); - }); - }); - - it('gets all strategies', done => { - request - .get('/api/strategies') - .expect('Content-Type', /json/) - .expect(200, done); - }); - - it('gets a strategy by name', done => { - request - .get('/api/strategies/default') - .expect('Content-Type', /json/) - .expect(200, done); - }); - - it('cant get a strategy by name that dose not exist', done => { - request - .get('/api/strategies/mystrategy') - .expect('Content-Type', /json/) - .expect(404, done); - }); - - it('creates a new strategy', done => { - request - .post('/api/strategies') - .send({ name: 'myCustomStrategy', description: 'Best strategy ever.' }) - .set('Content-Type', 'application/json') - .expect(201, done); - }); - - it('requires new strategies to have a name', done => { - request - .post('/api/strategies') - .send({ name: '' }) - .set('Content-Type', 'application/json') - .expect(400, done); - }); - - it('refuses to create a strategy with an existing name', done => { - request - .post('/api/strategies') - .send({ name: 'default' }) - .set('Content-Type', 'application/json') - .expect(403, done); - }); - - it('deletes a new strategy', done => { - request - .delete('/api/strategies/usersWithEmail') - .expect(200, done); - }); - - it('can\'t delete a strategy that dose not exist', done => { - request - .delete('/api/strategies/unknown') - .expect(404, done); - }); +test.beforeEach(() => { + logger.setLevel('FATAL'); +}); + +test.serial('gets all strategies', async (t) => { + const { request, destroy } = await setupApp('strategy_api_serial'); + return request + .get('/api/strategies') + .expect('Content-Type', /json/) + .expect(200) + .then(destroy); +}); + +test.serial('gets a strategy by name', async (t) => { + const { request, destroy } = await setupApp('strategy_api_serial'); + return request + .get('/api/strategies/default') + .expect('Content-Type', /json/) + .expect(200) + .then(destroy); +}); + +test.serial('cant get a strategy by name that dose not exist', async (t) => { + const { request, destroy } = await setupApp('strategy_api_serial'); + return request + .get('/api/strategies/mystrategy') + .expect('Content-Type', /json/) + .expect(404) + .then(destroy); +}); + +test.serial('creates a new strategy', async (t) => { + const { request, destroy } = await setupApp('strategy_api_serial'); + return request + .post('/api/strategies') + .send({ name: 'myCustomStrategy', description: 'Best strategy ever.' }) + .set('Content-Type', 'application/json') + .expect(201) + .then(destroy); +}); + +test.serial('requires new strategies to have a name', async (t) => { + const { request, destroy } = await setupApp('strategy_api_serial'); + return request + .post('/api/strategies') + .send({ name: '' }) + .set('Content-Type', 'application/json') + .expect(400) + .then(destroy); +}); + +test.serial('refuses to create a strategy with an existing name', async (t) => { + const { request, destroy } = await setupApp('strategy_api_serial'); + return request + .post('/api/strategies') + .send({ name: 'default' }) + .set('Content-Type', 'application/json') + .expect(403) + .then(destroy); +}); + +test.serial('deletes a new strategy', async (t) => { + const { request, destroy } = await setupApp('strategy_api_serial'); + return request + .delete('/api/strategies/usersWithEmail') + .expect(200) + .then(destroy); +}); + +test.serial('can\'t delete a strategy that dose not exist', async (t) => { + const { request, destroy } = await setupApp('strategy_api_serial', false); + return request + .delete('/api/strategies/unknown') + .expect(404); }); diff --git a/test/e2e/util/test-helper.js b/test/e2e/util/test-helper.js index ba859a7495..ca5b2347c3 100644 --- a/test/e2e/util/test-helper.js +++ b/test/e2e/util/test-helper.js @@ -2,28 +2,39 @@ process.env.NODE_ENV = 'test'; -let supertest = require('supertest'); - -const options = { - databaseUri: require('./database-config').getDatabaseUri(), - databaseSchema: 'test' -}; - +const supertest = require('supertest'); const migrator = require('../../../migrator'); const { createStores } = require('../../../lib/db'); +const { createDb } = require('../../../lib/db/db-pool'); +const _app = require('../../../app'); // because of migrator bug delete process.env.DATABASE_URL; -const db = require('../../../lib/db/db-pool').createDb(options.databaseUri); +function createApp (databaseSchema = 'test') { + const options = { + databaseUri: require('./database-config').getDatabaseUri(), + databaseSchema, + minPool: 0, + maxPool: 0, + }; + const db = createDb({ databaseUri: options.databaseUri, minPool: 0, maxPool: 0 }); -const createApp = db.raw(`DROP SCHEMA IF EXISTS ${options.databaseSchema} CASCADE; CREATE SCHEMA ${options.databaseSchema}`) - .then(() => migrator(options.databaseUri, options.databaseSchema)) - .then(() => { - const stores = createStores(options); - const app = require('../../../app')({stores}); - return { stores, request: supertest(app) }; - }); + return db.raw(`CREATE SCHEMA IF NOT EXISTS ${options.databaseSchema}`) + .then(() => migrator(options)) + .then(() => { + db.destroy(); + const stores = createStores(options); + const app = _app({ stores }); + return { + stores, + request: supertest(app), + destroy () { + return stores.db.destroy(); + }, + }; + }); +} function createStrategies (stores) { return [ @@ -49,7 +60,7 @@ function createClientStrategy (stores) { instanceId: 'test-1', strategies: ['default'], started: Date.now(), - interval: 10 + interval: 10, }, ].map(client => stores.clientStrategyStore.insert(client)); } @@ -61,7 +72,7 @@ function createClientInstance (stores) { instanceId: 'test-1', strategies: ['default'], started: Date.now(), - interval: 10 + interval: 10, }, ].map(client => stores.clientInstanceStore.insert(client)); } @@ -132,10 +143,10 @@ function createFeatures (stores) { function resetDatabase (stores) { return Promise.all([ - stores.db('strategies').del(), + stores.db('strategies').del(), stores.db('features').del(), stores.db('client_strategies').del(), - stores.db('client_instances').del() + stores.db('client_instances').del(), ]); } @@ -144,15 +155,15 @@ function setupDatabase (stores) { createStrategies(stores) .concat(createFeatures(stores) .concat(createClientInstance(stores)) - .concat(createClientStrategy(stores)))) + .concat(createClientStrategy(stores)))); } module.exports = { - setupApp () { - return createApp.then((app) => { + setupApp (name) { + return createApp(name).then((app) => { return resetDatabase(app.stores) - .then(() => setupDatabase(app.stores)) - .then(() => app); + .then(() => setupDatabase(app.stores)) + .then(() => app); }); - } + }, }; diff --git a/test/unit/event-differ.test.js b/test/unit/event-differ.test.js index ba607677e5..aec3b5a0de 100644 --- a/test/unit/event-differ.test.js +++ b/test/unit/event-differ.test.js @@ -1,99 +1,103 @@ 'use strict'; +const test = require('ava'); const eventDiffer = require('../../lib/event-differ'); -const eventType = require('../../lib/event-type'); -const assert = require('assert'); +const eventType = require('../../lib/event-type'); +const logger = require('../../lib/logger'); -describe('eventDiffer', () => { - it('fails if events include an unknown event type', () => { - const events = [ - { type: eventType.featureCreated, data: {} }, - { type: 'unknown-type', data: {} }, - ]; +test.beforeEach(() => { + logger.setLevel('FATAL'); +}); - assert.throws(() => { - eventDiffer.addDiffs(events); - }); - }); - - it('diffs a feature-update event', () => { - const feature = 'foo'; - const desc = 'bar'; - - const events = [ - { - type: eventType.featureUpdated, - data: { name: feature, description: desc, strategy: 'default', enabled: true, parameters: { value: 2 } }, - }, - { - type: eventType.featureCreated, - data: { name: feature, description: desc, strategy: 'default', enabled: false, parameters: { value: 1 } }, - }, - ]; +test('fails if events include an unknown event type', t => { + const events = [ + { type: eventType.featureCreated, data: {} }, + { type: 'unknown-type', data: {} }, + ]; + t.throws(() => { eventDiffer.addDiffs(events); - - assert.deepEqual(events[0].diffs, [ - { kind: 'E', path: ['enabled'], lhs: false, rhs: true }, - { kind: 'E', path: ['parameters', 'value'], lhs: 1, rhs: 2 }, - ]); - - assert.strictEqual(events[1].diffs, null); - }); - - it('diffs only against features with the same name', () => { - const events = [ - { - type: eventType.featureUpdated, - data: { name: 'bar', description: 'desc', strategy: 'default', enabled: true, parameters: {} }, - }, - { - type: eventType.featureUpdated, - data: { name: 'foo', description: 'desc', strategy: 'default', enabled: false, parameters: {} }, - }, - { - type: eventType.featureCreated, - data: { name: 'bar', description: 'desc', strategy: 'default', enabled: false, parameters: {} }, - }, - { - type: eventType.featureCreated, - data: { name: 'foo', description: 'desc', strategy: 'default', enabled: true, parameters: {} }, - }, - ]; - - eventDiffer.addDiffs(events); - - assert.strictEqual(events[0].diffs[0].rhs, true); - assert.strictEqual(events[1].diffs[0].rhs, false); - assert.strictEqual(events[2].diffs, null); - assert.strictEqual(events[3].diffs, null); - }); - - it('sets an empty array of diffs if nothing was changed', () => { - const events = [ - { - type: eventType.featureUpdated, - data: { name: 'foo', description: 'desc', strategy: 'default', enabled: true, parameters: {} }, - }, - { - type: eventType.featureCreated, - data: { name: 'foo', description: 'desc', strategy: 'default', enabled: true, parameters: {} }, - }, - ]; - - eventDiffer.addDiffs(events); - assert.deepEqual(events[0].diffs, []); - }); - - it('sets diffs to null if there was nothing to diff against', () => { - const events = [ - { - type: eventType.featureUpdated, - data: { name: 'foo', description: 'desc', strategy: 'default', enabled: true, parameters: {} }, - }, - ]; - - eventDiffer.addDiffs(events); - assert.strictEqual(events[0].diffs, null); }); }); + +test('diffs a feature-update event', t => { + const feature = 'foo'; + const desc = 'bar'; + + const events = [ + { + type: eventType.featureUpdated, + data: { name: feature, description: desc, strategy: 'default', enabled: true, parameters: { value: 2 } }, + }, + { + type: eventType.featureCreated, + data: { name: feature, description: desc, strategy: 'default', enabled: false, parameters: { value: 1 } }, + }, + ]; + + eventDiffer.addDiffs(events); + + t.deepEqual(events[0].diffs, [ + { kind: 'E', path: ['enabled'], lhs: false, rhs: true }, + { kind: 'E', path: ['parameters', 'value'], lhs: 1, rhs: 2 }, + ]); + + t.true(events[1].diffs === null); +}); + +test('diffs only against features with the same name', t => { + const events = [ + { + type: eventType.featureUpdated, + data: { name: 'bar', description: 'desc', strategy: 'default', enabled: true, parameters: {} }, + }, + { + type: eventType.featureUpdated, + data: { name: 'foo', description: 'desc', strategy: 'default', enabled: false, parameters: {} }, + }, + { + type: eventType.featureCreated, + data: { name: 'bar', description: 'desc', strategy: 'default', enabled: false, parameters: {} }, + }, + { + type: eventType.featureCreated, + data: { name: 'foo', description: 'desc', strategy: 'default', enabled: true, parameters: {} }, + }, + ]; + + eventDiffer.addDiffs(events); + + t.true(events[0].diffs[0].rhs === true); + t.true(events[1].diffs[0].rhs === false); + t.true(events[2].diffs === null); + t.true(events[3].diffs === null); +}); + +test('sets an empty array of diffs if nothing was changed', t => { + const events = [ + { + type: eventType.featureUpdated, + data: { name: 'foo', description: 'desc', strategy: 'default', enabled: true, parameters: {} }, + }, + { + type: eventType.featureCreated, + data: { name: 'foo', description: 'desc', strategy: 'default', enabled: true, parameters: {} }, + }, + ]; + + eventDiffer.addDiffs(events); + t.deepEqual(events[0].diffs, []); +}); + +test('sets diffs to null if there was nothing to diff against', t => { + const events = [ + { + type: eventType.featureUpdated, + data: { name: 'foo', description: 'desc', strategy: 'default', enabled: true, parameters: {} }, + }, + ]; + + eventDiffer.addDiffs(events); + t.true(events[0].diffs === null); +}); + diff --git a/test/unit/helper/legacy-feature-mapper.test.js b/test/unit/helper/legacy-feature-mapper.test.js index 68167fca58..0a181b5775 100644 --- a/test/unit/helper/legacy-feature-mapper.test.js +++ b/test/unit/helper/legacy-feature-mapper.test.js @@ -1,66 +1,63 @@ 'use strict'; -const assert = require('assert'); - +const test = require('ava'); const mapper = require('../../../lib/helper/legacy-feature-mapper'); -describe('legacy-feature-mapper', () => { - it('adds old fields to feature', () => { - const feature = { - name: 'test', - enabled: 0, - strategies: [{ - name: 'default', - parameters: { - val: 'bar', - }, - }], - }; - - const mappedFeature = mapper.addOldFields(feature); - - assert.equal(mappedFeature.name, feature.name); - assert.equal(mappedFeature.enabled, feature.enabled); - assert.equal(mappedFeature.strategy, feature.strategies[0].name); - assert.notEqual(mappedFeature.parameters, feature.strategies[0].parameters); - assert.deepEqual(mappedFeature.parameters, feature.strategies[0].parameters); - }); - - it('transforms fields to new format', () => { - const feature = { - name: 'test', - enabled: 0, - strategy: 'default', +test('adds old fields to feature', t => { + const feature = { + name: 'test', + enabled: 0, + strategies: [{ + name: 'default', parameters: { val: 'bar', }, - }; + }], + }; - const mappedFeature = mapper.toNewFormat(feature); + const mappedFeature = mapper.addOldFields(feature); - assert.equal(mappedFeature.name, feature.name); - assert.equal(mappedFeature.enabled, feature.enabled); - assert.equal(mappedFeature.strategies.length, 1); - assert.equal(mappedFeature.strategies[0].name, feature.strategy); - assert.deepEqual(mappedFeature.strategies[0].parameters, feature.parameters); - assert(mappedFeature.strategy === undefined); - assert(mappedFeature.parameters === undefined); - }); - - it('should not transform if it already is the new format', () => { - const feature = { - name: 'test', - enabled: 0, - strategies: [{ - name: 'default', - parameters: { - val: 'bar', - }, - }], - }; - - const mappedFeature = mapper.toNewFormat(feature); - - assert.equal(mappedFeature, feature); - }); + t.true(mappedFeature.name === feature.name); + t.true(mappedFeature.enabled === feature.enabled); + t.true(mappedFeature.strategy === feature.strategies[0].name); + t.true(mappedFeature.parameters !== feature.strategies[0].parameters); + t.deepEqual(mappedFeature.parameters, feature.strategies[0].parameters); +}); + +test('transforms fields to new format', t => { + const feature = { + name: 'test', + enabled: 0, + strategy: 'default', + parameters: { + val: 'bar', + }, + }; + + const mappedFeature = mapper.toNewFormat(feature); + + t.true(mappedFeature.name === feature.name); + t.true(mappedFeature.enabled === feature.enabled); + t.true(mappedFeature.strategies.length === 1); + t.true(mappedFeature.strategies[0].name === feature.strategy); + t.deepEqual(mappedFeature.strategies[0].parameters, feature.parameters); + t.true(mappedFeature.strategy === undefined); + t.true(mappedFeature.parameters === undefined); +}); + +test('should not transform if it already is the new format', t => { + const feature = { + name: 'test', + enabled: 0, + strategies: [{ + name: 'default', + parameters: { + val: 'bar', + }, + }], + }; + + const mappedFeature = mapper.toNewFormat(feature); + + t.true(mappedFeature === feature); }); diff --git a/test/unit/routes/feature.test.js b/test/unit/routes/feature.test.js index 5ab93cde85..16d0ef5339 100644 --- a/test/unit/routes/feature.test.js +++ b/test/unit/routes/feature.test.js @@ -1,61 +1,63 @@ 'use strict'; +const test = require('ava'); const store = require('./mocks/store'); - const supertest = require('supertest'); -const assert = require('assert'); +const logger = require('../../../lib/logger'); - -let request; -let featureToggleStore; - -describe('Unit: The features api', () => { - beforeEach(done => { - const stores = store.createStores(); - const app = require('../../../app')({ - baseUriPath: '', - stores: stores, - }); - - featureToggleStore = stores.featureToggleStore; - request = supertest(app); - done(); - }); - - it('should get empty getFeatures', (done) => { - request - .get('/features') - .expect('Content-Type', /json/) - .expect(200) - .end((err, res) => { - assert(res.body.features.length === 0); - done(); - }); - }); - - it('should get one getFeature', (done) => { - featureToggleStore.addFeature( { name: 'test', strategies: [{ name: 'default' }] } ); - - request - .get('/features') - .expect('Content-Type', /json/) - .expect(200) - .end((err, res) => { - assert(res.body.features.length === 1); - done(); - }); - }); - - it('should add version numbers for /features', (done) => { - featureToggleStore.addFeature( { name: 'test', strategies: [{ name: 'default' }] } ); - - request - .get('/features') - .expect('Content-Type', /json/) - .expect(200) - .end((err, res) => { - assert.equal(res.body.version, 1); - done(); - }); - }); +test.beforeEach(() => { + logger.setLevel('FATAL'); }); + +function getSetup () { + const base = `/random${Math.round(Math.random() * 1000)}`; + const stores = store.createStores(); + const app = require('../../../app')({ + baseUriPath: base, + stores, + }); + + return { + base, + featureToggleStore: stores.featureToggleStore, + request: supertest(app), + }; +} + +test('should get empty getFeatures', t => { + const { request, base } = getSetup(); + return request + .get(`${base}/features`) + .expect('Content-Type', /json/) + .expect(200) + .expect((res) => { + t.true(res.body.features.length === 0); + }); +}); + +test('should get one getFeature', t => { + const { request, featureToggleStore, base } = getSetup(); + featureToggleStore.addFeature({ name: 'test_', strategies: [{ name: 'default_' }] }); + + return request + .get(`${base}/features`) + .expect('Content-Type', /json/) + .expect(200) + .expect((res) => { + t.true(res.body.features.length === 1); + }); +}); + +test('should add version numbers for /features', t => { + const { request, featureToggleStore, base } = getSetup(); + featureToggleStore.addFeature({ name: 'test2', strategies: [{ name: 'default' }] }); + + return request + .get(`${base}/features`) + .expect('Content-Type', /json/) + .expect(200) + .expect((res) => { + t.true(res.body.version === 1); + }); +}); + diff --git a/test/unit/routes/health-check.js b/test/unit/routes/health-check.js deleted file mode 100644 index 3c71c0e4bb..0000000000 --- a/test/unit/routes/health-check.js +++ /dev/null @@ -1,58 +0,0 @@ -'use strict'; - -const store = require('./mocks/store'); - - -const supertest = require('supertest'); -const assert = require('assert'); -const sinon = require('sinon'); - -let request; -let db; - -describe('Unit: The health cheack api', () => { - beforeEach(done => { - const stores = store.createStores(); - db = stores.db; - const app = require('../../../app')({ - baseUriPath: '', - stores: stores, - }); - request = supertest(app); - done(); - }); - - it('should give 500 when db is failing', (done) => { - db.select = () => { - return { - from: () => Promise.reject(new Error('db error')) - } - } - - request - .get('/health') - .expect(500) - .end((err, res) => { - assert.equal(res.status, 500) - assert.equal(res.body.health, 'BAD'); - done(); - }); - }); - - it('should give 200 when db is not failing', (done) => { - request - .get('/health') - .expect(200, done) - }); - - it('should give health=GOOD when db is not failing', (done) => { - request - .get('/health') - .expect(200) - .end((err, res) => { - assert.equal(res.status, 200) - assert.equal(res.body.health, 'GOOD'); - done(); - }); - }); -}); diff --git a/test/unit/routes/health-check.test.js b/test/unit/routes/health-check.test.js new file mode 100644 index 0000000000..7b564f2c00 --- /dev/null +++ b/test/unit/routes/health-check.test.js @@ -0,0 +1,59 @@ +'use strict'; + +const test = require('ava'); +const store = require('./mocks/store'); +const supertest = require('supertest'); +const logger = require('../../../lib/logger'); + +test.beforeEach(() => { + logger.setLevel('FATAL'); +}); + + +function getSetup () { + const stores = store.createStores(); + const db = stores.db; + const app = require('../../../app')({ + baseUriPath: '', + stores, + }); + + return { + db, + request: supertest(app), + }; +} + +test('should give 500 when db is failing', t => { + const { request, db } = getSetup(); + db.select = () => ({ + from: () => Promise.reject(new Error('db error')), + }); + + return request + .get('/health') + .expect(500) + .expect((res) => { + t.true(res.status === 500); + t.true(res.body.health === 'BAD'); + }); +}); + +test('should give 200 when db is not failing', () => { + const { request } = getSetup(); + return request + .get('/health') + .expect(200); +}); + +test('should give health=GOOD when db is not failing', t => { + const { request } = getSetup(); + return request + .get('/health') + .expect(200) + .expect((res) => { + t.true(res.status === 200); + t.true(res.body.health === 'GOOD'); + }); +}); + diff --git a/test/unit/routes/metrics.test.js b/test/unit/routes/metrics.test.js index 227ce4d0ff..1d9e555b3b 100644 --- a/test/unit/routes/metrics.test.js +++ b/test/unit/routes/metrics.test.js @@ -1,68 +1,74 @@ 'use strict'; +const test = require('ava'); const store = require('./mocks/store'); const supertest = require('supertest'); -const assert = require('assert'); +const logger = require('../../../lib/logger'); -let request; - -describe('Unit: The metrics api', () => { - beforeEach(done => { - const stores = store.createStores(); - const app = require('../../../app')({ - baseUriPath: '', - stores: stores, - }); - - request = supertest(app); - done(); - }); - - it('should register client', (done) => { - request - .post('/api/client/register') - .send({ - appName: 'demo', - instanceId: 'test', - strategies: ['default'], - started: Date.now(), - interval: 10 - }) - .expect(202, done); - }); - - it('should require appName field', (done) => { - request - .post('/api/client/register') - .expect(400, done) - }); - - it('should require strategies field', (done) => { - request - .post('/api/client/register') - .send({ - appName: 'demo', - instanceId: 'test', - //strategies: ['default'], - started: Date.now(), - interval: 10 - }) - .expect(400, done) - }); - - - it('should accept client metrics', (done) => { - request - .post('/api/client/metrics') - .send({ - appName: 'demo', - instanceId: '1', - bucket: { - start: Date.now(), - stop: Date.now(), - toggles: {} - } - }) - .expect(202, done) - }); +test.beforeEach(() => { + logger.setLevel('FATAL'); +}); + +function getSetup () { + const stores = store.createStores(); + const app = require('../../../app')({ + baseUriPath: '', + stores, + }); + + return { + request: supertest(app), + }; +} + +test('should register client', () => { + const { request } = getSetup(); + return request + .post('/api/client/register') + .send({ + appName: 'demo', + instanceId: 'test', + strategies: ['default'], + started: Date.now(), + interval: 10, + }) + .expect(202); +}); + +test('should require appName field', () => { + const { request } = getSetup(); + return request + .post('/api/client/register') + .expect(400); +}); + +test('should require strategies field', () => { + const { request } = getSetup(); + return request + .post('/api/client/register') + .send({ + appName: 'demo', + instanceId: 'test', + // strategies: ['default'], + started: Date.now(), + interval: 10, + }) + .expect(400); +}); + + +test('should accept client metrics', () => { + const { request } = getSetup(); + return request + .post('/api/client/metrics') + .send({ + appName: 'demo', + instanceId: '1', + bucket: { + start: Date.now(), + stop: Date.now(), + toggles: {}, + }, + }) + .expect(202); }); diff --git a/test/unit/routes/mocks/fake-client-instance-store.js b/test/unit/routes/mocks/fake-client-instance-store.js index 954a2e2ab2..1b2ea2a50a 100644 --- a/test/unit/routes/mocks/fake-client-instance-store.js +++ b/test/unit/routes/mocks/fake-client-instance-store.js @@ -1,6 +1,5 @@ 'use strict'; -module.exports = { - reset: () => {}, +module.exports = () => ({ insert: () => Promise.resolve(), -}; +}); diff --git a/test/unit/routes/mocks/fake-client-strategy-store.js b/test/unit/routes/mocks/fake-client-strategy-store.js index 954a2e2ab2..1b2ea2a50a 100644 --- a/test/unit/routes/mocks/fake-client-strategy-store.js +++ b/test/unit/routes/mocks/fake-client-strategy-store.js @@ -1,6 +1,5 @@ 'use strict'; -module.exports = { - reset: () => {}, +module.exports = () => ({ insert: () => Promise.resolve(), -}; +}); diff --git a/test/unit/routes/mocks/fake-feature-toggle-store.js b/test/unit/routes/mocks/fake-feature-toggle-store.js index 7997284c06..d25aa78edc 100644 --- a/test/unit/routes/mocks/fake-feature-toggle-store.js +++ b/test/unit/routes/mocks/fake-feature-toggle-store.js @@ -1,11 +1,10 @@ 'use strict'; -const _features = []; -module.exports = { - getFeatures: () => Promise.resolve(_features), - addFeature: (feature) => _features.push(feature), - reset: () => { - _features.lengyh = 0; - }, +module.exports = () => { + const _features = []; + return { + getFeatures: () => Promise.resolve(_features), + addFeature: (feature) => _features.push(feature), + }; }; diff --git a/test/unit/routes/mocks/fake-metrics-store.js b/test/unit/routes/mocks/fake-metrics-store.js index 6f43ad12ed..7a986d86a5 100644 --- a/test/unit/routes/mocks/fake-metrics-store.js +++ b/test/unit/routes/mocks/fake-metrics-store.js @@ -1,7 +1,6 @@ 'use strict'; -module.exports = { - reset: () => {}, +module.exports = () => ({ getMetricsLastHour: () => Promise.resolve([]), insert: () => Promise.resolve(), -}; +}); diff --git a/test/unit/routes/mocks/fake-strategies-store.js b/test/unit/routes/mocks/fake-strategies-store.js index 4f5042ffa0..9a11dc3433 100644 --- a/test/unit/routes/mocks/fake-strategies-store.js +++ b/test/unit/routes/mocks/fake-strategies-store.js @@ -1,12 +1,13 @@ 'use strict'; -const _strategies = [{ name: 'default', parameters: {} }]; -module.exports = { - getStrategies: () => Promise.resolve(_strategies), - addStrategy: (strat) => _strategies.push(strat), - reset: () => { - _strategies.length = 0; - }, + +module.exports = () => { + const _strategies = [{ name: 'default', parameters: {} }]; + + return { + getStrategies: () => Promise.resolve(_strategies), + addStrategy: (strat) => _strategies.push(strat), + }; }; diff --git a/test/unit/routes/mocks/store.js b/test/unit/routes/mocks/store.js index 4f31e28f86..d88e012e7f 100644 --- a/test/unit/routes/mocks/store.js +++ b/test/unit/routes/mocks/store.js @@ -1,4 +1,4 @@ -const sinon = require('sinon'); +'use strict'; const clientMetricsStore = require('./fake-metrics-store'); const clientStrategyStore = require('./fake-client-strategy-store'); @@ -11,27 +11,18 @@ const strategyStore = require('./fake-strategies-store'); module.exports = { createStores: () => { const db = { - select: () => { - return { - from: () => Promise.resolve() - } - } - } - - clientMetricsStore.reset(); - clientStrategyStore.reset(); - clientInstanceStore.reset(); - featureToggleStore.reset(); - strategyStore.reset(); + select: () => ({ + from: () => Promise.resolve(), + }), + }; return { db, - clientMetricsStore, - clientStrategyStore, - clientInstanceStore, - featureToggleStore, - strategyStore, - } - - } -}; \ No newline at end of file + clientMetricsStore: clientMetricsStore(), + clientStrategyStore: clientStrategyStore(), + clientInstanceStore: clientInstanceStore(), + featureToggleStore: featureToggleStore(), + strategyStore: strategyStore(), + }; + }, +}; diff --git a/test/unit/routes/strategies.test.js b/test/unit/routes/strategies.test.js index 463ec338d4..92edc91202 100644 --- a/test/unit/routes/strategies.test.js +++ b/test/unit/routes/strategies.test.js @@ -1,35 +1,28 @@ 'use strict'; +const test = require('ava'); const store = require('./mocks/store'); - - const supertest = require('supertest'); -const assert = require('assert'); -const sinon = require('sinon'); +const logger = require('../../../lib/logger'); -let request; -let strategyStore; - -describe('Unit: The strategies api', () => { - beforeEach(done => { - const stores = store.createStores(); - const app = require('../../../app')({ - baseUriPath: '', - stores: stores, - }); - strategyStore = stores.strategyStore; - request = supertest(app); - done(); - }); - - it('should add version numbers for /stategies', (done) => { - request - .get('/api/strategies') - .expect('Content-Type', /json/) - .expect(200) - .end((err, res) => { - assert.equal(res.body.version, 1); - done(); - }); - }); +test.beforeEach(() => { + logger.setLevel('FATAL'); +}); + +test('should add version numbers for /stategies', t => { + const stores = store.createStores(); + const app = require('../../../app')({ + baseUriPath: '', + stores, + }); + + const request = supertest(app); + + return request + .get('/api/strategies') + .expect('Content-Type', /json/) + .expect(200) + .expect((res) => { + t.true(res.body.version === 1); + }); });