From 3b3ef23fd944858f2adfc37105e0193df828447b Mon Sep 17 00:00:00 2001 From: Ivar Date: Sat, 30 Apr 2016 10:47:17 +0200 Subject: [PATCH 01/15] gitignore: added Visual Stuido Code IDE ignores --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index 04b43fe3af..4797c840a2 100644 --- a/.gitignore +++ b/.gitignore @@ -32,3 +32,7 @@ unleash-server.tar.gz *.iml .vagrant/ + +# Visual Studio Code +jsconfig.json +typings \ No newline at end of file From 225db218d30d4fb706a0c8473a70df2dd1112519 Mon Sep 17 00:00:00 2001 From: ivaosthu Date: Thu, 28 Apr 2016 16:58:59 +0200 Subject: [PATCH 02/15] Move all routes to a routes folder --- app.js | 11 ++--------- lib/{ => db}/dbPool.js | 2 +- lib/{eventDb.js => db/event.js} | 0 lib/{featureDb.js => db/feature.js} | 8 ++++---- lib/{strategyDb.js => db/strategy.js} | 8 ++++---- lib/eventStore.js | 2 +- lib/{eventApi.js => routes/event.js} | 4 ++-- .../feature-archive.js} | 12 ++++++------ lib/{featureApi.js => routes/feature.js} | 18 +++++++++--------- lib/{routes.js => routes/health-check.js} | 4 ++-- lib/routes/index.js | 11 +++++++++++ lib/{strategyApi.js => routes/strategy.js} | 18 +++++++++--------- test/specHelper.js | 6 +++--- 13 files changed, 54 insertions(+), 50 deletions(-) rename lib/{ => db}/dbPool.js (97%) rename lib/{eventDb.js => db/event.js} (100%) rename lib/{featureDb.js => db/feature.js} (93%) rename lib/{strategyDb.js => db/strategy.js} (89%) rename lib/{eventApi.js => routes/event.js} (87%) rename lib/{featureArchiveApi.js => routes/feature-archive.js} (75%) rename lib/{featureApi.js => routes/feature.js} (88%) rename lib/{routes.js => routes/health-check.js} (85%) create mode 100644 lib/routes/index.js rename lib/{strategyApi.js => routes/strategy.js} (85%) diff --git a/app.js b/app.js index a67fc63655..435a82d4f4 100644 --- a/app.js +++ b/app.js @@ -4,10 +4,6 @@ var express = require('express'), log4js = require('log4js'), logger = require('./lib/logger'), routes = require('./lib/routes'), - eventApi = require('./lib/eventApi'), - featureApi = require('./lib/featureApi'), - featureArchiveApi = require('./lib/featureArchiveApi'), - strategyApi = require('./lib/strategyApi'), validator = require('express-validator'), app = express(), router = express.Router(), // eslint-disable-line @@ -45,11 +41,8 @@ app.use(bodyParser.json({ strict: false })); app.use(cookieParser()); -eventApi(router); -featureApi(router); -featureArchiveApi(router); -strategyApi(router); -routes(router); +routes.create(router); + app.use(baseUriPath, router); module.exports = app; diff --git a/lib/dbPool.js b/lib/db/dbPool.js similarity index 97% rename from lib/dbPool.js rename to lib/db/dbPool.js index 5c7cb0ff29..640238a928 100644 --- a/lib/dbPool.js +++ b/lib/db/dbPool.js @@ -1,4 +1,4 @@ -var logger = require('./logger'); +var logger = require('../logger'); var nconf = require('nconf'); var fs = require('fs'); var ini = require('ini'); diff --git a/lib/eventDb.js b/lib/db/event.js similarity index 100% rename from lib/eventDb.js rename to lib/db/event.js diff --git a/lib/featureDb.js b/lib/db/feature.js similarity index 93% rename from lib/featureDb.js rename to lib/db/feature.js index 28f51bd173..9a7d2dad14 100644 --- a/lib/featureDb.js +++ b/lib/db/feature.js @@ -1,8 +1,8 @@ -var eventStore = require('./eventStore'); -var eventType = require('./eventType'); -var logger = require('./logger'); +var eventStore = require('../eventStore'); +var eventType = require('../eventType'); +var logger = require('../logger'); var knex = require('./dbPool'); -var NotFoundError = require('./error/NotFoundError'); +var NotFoundError = require('../error/NotFoundError'); var FEATURE_COLUMNS = ['name', 'description', 'enabled', 'strategy_name', 'parameters']; eventStore.on(eventType.featureCreated, function (event) { diff --git a/lib/strategyDb.js b/lib/db/strategy.js similarity index 89% rename from lib/strategyDb.js rename to lib/db/strategy.js index 2972bdfae1..faebcfb36b 100644 --- a/lib/strategyDb.js +++ b/lib/db/strategy.js @@ -1,8 +1,8 @@ -var eventStore = require('./eventStore'); -var eventType = require('./eventType'); -var logger = require('./logger'); +var eventStore = require('../eventStore'); +var eventType = require('../eventType'); +var logger = require('../logger'); var knex = require('./dbPool'); -var NotFoundError = require('./error/NotFoundError'); +var NotFoundError = require('../error/NotFoundError'); var STRATEGY_COLUMNS = ['name', 'description', 'parameters_template']; eventStore.on(eventType.strategyCreated, function (event) { diff --git a/lib/eventStore.js b/lib/eventStore.js index 67802c3cfa..8e71fcd61b 100644 --- a/lib/eventStore.js +++ b/lib/eventStore.js @@ -1,5 +1,5 @@ var util = require('util'), - eventDb = require('./eventDb'), + eventDb = require('./db/event'), EventEmitter = require('events').EventEmitter; function EventStore() { diff --git a/lib/eventApi.js b/lib/routes/event.js similarity index 87% rename from lib/eventApi.js rename to lib/routes/event.js index 6c8e2b33e6..6461b1f58a 100644 --- a/lib/eventApi.js +++ b/lib/routes/event.js @@ -1,5 +1,5 @@ -var eventDb = require('./eventDb'); -var eventDiffer = require('./eventDiffer'); +var eventDb = require('../db/event'); +var eventDiffer = require('../eventDiffer'); module.exports = function (app) { app.get('/events', function (req, res) { diff --git a/lib/featureArchiveApi.js b/lib/routes/feature-archive.js similarity index 75% rename from lib/featureArchiveApi.js rename to lib/routes/feature-archive.js index 430b0c82a7..d9b260349f 100644 --- a/lib/featureArchiveApi.js +++ b/lib/routes/feature-archive.js @@ -1,9 +1,9 @@ -var logger = require('./logger'); -var eventStore = require('./eventStore'); -var eventType = require('./eventType'); -var featureDb = require('./featureDb'); -var ValidationError = require('./error/ValidationError'); -var validateRequest = require('./error/validateRequest'); +var logger = require('../logger'); +var eventStore = require('../eventStore'); +var eventType = require('../eventType'); +var featureDb = require('../db/feature'); +var ValidationError = require('../error/ValidationError'); +var validateRequest = require('../error/validateRequest'); module.exports = function (app) { app.get('/archive/features', function (req, res) { diff --git a/lib/featureApi.js b/lib/routes/feature.js similarity index 88% rename from lib/featureApi.js rename to lib/routes/feature.js index 5a4ba8a817..51ab2a8055 100644 --- a/lib/featureApi.js +++ b/lib/routes/feature.js @@ -1,13 +1,13 @@ var Promise = require("bluebird"); -var logger = require('./logger'); -var eventStore = require('./eventStore'); -var eventType = require('./eventType'); -var featureDb = require('./featureDb'); -var NameExistsError = require('./error/NameExistsError'); -var NotFoundError = require('./error/NotFoundError'); -var ValidationError = require('./error/ValidationError'); -var validateRequest = require('./error/validateRequest'); -var extractUser = require('./extractUser'); +var logger = require('../logger'); +var eventStore = require('../eventStore'); +var eventType = require('../eventType'); +var featureDb = require('../db/feature'); +var NameExistsError = require('../error/NameExistsError'); +var NotFoundError = require('../error/NotFoundError'); +var ValidationError = require('../error/ValidationError'); +var validateRequest = require('../error/validateRequest'); +var extractUser = require('../extractUser'); module.exports = function (app) { app.get('/features', function (req, res) { diff --git a/lib/routes.js b/lib/routes/health-check.js similarity index 85% rename from lib/routes.js rename to lib/routes/health-check.js index f354178c10..76b84afe1c 100644 --- a/lib/routes.js +++ b/lib/routes/health-check.js @@ -1,5 +1,5 @@ -var knex = require('./dbPool'); -var logger = require('./logger'); +var knex = require('../db/dbPool'); +var logger = require('../logger'); module.exports = function (app) { app.get('/health', function (req, res) { diff --git a/lib/routes/index.js b/lib/routes/index.js new file mode 100644 index 0000000000..0c25412d3d --- /dev/null +++ b/lib/routes/index.js @@ -0,0 +1,11 @@ +/** + * TODO: we should also inject config and + * services to the routes to ease testing. +**/ +exports.create = function (app) { + require('./event')(app); + require('./feature')(app); + require('./feature-archive')(app); + require('./strategy')(app); + require('./health-check')(app); +}; diff --git a/lib/strategyApi.js b/lib/routes/strategy.js similarity index 85% rename from lib/strategyApi.js rename to lib/routes/strategy.js index 2837f3ff89..20e635d897 100644 --- a/lib/strategyApi.js +++ b/lib/routes/strategy.js @@ -1,13 +1,13 @@ var Promise = require("bluebird"); -var eventStore = require('./eventStore'); -var eventType = require('./eventType'); -var strategyDb = require('./strategyDb'); -var logger = require('./logger'); -var NameExistsError = require('./error/NameExistsError'); -var ValidationError = require('./error/ValidationError'); -var NotFoundError = require('./error/NotFoundError'); -var validateRequest = require('./error/validateRequest'); -var extractUser = require('./extractUser'); +var eventStore = require('../eventStore'); +var eventType = require('../eventType'); +var strategyDb = require('../db/strategy'); +var logger = require('../logger'); +var NameExistsError = require('../error/NameExistsError'); +var ValidationError = require('../error/ValidationError'); +var NotFoundError = require('../error/NotFoundError'); +var validateRequest = require('../error/validateRequest'); +var extractUser = require('../extractUser'); module.exports = function (app) { app.get('/strategies', function (req, res) { diff --git a/test/specHelper.js b/test/specHelper.js index 3f8f7552ca..65db1d5882 100644 --- a/test/specHelper.js +++ b/test/specHelper.js @@ -4,9 +4,9 @@ process.env.NODE_ENV = 'test'; var Promise = require('bluebird'); var request = require('supertest'); var app = require('../app'); -var knex = require('../lib/dbPool'); -var featureDb = require('../lib/featureDb'); -var strategyDb = require('../lib/strategyDb'); +var knex = require('../lib/db/dbPool'); +var featureDb = require('../lib/db/feature'); +var strategyDb = require('../lib/db/strategy'); Promise.promisifyAll(request); request = request(app); From 9dc87d9860ed0ffa83694510ef51b1e443de0d0a Mon Sep 17 00:00:00 2001 From: ivaosthu Date: Thu, 28 Apr 2016 17:06:08 +0200 Subject: [PATCH 03/15] Add enngine details --- package.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/package.json b/package.json index af8e718853..46ea60bfd8 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,9 @@ "bugs": { "url": "https://github.com/finn-no/unleash/issues" }, + "engines" : { + "node" : ">=4.4.3" + }, "private": true, "scripts": { "db-migrate-and-start": "npm run db-migrate && npm run start", From 04ec1c3bff41da90587a20212152f33665d54a01 Mon Sep 17 00:00:00 2001 From: Ivar Date: Sat, 30 Apr 2016 22:11:16 +0200 Subject: [PATCH 04/15] ignored vscode files --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index f980b6b65a..d96e8607dd 100644 --- a/.gitignore +++ b/.gitignore @@ -35,4 +35,5 @@ unleash-server.tar.gz # Visual Studio Code jsconfig.json -typings \ No newline at end of file +typings +.vscode \ No newline at end of file From 683883702490fc428a8160bcecb2e1e195a0c0ba Mon Sep 17 00:00:00 2001 From: Ivar Date: Sat, 30 Apr 2016 22:31:07 +0200 Subject: [PATCH 05/15] upgrade express dependencies --- package.json | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index 46ea60bfd8..9368eb55de 100644 --- a/package.json +++ b/package.json @@ -15,8 +15,8 @@ "bugs": { "url": "https://github.com/finn-no/unleash/issues" }, - "engines" : { - "node" : ">=4.4.3" + "engines" : { + "node" : ">=4.4.3" }, "private": true, "scripts": { @@ -42,20 +42,20 @@ }, "dependencies": { "bluebird": "2.9.14", - "body-parser": "1.12.2", - "cookie-parser": "^1.3.3", + "body-parser": "1.15.0", + "cookie-parser": "^1.4.1", "db-migrate": "0.9.23", - "deep-diff": "^0.3.0", + "deep-diff": "^0.3.3", "errorhandler": "1.3.5", - "express": "4.12.3", - "express-validator": "2.9.0", - "ini": "1.3.3", + "express": "4.13.4", + "express-validator": "2.20.3", + "ini": "1.3.4", "jsx-loader": "0.12.2", "jsxhint": "0.13.2", "knex": "^0.11.0", "lodash": "^3.5.0", - "log4js": "0.6.22", - "moment": "^2.11.2", + "log4js": "0.6.35", + "moment": "^2.13.0", "nconf": "0.7.1", "pg": "^4.5.5", "react": "^0.13.1", From e93c73b33f2ee1def83cf35388a4df2ff1c364e3 Mon Sep 17 00:00:00 2001 From: Ivar Date: Sat, 30 Apr 2016 22:32:49 +0200 Subject: [PATCH 06/15] upgrade reqwest lib --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 9368eb55de..44d4061c3b 100644 --- a/package.json +++ b/package.json @@ -56,12 +56,12 @@ "lodash": "^3.5.0", "log4js": "0.6.35", "moment": "^2.13.0", - "nconf": "0.7.1", + "nconf": "0.8.4", "pg": "^4.5.5", "react": "^0.13.1", "react-router": "^0.13.2", "reflux": "^0.2.10", - "reqwest": "^1.1.4", + "reqwest": "^2.0.5", "webpack": "1.7.3", "webpack-dev-middleware": "^1.0.11" }, From c28093fc507dc0ac598b023813b7dc4737cc09c9 Mon Sep 17 00:00:00 2001 From: Ivar Date: Sat, 30 Apr 2016 22:38:38 +0200 Subject: [PATCH 07/15] upgraded dev-dependencies --- package.json | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index 44d4061c3b..85d626c711 100644 --- a/package.json +++ b/package.json @@ -66,21 +66,21 @@ "webpack-dev-middleware": "^1.0.11" }, "devDependencies": { - "chai": "2.1.2", - "coveralls": "^2.11.2", - "eslint": "^2.7.0", + "chai": "3.5.0", + "coveralls": "^2.11.9", + "eslint": "^2.9.0", "eslint-config-spt": "^2.0.0", "eslint-plugin-react": "^4.3.0", - "istanbul": "^0.3.5", + "istanbul": "^0.4.3", "jest-cli": "0.5.4", - "mocha": "^2.1.0", - "mocha-lcov-reporter": "0.0.2", - "nsp": "^1.0.0", + "mocha": "^2.4.5", + "mocha-lcov-reporter": "1.2.0", + "nsp": "^2.3.2", "pre-commit": "^1.0.2", "react-tools": "^0.13.1", - "supertest": "^0.15.0", - "supervisor": "^0.6.0", - "xmlbuilder": "^2.5.1" + "supertest": "^1.2.0", + "supervisor": "^0.10.0", + "xmlbuilder": "^8.2.2" }, "jest": { "scriptPreprocessor": "/jest-preprocessor.js", From 3bed10a9c521af63b58083f6ddd0078b3e9c11a0 Mon Sep 17 00:00:00 2001 From: Ivar Date: Sat, 30 Apr 2016 23:40:51 +0200 Subject: [PATCH 08/15] Upgrade webpack --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 85d626c711..ff15b2371c 100644 --- a/package.json +++ b/package.json @@ -62,8 +62,8 @@ "react-router": "^0.13.2", "reflux": "^0.2.10", "reqwest": "^2.0.5", - "webpack": "1.7.3", - "webpack-dev-middleware": "^1.0.11" + "webpack": "^1.13.0", + "webpack-dev-middleware": "^1.6.1" }, "devDependencies": { "chai": "3.5.0", From d8ef2beae5eb0e978c8dfe03ed8e0c0c65169550 Mon Sep 17 00:00:00 2001 From: Ivar Date: Sat, 30 Apr 2016 23:41:09 +0200 Subject: [PATCH 09/15] formatting --- app.js | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/app.js b/app.js index 435a82d4f4..05ee760d8e 100644 --- a/app.js +++ b/app.js @@ -1,13 +1,13 @@ -var express = require('express'), - bodyParser = require('body-parser'), - cookieParser = require('cookie-parser'), - log4js = require('log4js'), - logger = require('./lib/logger'), - routes = require('./lib/routes'), - validator = require('express-validator'), - app = express(), - router = express.Router(), // eslint-disable-line - baseUriPath = process.env.BASE_URI_PATH || ''; +var express = require('express'); +var bodyParser = require('body-parser'); +var cookieParser = require('cookie-parser'); +var log4js = require('log4js'); +var logger = require('./lib/logger'); +var routes = require('./lib/routes'); +var validator = require('express-validator'); +var app = express(); +var router = express.Router(); // eslint-disable-line +var baseUriPath = process.env.BASE_URI_PATH || ''; if (app.get('env') === 'development') { app.use(require('errorhandler')()); From 86df52060c35f5fb7ea065548ab1391f65a43167 Mon Sep 17 00:00:00 2001 From: Ivar Date: Sun, 1 May 2016 15:43:25 +0200 Subject: [PATCH 10/15] Fixed placeholder for favicon.ico --- app.js | 3 + package.json | 195 +++++++++++++++++++++++---------------------- public/favicon.ico | Bin 0 -> 34494 bytes 3 files changed, 102 insertions(+), 96 deletions(-) create mode 100644 public/favicon.ico diff --git a/app.js b/app.js index 05ee760d8e..3f236aeed8 100644 --- a/app.js +++ b/app.js @@ -1,4 +1,5 @@ var express = require('express'); +var favicon = require('serve-favicon'); var bodyParser = require('body-parser'); var cookieParser = require('cookie-parser'); var log4js = require('log4js'); @@ -24,6 +25,8 @@ if (app.get('env') === 'development') { app.use(baseUriPath, webpackDevMiddleware(compiler, config)); } +app.use(favicon(__dirname + '/public/favicon.ico')); + app.use(validator([])); app.set('trust proxy'); diff --git a/package.json b/package.json index ff15b2371c..c61aae42cf 100644 --- a/package.json +++ b/package.json @@ -1,99 +1,102 @@ { - "name": "unleash-server", - "description": "unleash your features", - "version": "0.1.0", - "keywords": [ - "unleash", - "feature toggle", - "feature", - "toggle" - ], - "repository": { - "type": "git", - "url": "ssh://git@github.com:finn-no/unleash.git" - }, - "bugs": { - "url": "https://github.com/finn-no/unleash/issues" - }, - "engines" : { - "node" : ">=4.4.3" - }, - "private": true, - "scripts": { - "db-migrate-and-start": "npm run db-migrate && npm run start", - "start": "NODE_ENV=production node server.js", - "build": "./node_modules/.bin/webpack -p", - "dev": "NODE_ENV=development supervisor --ignore ./node_modules/,./public/js server.js", - "start-pg": "pg_virtualenv npm run start-pg-chain", - "start-pg-chain": "export DATABASE_URL=postgres://$PGUSER:$PGPASSWORD@localhost:$PGPORT/postgres ; db-migrate up && npm run dev", - "test": "export PORT=4243 ; jest && npm run lint && mocha test test/*.js && npm run coverage", - "docker-test": "export PORT=4243 ; ./scripts/docker-postgres.sh", - "pg-virtualenv-test": "pg_virtualenv npm run pg-virtualenv-chain", - "pg-virtualenv-chain": "export TEST_DATABASE_URL=postgres://$PGUSER:$PGPASSWORD@localhost:$PGPORT/postgres ; npm run db-migrate-testdb && npm test", - "db-migrate": "node_modules/.bin/db-migrate up", - "db-migrate-testdb": "DATABASE_URL=$TEST_DATABASE_URL ./node_modules/.bin/db-migrate up", - "tdd": "mocha --watch test test/*", - "test-bamboo-ci": "mocha test test/*", - "coverage": "istanbul cover ./node_modules/mocha/bin/_mocha --report lcovonly -- -R spec", - "coverage-report": "cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js && rm -rf ./coverage", - "postinstall": "npm run build", - "jest": "jest", - "lint": "eslint . --ignore-path .gitignore" - }, - "dependencies": { - "bluebird": "2.9.14", - "body-parser": "1.15.0", - "cookie-parser": "^1.4.1", - "db-migrate": "0.9.23", - "deep-diff": "^0.3.3", - "errorhandler": "1.3.5", - "express": "4.13.4", - "express-validator": "2.20.3", - "ini": "1.3.4", - "jsx-loader": "0.12.2", - "jsxhint": "0.13.2", - "knex": "^0.11.0", - "lodash": "^3.5.0", - "log4js": "0.6.35", - "moment": "^2.13.0", - "nconf": "0.8.4", - "pg": "^4.5.5", - "react": "^0.13.1", - "react-router": "^0.13.2", - "reflux": "^0.2.10", - "reqwest": "^2.0.5", - "webpack": "^1.13.0", - "webpack-dev-middleware": "^1.6.1" - }, - "devDependencies": { - "chai": "3.5.0", - "coveralls": "^2.11.9", - "eslint": "^2.9.0", - "eslint-config-spt": "^2.0.0", - "eslint-plugin-react": "^4.3.0", - "istanbul": "^0.4.3", - "jest-cli": "0.5.4", - "mocha": "^2.4.5", - "mocha-lcov-reporter": "1.2.0", - "nsp": "^2.3.2", - "pre-commit": "^1.0.2", - "react-tools": "^0.13.1", - "supertest": "^1.2.0", - "supervisor": "^0.10.0", - "xmlbuilder": "^8.2.2" - }, - "jest": { - "scriptPreprocessor": "/jest-preprocessor.js", - "unmockedModulePathPatterns": [ - "/node_modules/react", - "/node_modules/reflux" - ], - "moduleFileExtensions": [ - "jsx", - "js" - ] - }, - "pre-commit": [ - "lint" + "name": "unleash-server", + "description": "unleash your features", + "version": "0.1.0", + "keywords": [ + "unleash", + "feature toggle", + "feature", + "toggle" + ], + "repository": { + "type": "git", + "url": "ssh://git@github.com:finn-no/unleash.git" + }, + "bugs": { + "url": "https://github.com/finn-no/unleash/issues" + }, + "engines": { + "node": ">=4.4.3" + }, + "private": true, + "scripts": { + "db-migrate-and-start": "npm run db-migrate && npm run start", + "start": "NODE_ENV=production node server.js", + "build": "./node_modules/.bin/webpack -p", + "dev": "NODE_ENV=development supervisor --ignore ./node_modules/,./public/js server.js", + "start-pg": "pg_virtualenv npm run start-pg-chain", + "start-pg-chain": "export DATABASE_URL=postgres://$PGUSER:$PGPASSWORD@localhost:$PGPORT/postgres ; db-migrate up && npm run dev", + "test": "export PORT=4243 ; jest && npm run lint && mocha test test/*.js && npm run coverage", + "docker-test": "export PORT=4243 ; ./scripts/docker-postgres.sh", + "pg-virtualenv-test": "pg_virtualenv npm run pg-virtualenv-chain", + "pg-virtualenv-chain": "export TEST_DATABASE_URL=postgres://$PGUSER:$PGPASSWORD@localhost:$PGPORT/postgres ; npm run db-migrate-testdb && npm test", + "db-migrate": "node_modules/.bin/db-migrate up", + "db-migrate-testdb": "DATABASE_URL=$TEST_DATABASE_URL ./node_modules/.bin/db-migrate up", + "tdd": "mocha --watch test test/*", + "test-bamboo-ci": "mocha test test/*", + "coverage": "istanbul cover ./node_modules/mocha/bin/_mocha --report lcovonly -- -R spec", + "coverage-report": "cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js && rm -rf ./coverage", + "postinstall": "npm run build", + "jest": "jest", + "lint": "eslint . --ignore-path .gitignore" + }, + "dependencies": { + "bluebird": "2.9.14", + "body-parser": "1.15.0", + "cookie-parser": "^1.4.1", + "db-migrate": "0.9.23", + "deep-diff": "^0.3.3", + "errorhandler": "1.3.5", + "express": "4.13.4", + "express-validator": "2.20.3", + "ini": "1.3.4", + "install": "^0.6.1", + "jsx-loader": "0.12.2", + "jsxhint": "0.13.2", + "knex": "^0.10.0", + "lodash": "^3.5.0", + "log4js": "0.6.35", + "moment": "^2.13.0", + "nconf": "0.8.4", + "npm": "^3.8.8", + "pg": "^4.5.5", + "react": "^0.13.1", + "react-router": "^0.13.2", + "reflux": "^0.2.10", + "reqwest": "^2.0.5", + "serve-favicon": "^2.3.0", + "webpack": "^1.13.0", + "webpack-dev-middleware": "^1.6.1" + }, + "devDependencies": { + "chai": "3.5.0", + "coveralls": "^2.11.9", + "eslint": "^2.9.0", + "eslint-config-spt": "^2.0.0", + "eslint-plugin-react": "^4.3.0", + "istanbul": "^0.4.3", + "jest-cli": "0.5.4", + "mocha": "^2.4.5", + "mocha-lcov-reporter": "1.2.0", + "nsp": "^2.3.2", + "pre-commit": "^1.0.2", + "react-tools": "^0.13.1", + "supertest": "^1.2.0", + "supervisor": "^0.10.0", + "xmlbuilder": "^8.2.2" + }, + "jest": { + "scriptPreprocessor": "/jest-preprocessor.js", + "unmockedModulePathPatterns": [ + "/node_modules/react", + "/node_modules/reflux" + ], + "moduleFileExtensions": [ + "jsx", + "js" ] + }, + "pre-commit": [ + "lint" + ] } diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..a2bc43c660a81140395e12f5df4370fb45408120 GIT binary patch literal 34494 zcmeHQTWl3Y7#<1~K_bLxL<87V&|;$UVvGj05`!^bAH2l)f)us*fCe#Wz)Mnz7+)xe z0UiJ)3gRsh6%zzSDG4nt_i_^fk#ZAg3zX8`+41{#&m8vb**&)9?CIIF|DSwkW@l&q z`Tv=3XJ=>UoFhap(N_!}ED)B6%05CoBZL?-#5tbTUx>9xD=Be~mm}Y}tArRmI&nNw zh||M`C@*)8%f<@v$%8_aK?kxzqmzz62VkP*5V9fFgw{zTicG><~DW_0YYRvKn!?u7oJ{Hdj#Bg#uQF}Mw~$^q{@ zDe#yc<}k?$;vmh#N`P`8IS->U9tkSX>3nT72V%j2+34q<5~{mR&3-6lF5sRQWQxl} zKiGDg+n(<9+(6GosEl1VJ~Gvj>6~nsW7n^Bb~UsMbN$h6|LqHM(*GS3gz|$tw6f>w zujqw2I!*mMKQH%QA9i6XAFy7k)BSums>kT!UB33U9a@2|Cn)r*UmkSYo^)t^T@AZi zzq#Z|rOfkG{B8Q^YP~u?l_d%CTc^AIH)h_ZRL2=A_7e2a{4;0u8}lB(v+}=GV93dK9{p7*%cOc&0e86T*7aZJ{V&t~pVrH1 z@%}o`V}pH&bn5@_fbI&_9rz5x=eTW{1EF&uf*5-*~N*Sw#|<1$~v;M-n|x*t+;Ay`4jc1jy1(uhjp&8o^+E~ zf7RAz%VxKpQ0;H2t97hr``vBsj&u75UpE%>$M@Yq3V$xN?x$-kl<_AQ?QgUM7EHm^mLKjzX`wi9igFLlb2&9IN;0PvLCZXHK@c8^k_qMsNZFYw^_nDp9II}mz^#{HFL-qt=BhLK{(8i=m!0m23gW||{b)pP{tcza% z;WfqlTT|pd;XYvwFb9|e%z=F80464SFH!cxpt(`cr57ct)}fw$;>SL0xi1mE4}(r&SKT2PF4tQG!RPlNj6v%mL;AbAUO(9AFMG2bcrQ0p~+8(1}+%aRrEv>o1 zs1|wrE4>HH_MPl7s_txZ@39O!PHmj@AHIjN7bZxjQFo8M|5De_{&W8`|M~h4d(3m| z=kbrne|`U<`+m^9DvWf#|K-8`f5xq+V%`6HNP63*CR?{kxj*eJH)&xgLJ^iHrZn z%)5^$X`W8>_1_5T@0MuKWx@Bqx$ybD=y$!weiA;9(%Vl9+W*P{(%Q1p{as^v)}t-C zNhwJG@qJT#Kfe**$vX=FwETgH&H1GBh#;+C_-{6Pd lqJ5y(KL#e;7@7#jB*Ga^*voXne$Ed-h#T!NtzmMM@E-=Q5N7}Y literal 0 HcmV?d00001 From dd66921a97e14b844d6170725367b3ebe56066dc Mon Sep 17 00:00:00 2001 From: Ivar Date: Sun, 1 May 2016 16:25:44 +0200 Subject: [PATCH 11/15] Fixed failing jest-tests --- package.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index c61aae42cf..d37ac33519 100644 --- a/package.json +++ b/package.json @@ -75,7 +75,7 @@ "eslint-config-spt": "^2.0.0", "eslint-plugin-react": "^4.3.0", "istanbul": "^0.4.3", - "jest-cli": "0.5.4", + "jest-cli": "0.5.8", "mocha": "^2.4.5", "mocha-lcov-reporter": "1.2.0", "nsp": "^2.3.2", @@ -87,6 +87,9 @@ }, "jest": { "scriptPreprocessor": "/jest-preprocessor.js", + "modulePathIgnorePatterns": [ + "/node_modules/npm" + ], "unmockedModulePathPatterns": [ "/node_modules/react", "/node_modules/reflux" From c1987a76fc38adfd8bf7f870185e4b4139f8da59 Mon Sep 17 00:00:00 2001 From: Ivar Date: Sun, 1 May 2016 16:28:30 +0200 Subject: [PATCH 12/15] Move all custom-scripts to /scripts folder --- README.md | 2 +- migrations/20141020151056-initial-schema.js | 2 +- migrations/20141110144153-add-description-to-features.js | 2 +- .../20141117200435-add-parameters-template-to-strategies.js | 2 +- migrations/20141117202209-insert-default-strategy.js | 2 +- migrations/20141118071458-default-strategy-event.js | 2 +- migrations/20141215210141-005-archived-flag-to-features.js | 2 +- migrations/20150210152531-006-rename-eventtype.js | 2 +- package.json | 2 +- jest-preprocessor.js => scripts/jest-preprocessor.js | 0 lib/migrationRunner.js => scripts/migration-runner.js | 0 11 files changed, 9 insertions(+), 9 deletions(-) rename jest-preprocessor.js => scripts/jest-preprocessor.js (100%) rename lib/migrationRunner.js => scripts/migration-runner.js (100%) diff --git a/README.md b/README.md index 66d60576ec..aa215a4335 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,6 @@ npm run docker-test 1. Create `migrations/sql/NNN-your-migration-name.up.sql` with your change in SQL. 2. Create `migrations/sql/NNN-your-migration-name.down.sql` with the rollback of your change in SQL. -3. Run `db-migrate create your-migration-name` and edit the generated file to have this line: `module.exports = require('../lib/migrationRunner').create('NNN-your-migration-name');` +3. Run `db-migrate create your-migration-name` and edit the generated file to have this line: `module.exports = require('../scripts/migration-runner').create('NNN-your-migration-name');` 4. Run `db-migrate up`. 5. Generate LB artifact using `scripts/generate-liquibase-artifact` (TODO: make this internal) diff --git a/migrations/20141020151056-initial-schema.js b/migrations/20141020151056-initial-schema.js index b1d5b3f5f0..0a41df16f3 100644 --- a/migrations/20141020151056-initial-schema.js +++ b/migrations/20141020151056-initial-schema.js @@ -1 +1 @@ -module.exports = require('../lib/migrationRunner').create('001-initial-schema'); +module.exports = require('../scripts/migration-runner').create('001-initial-schema'); diff --git a/migrations/20141110144153-add-description-to-features.js b/migrations/20141110144153-add-description-to-features.js index fd90440779..248e5aa474 100644 --- a/migrations/20141110144153-add-description-to-features.js +++ b/migrations/20141110144153-add-description-to-features.js @@ -1 +1 @@ -module.exports = require('../lib/migrationRunner').create('002-add-description-to-features'); +module.exports = require('../scripts/migration-runner').create('002-add-description-to-features'); diff --git a/migrations/20141117200435-add-parameters-template-to-strategies.js b/migrations/20141117200435-add-parameters-template-to-strategies.js index e8068b7a53..0c6ef1b1a2 100644 --- a/migrations/20141117200435-add-parameters-template-to-strategies.js +++ b/migrations/20141117200435-add-parameters-template-to-strategies.js @@ -1,2 +1,2 @@ -module.exports = require('../lib/migrationRunner').create('003-add-parameters-template-to-strategies'); +module.exports = require('../scripts/migration-runner').create('003-add-parameters-template-to-strategies'); diff --git a/migrations/20141117202209-insert-default-strategy.js b/migrations/20141117202209-insert-default-strategy.js index 2023e55488..1bc6251635 100644 --- a/migrations/20141117202209-insert-default-strategy.js +++ b/migrations/20141117202209-insert-default-strategy.js @@ -1 +1 @@ -module.exports = require('../lib/migrationRunner').create('004-insert-default-strategy'); +module.exports = require('../scripts/migration-runner').create('004-insert-default-strategy'); diff --git a/migrations/20141118071458-default-strategy-event.js b/migrations/20141118071458-default-strategy-event.js index 8157598e8c..488b3ac594 100644 --- a/migrations/20141118071458-default-strategy-event.js +++ b/migrations/20141118071458-default-strategy-event.js @@ -1 +1 @@ -module.exports = require('../lib/migrationRunner').create('004-insert-default-strategy-event'); +module.exports = require('../scripts/migration-runner').create('004-insert-default-strategy-event'); diff --git a/migrations/20141215210141-005-archived-flag-to-features.js b/migrations/20141215210141-005-archived-flag-to-features.js index 12a3995472..0bd29e3271 100644 --- a/migrations/20141215210141-005-archived-flag-to-features.js +++ b/migrations/20141215210141-005-archived-flag-to-features.js @@ -1 +1 @@ -module.exports = require('../lib/migrationRunner').create('005-archived-flag-to-features'); +module.exports = require('../scripts/migration-runner').create('005-archived-flag-to-features'); diff --git a/migrations/20150210152531-006-rename-eventtype.js b/migrations/20150210152531-006-rename-eventtype.js index d184ba32f7..0de099bdbd 100644 --- a/migrations/20150210152531-006-rename-eventtype.js +++ b/migrations/20150210152531-006-rename-eventtype.js @@ -1 +1 @@ -module.exports = require('../lib/migrationRunner').create('006-rename-eventtype'); +module.exports = require('../scripts/migration-runner').create('006-rename-eventtype'); diff --git a/package.json b/package.json index d37ac33519..de9bc6abe4 100644 --- a/package.json +++ b/package.json @@ -86,7 +86,7 @@ "xmlbuilder": "^8.2.2" }, "jest": { - "scriptPreprocessor": "/jest-preprocessor.js", + "scriptPreprocessor": "/scripts/jest-preprocessor.js", "modulePathIgnorePatterns": [ "/node_modules/npm" ], diff --git a/jest-preprocessor.js b/scripts/jest-preprocessor.js similarity index 100% rename from jest-preprocessor.js rename to scripts/jest-preprocessor.js diff --git a/lib/migrationRunner.js b/scripts/migration-runner.js similarity index 100% rename from lib/migrationRunner.js rename to scripts/migration-runner.js From b85d9eb6d65604302d53ac89012d203991074a39 Mon Sep 17 00:00:00 2001 From: Ivar Date: Sun, 1 May 2016 18:20:10 +0200 Subject: [PATCH 13/15] Start injecting config to app. --- app.js | 54 ++++++++++++++++++---------------------------- server.js | 23 +++++++++++++++++++- test/specHelper.js | 10 ++++----- 3 files changed, 48 insertions(+), 39 deletions(-) diff --git a/app.js b/app.js index 3f236aeed8..d6cb006f80 100644 --- a/app.js +++ b/app.js @@ -2,50 +2,38 @@ var express = require('express'); var favicon = require('serve-favicon'); var bodyParser = require('body-parser'); var cookieParser = require('cookie-parser'); +var validator = require('express-validator'); var log4js = require('log4js'); var logger = require('./lib/logger'); var routes = require('./lib/routes'); -var validator = require('express-validator'); -var app = express(); -var router = express.Router(); // eslint-disable-line -var baseUriPath = process.env.BASE_URI_PATH || ''; -if (app.get('env') === 'development') { - app.use(require('errorhandler')()); +module.exports = function(config) { + var app = express(); + var router = express.Router(); // eslint-disable-line + var baseUriPath = config.baseUriPath || ''; - var webpack = require('webpack'), - webpackDevMiddleware = require('webpack-dev-middleware'), - webpackConfig = require('./webpack.config'), - compiler = webpack(webpackConfig), - config = { - publicPath: '/js', - noInfo: true - }; + app.use(favicon(__dirname + '/public/favicon.ico')); - app.use(baseUriPath, webpackDevMiddleware(compiler, config)); -} + app.use(validator([])); -app.use(favicon(__dirname + '/public/favicon.ico')); + app.set('trust proxy'); + app.locals.baseUriPath = baseUriPath; -app.use(validator([])); + app.use(log4js.connectLogger(logger, { + format: ':remote-addr :status :method :url :response-timems', + level: 'auto' // 3XX=WARN, 4xx/5xx=ERROR + })); -app.set('trust proxy'); -app.locals.baseUriPath = baseUriPath; + app.set('port', config.port); -app.use(log4js.connectLogger(logger, { - format: ':remote-addr :status :method :url :response-timems', - level: 'auto' // 3XX=WARN, 4xx/5xx=ERROR -})); + app.use(baseUriPath, express.static(__dirname + '/public')); + app.use(bodyParser.json({ strict: false })); -app.set('port', process.env.HTTP_PORT || process.env.PORT || 4242); + app.use(cookieParser()); -app.use(baseUriPath, express.static(__dirname + '/public')); -app.use(bodyParser.json({ strict: false })); + routes.create(router); -app.use(cookieParser()); + app.use(baseUriPath, router); -routes.create(router); - -app.use(baseUriPath, router); - -module.exports = app; + return app; +}; diff --git a/server.js b/server.js index 238ac698f7..8590411f1b 100644 --- a/server.js +++ b/server.js @@ -1,10 +1,31 @@ -var app = require('./app'); var logger = require('./lib/logger'); +var config = { + baseUriPath: process.env.BASE_URI_PATH || '', + port: process.env.HTTP_PORT || process.env.PORT || 4242 +}; + +var app = require('./app')(config); + var server = app.listen(app.get('port'), function() { logger.info('unleash started on ' + app.get('port')); }); +if (app.get('env') === 'development') { + app.use(require('errorhandler')()); + + var webpack = require('webpack'); + var webpackDevMiddleware = require('webpack-dev-middleware'); + var webpackConfig = require('./webpack.config'); + var compiler = webpack(webpackConfig); + + app.use(config.baseUriPath, webpackDevMiddleware(compiler, { + publicPath: '/js', + noInfo: true + })); +} + + process.on('uncaughtException', function(err) { logger.error('Uncaught Exception:', err.message); logger.error(err.stack); diff --git a/test/specHelper.js b/test/specHelper.js index 65db1d5882..02a6563481 100644 --- a/test/specHelper.js +++ b/test/specHelper.js @@ -1,11 +1,11 @@ 'use strict'; process.env.NODE_ENV = 'test'; -var Promise = require('bluebird'); -var request = require('supertest'); -var app = require('../app'); -var knex = require('../lib/db/dbPool'); -var featureDb = require('../lib/db/feature'); +var Promise = require('bluebird'); +var request = require('supertest'); +var app = require('../app')({ baseUriPath: '' }); +var knex = require('../lib/db/dbPool'); +var featureDb = require('../lib/db/feature'); var strategyDb = require('../lib/db/strategy'); Promise.promisifyAll(request); From 2d8fa7ee6b1d64dfb3b44cf9a783676efad0e10b Mon Sep 17 00:00:00 2001 From: Ivar Date: Sun, 1 May 2016 22:53:09 +0200 Subject: [PATCH 14/15] Statefull modules should be injected from top --- app.js | 3 +- lib/databaseConfig.js | 29 +++++ lib/db/dbPool.js | 51 +-------- lib/db/event.js | 64 ++++++----- lib/db/feature.js | 208 +++++++++++++++++----------------- lib/db/strategy.js | 110 +++++++++--------- lib/eventStore.js | 14 +-- lib/routes/event.js | 5 +- lib/routes/feature-archive.js | 7 +- lib/routes/feature.js | 7 +- lib/routes/health-check.js | 5 +- lib/routes/index.js | 12 +- lib/routes/strategy.js | 7 +- server.js | 17 ++- test/databaseConfig.js | 11 ++ test/featureApiSpec.js | 6 + test/specHelper.js | 20 +++- 17 files changed, 305 insertions(+), 271 deletions(-) create mode 100644 lib/databaseConfig.js create mode 100644 test/databaseConfig.js diff --git a/app.js b/app.js index d6cb006f80..8f643b3b34 100644 --- a/app.js +++ b/app.js @@ -31,7 +31,8 @@ module.exports = function(config) { app.use(cookieParser()); - routes.create(router); + // Setup API routes + routes.create(router, config); app.use(baseUriPath, router); diff --git a/lib/databaseConfig.js b/lib/databaseConfig.js new file mode 100644 index 0000000000..70cb78e3c7 --- /dev/null +++ b/lib/databaseConfig.js @@ -0,0 +1,29 @@ +var nconf = require('nconf'); +var fs = require('fs'); +var ini = require('ini'); +var logger = require('./logger'); + +function getDatabaseIniUrl() { + // Finn specific way of delivering env variables + var databaseini = nconf.argv().get('databaseini'); + var config = ini.parse(fs.readFileSync(databaseini, 'utf-8')); + + logger.info('unleash started with databaseini: ' + databaseini); + + return config.DATABASE_URL; +} + +function getDatabaseUrl() { + if (process.env.DATABASE_URL) { + logger.info('unleash started with DATABASE_URL'); + return process.env.DATABASE_URL; + } else if (nconf.argv().get('databaseini') !== undefined) { + return getDatabaseIniUrl(); + } + + throw new Error('please set DATABASE_URL or pass --databaseini'); +} + +module.exports = { + getDatabaseUrl: getDatabaseUrl +}; diff --git a/lib/db/dbPool.js b/lib/db/dbPool.js index 640238a928..33a863e674 100644 --- a/lib/db/dbPool.js +++ b/lib/db/dbPool.js @@ -1,52 +1,9 @@ -var logger = require('../logger'); -var nconf = require('nconf'); -var fs = require('fs'); -var ini = require('ini'); var knex = require('knex'); -function isTestEnv() { - return process.env.NODE_ENV === 'test'; -} - -function getDatabaseIniUrl() { - // Finn specific way of delivering env variables - var databaseini = nconf.argv().get('databaseini'); - var config = ini.parse(fs.readFileSync(databaseini, 'utf-8')); - - logger.info('unleash started with databaseini: ' + databaseini); - - return config.DATABASE_URL; -} - -function getTestDatabaseUrl() { - if (process.env.TEST_DATABASE_URL) { - logger.info('unleash started with TEST_DATABASE_URL'); - return process.env.TEST_DATABASE_URL; - } else { - throw new Error('please set TEST_DATABASE_URL'); - } -} - -function getDatabaseUrl() { - if (process.env.DATABASE_URL) { - logger.info('unleash started with DATABASE_URL'); - return process.env.DATABASE_URL; - } else if (nconf.argv().get('databaseini') !== undefined) { - return getDatabaseIniUrl(); - } - - throw new Error('please set DATABASE_URL or pass --databaseini'); -} - -function createDbPool() { +module.exports = function(databaseConnection) { return knex({ client: 'pg', - connection: isTestEnv() ? getTestDatabaseUrl() : getDatabaseUrl(), - pool: { - min: 2, - max: 20 - } + connection: databaseConnection, + pool: { min: 2, max: 20 } }); -} - -module.exports = createDbPool(); +}; diff --git a/lib/db/event.js b/lib/db/event.js index 5dea161375..8d4d1f24f5 100644 --- a/lib/db/event.js +++ b/lib/db/event.js @@ -1,43 +1,45 @@ -var knex = require('./dbPool'); var EVENT_COLUMNS = ['id', 'type', 'created_by', 'created_at', 'data']; -function storeEvent(event) { - return knex('events').insert({ - type: event.type, - created_by: event.createdBy, // eslint-disable-line - data: event.data - }); -} +module.exports = function(db) { + function storeEvent(event) { + return db('events').insert({ + type: event.type, + created_by: event.createdBy, // eslint-disable-line + data: event.data + }); + } -function getEvents() { - return knex + function getEvents() { + return db + .select(EVENT_COLUMNS) + .from('events') + .orderBy('created_at', 'desc') + .map(rowToEvent); + } + + function getEventsFilterByName(name) { + return db .select(EVENT_COLUMNS) .from('events') + .whereRaw("data ->> 'name' = ?", [name]) .orderBy('created_at', 'desc') .map(rowToEvent); -} + } -function getEventsFilterByName(name) { - return knex - .select(EVENT_COLUMNS) - .from('events') - .whereRaw("data ->> 'name' = ?", [name]) - .orderBy('created_at', 'desc') - .map(rowToEvent); -} + function rowToEvent(row) { + return { + id: row.id, + type: row.type, + createdBy: row.created_by, + createdAt: row.created_at, + data: row.data + }; + } -function rowToEvent(row) { return { - id: row.id, - type: row.type, - createdBy: row.created_by, - createdAt: row.created_at, - data: row.data + store: storeEvent, + getEvents: getEvents, + getEventsFilterByName: getEventsFilterByName }; -} - -module.exports = { - store: storeEvent, - getEvents: getEvents, - getEventsFilterByName: getEventsFilterByName }; + diff --git a/lib/db/feature.js b/lib/db/feature.js index 9a7d2dad14..fe54a553c9 100644 --- a/lib/db/feature.js +++ b/lib/db/feature.js @@ -1,118 +1,118 @@ -var eventStore = require('../eventStore'); var eventType = require('../eventType'); var logger = require('../logger'); -var knex = require('./dbPool'); var NotFoundError = require('../error/NotFoundError'); var FEATURE_COLUMNS = ['name', 'description', 'enabled', 'strategy_name', 'parameters']; -eventStore.on(eventType.featureCreated, function (event) { - return createFeature(event.data); -}); +module.exports = function(db, eventStore) { + eventStore.on(eventType.featureCreated, function (event) { + return createFeature(event.data); + }); -eventStore.on(eventType.featureUpdated, function (event) { - return updateFeature(event.data); -}); + eventStore.on(eventType.featureUpdated, function (event) { + return updateFeature(event.data); + }); -eventStore.on(eventType.featureArchived, function (event) { - return archiveFeature(event.data); -}); + eventStore.on(eventType.featureArchived, function (event) { + return archiveFeature(event.data); + }); -eventStore.on(eventType.featureRevived, function (event) { - return reviveFeature(event.data); -}); + eventStore.on(eventType.featureRevived, function (event) { + return reviveFeature(event.data); + }); -function getFeatures() { - return knex - .select(FEATURE_COLUMNS) - .from('features') - .where({ archived: 0 }) - .orderBy('name', 'asc') - .map(rowToFeature); -} - -function getFeature(name) { - return knex - .first(FEATURE_COLUMNS) - .from('features') - .where({ name: name }) - .then(rowToFeature); -} - -function getArchivedFeatures() { - return knex - .select(FEATURE_COLUMNS) - .from('features') - .where({ archived: 1 }) - .orderBy('name', 'asc') - .map(rowToFeature); -} - - -function rowToFeature(row) { - if (!row) { - throw new NotFoundError('No feature toggle found'); + function getFeatures() { + return db + .select(FEATURE_COLUMNS) + .from('features') + .where({ archived: 0 }) + .orderBy('name', 'asc') + .map(rowToFeature); } + function getFeature(name) { + return db + .first(FEATURE_COLUMNS) + .from('features') + .where({ name: name }) + .then(rowToFeature); + } + + function getArchivedFeatures() { + return db + .select(FEATURE_COLUMNS) + .from('features') + .where({ archived: 1 }) + .orderBy('name', 'asc') + .map(rowToFeature); + } + + + function rowToFeature(row) { + if (!row) { + throw new NotFoundError('No feature toggle found'); + } + + return { + name: row.name, + description: row.description, + enabled: row.enabled > 0, + strategy: row.strategy_name, // eslint-disable-line + parameters: row.parameters + }; + } + + function eventDataToRow(data) { + return { + name: data.name, + description: data.description, + enabled: data.enabled ? 1 : 0, + archived: data.archived ? 1 :0, + strategy_name: data.strategy, // eslint-disable-line + parameters: data.parameters + }; + } + + function createFeature(data) { + return db('features') + .insert(eventDataToRow(data)) + .catch(function (err) { + logger.error('Could not insert feature, error was: ', err); + }); + } + + function updateFeature(data) { + return db('features') + .where({ name: data.name }) + .update(eventDataToRow(data)) + .catch(function (err) { + logger.error('Could not update feature, error was: ', err); + }); + } + + function archiveFeature(data) { + return db('features') + .where({ name: data.name }) + .update({ archived: 1 }) + .catch(function (err) { + logger.error('Could not archive feature, error was: ', err); + }); + } + + function reviveFeature(data) { + return db('features') + .where({ name: data.name }) + .update({ archived: 0, enabled: 0 }) + .catch(function (err) { + logger.error('Could not archive feature, error was: ', err); + }); + } + + return { - name: row.name, - description: row.description, - enabled: row.enabled > 0, - strategy: row.strategy_name, // eslint-disable-line - parameters: row.parameters + getFeatures: getFeatures, + getFeature: getFeature, + getArchivedFeatures: getArchivedFeatures, + _createFeature: createFeature, // visible for testing + _updateFeature: updateFeature // visible for testing }; -} - -function eventDataToRow(data) { - return { - name: data.name, - description: data.description || '', - enabled: data.enabled ? 1 : 0, - archived: data.archived ? 1 :0, - strategy_name: data.strategy || 'default', // eslint-disable-line - parameters: data.parameters || {} - }; -} - -function createFeature(data) { - return knex('features') - .insert(eventDataToRow(data)) - .catch(function (err) { - logger.error('Could not insert feature, error was: ', err); - }); -} - -function updateFeature(data) { - return knex('features') - .where({ name: data.name }) - .update(eventDataToRow(data)) - .catch(function (err) { - logger.error('Could not update feature, error was: ', err); - }); -} - -function archiveFeature(data) { - return knex('features') - .where({ name: data.name }) - .update({ archived: 1 }) - .catch(function (err) { - logger.error('Could not archive feature, error was: ', err); - }); -} - -function reviveFeature(data) { - return knex('features') - .where({ name: data.name }) - .update({ archived: 0, enabled: 0 }) - .catch(function (err) { - logger.error('Could not archive feature, error was: ', err); - }); -} - - -module.exports = { - getFeatures: getFeatures, - getFeature: getFeature, - getArchivedFeatures: getArchivedFeatures, - _createFeature: createFeature, // visible for testing - _updateFeature: updateFeature // visible for testing }; diff --git a/lib/db/strategy.js b/lib/db/strategy.js index faebcfb36b..9a19a9c503 100644 --- a/lib/db/strategy.js +++ b/lib/db/strategy.js @@ -1,70 +1,70 @@ -var eventStore = require('../eventStore'); var eventType = require('../eventType'); var logger = require('../logger'); -var knex = require('./dbPool'); var NotFoundError = require('../error/NotFoundError'); var STRATEGY_COLUMNS = ['name', 'description', 'parameters_template']; -eventStore.on(eventType.strategyCreated, function (event) { - return createStrategy(event.data); -}); +module.exports = function(db, eventStore) { + eventStore.on(eventType.strategyCreated, function (event) { + return createStrategy(event.data); + }); -eventStore.on(eventType.strategyDeleted, function (event) { - knex('strategies') - .where('name', event.data.name) - .del() - .catch(function (err) { - logger.error('Could not delete strategy, error was: ', err); - }); -}); + eventStore.on(eventType.strategyDeleted, function (event) { + db('strategies') + .where('name', event.data.name) + .del() + .catch(function (err) { + logger.error('Could not delete strategy, error was: ', err); + }); + }); -function getStrategies() { - return knex - .select(STRATEGY_COLUMNS) - .from('strategies') - .orderBy('created_at', 'asc') - .map(rowToStrategy); -} + function getStrategies() { + return db + .select(STRATEGY_COLUMNS) + .from('strategies') + .orderBy('created_at', 'asc') + .map(rowToStrategy); + } -function getStrategy(name) { - return knex - .first(STRATEGY_COLUMNS) - .from('strategies') - .where({ name: name }) - .then(rowToStrategy); -} + function getStrategy(name) { + return db + .first(STRATEGY_COLUMNS) + .from('strategies') + .where({ name: name }) + .then(rowToStrategy); + } -function rowToStrategy(row) { - if (!row) { - throw new NotFoundError('No strategy found'); + function rowToStrategy(row) { + if (!row) { + throw new NotFoundError('No strategy found'); + } + + return { + name: row.name, + description: row.description, + parametersTemplate: row.parameters_template + }; + } + + function eventDataToRow(data) { + return { + name: data.name, + description: data.description, + parameters_template: data.parametersTemplate // eslint-disable-line + }; + } + + function createStrategy(data) { + db('strategies') + .insert(eventDataToRow(data)) + .catch(function (err) { + logger.error('Could not insert strategy, error was: ', err); + }); } return { - name: row.name, - description: row.description, - parametersTemplate: row.parameters_template + getStrategies: getStrategies, + getStrategy: getStrategy, + _createStrategy: createStrategy // visible for testing }; -} - -function eventDataToRow(data) { - return { - name: data.name, - description: data.description, - parameters_template: data.parametersTemplate || {} // eslint-disable-line - }; -} - -function createStrategy(data) { - knex('strategies') - .insert(eventDataToRow(data)) - .catch(function (err) { - logger.error('Could not insert strategy, error was: ', err); - }); -} - -module.exports = { - getStrategies: getStrategies, - getStrategy: getStrategy, - _createStrategy: createStrategy // visible for testing }; diff --git a/lib/eventStore.js b/lib/eventStore.js index 8e71fcd61b..1f39dbdf2c 100644 --- a/lib/eventStore.js +++ b/lib/eventStore.js @@ -1,17 +1,17 @@ -var util = require('util'), - eventDb = require('./db/event'), - EventEmitter = require('events').EventEmitter; +var util = require('util'); +var EventEmitter = require('events').EventEmitter; -function EventStore() { +function EventStore(eventDb) { + this.eventDb = eventDb; EventEmitter.call(this); } util.inherits(EventStore, EventEmitter); EventStore.prototype.create = function (event) { var that = this; - return eventDb.store(event).then(function() { - return that.emit(event.type, event); + return this.eventDb.store(event).then(function() { + that.emit(event.type, event); }); }; -module.exports = new EventStore(); +module.exports = EventStore; diff --git a/lib/routes/event.js b/lib/routes/event.js index 6461b1f58a..b69c7f7f09 100644 --- a/lib/routes/event.js +++ b/lib/routes/event.js @@ -1,7 +1,8 @@ -var eventDb = require('../db/event'); var eventDiffer = require('../eventDiffer'); -module.exports = function (app) { +module.exports = function (app, config) { + var eventDb = config.eventDb; + app.get('/events', function (req, res) { eventDb.getEvents().then(function (events) { eventDiffer.addDiffs(events); diff --git a/lib/routes/feature-archive.js b/lib/routes/feature-archive.js index d9b260349f..29fc82448a 100644 --- a/lib/routes/feature-archive.js +++ b/lib/routes/feature-archive.js @@ -1,11 +1,12 @@ var logger = require('../logger'); -var eventStore = require('../eventStore'); var eventType = require('../eventType'); -var featureDb = require('../db/feature'); var ValidationError = require('../error/ValidationError'); var validateRequest = require('../error/validateRequest'); -module.exports = function (app) { +module.exports = function (app, config) { + var featureDb = config.featureDb; + var eventStore = config.eventStore; + app.get('/archive/features', function (req, res) { featureDb.getArchivedFeatures().then(function (archivedFeatures) { res.json({ 'features': archivedFeatures }); diff --git a/lib/routes/feature.js b/lib/routes/feature.js index 51ab2a8055..1f3c726eaf 100644 --- a/lib/routes/feature.js +++ b/lib/routes/feature.js @@ -1,15 +1,16 @@ var Promise = require("bluebird"); var logger = require('../logger'); -var eventStore = require('../eventStore'); var eventType = require('../eventType'); -var featureDb = require('../db/feature'); var NameExistsError = require('../error/NameExistsError'); var NotFoundError = require('../error/NotFoundError'); var ValidationError = require('../error/ValidationError'); var validateRequest = require('../error/validateRequest'); var extractUser = require('../extractUser'); -module.exports = function (app) { +module.exports = function (app, config) { + var featureDb = config.featureDb; + var eventStore = config.eventStore; + app.get('/features', function (req, res) { featureDb.getFeatures().then(function (features) { res.json({ features: features }); diff --git a/lib/routes/health-check.js b/lib/routes/health-check.js index 76b84afe1c..1343e81686 100644 --- a/lib/routes/health-check.js +++ b/lib/routes/health-check.js @@ -1,9 +1,8 @@ -var knex = require('../db/dbPool'); var logger = require('../logger'); -module.exports = function (app) { +module.exports = function (app, config) { app.get('/health', function (req, res) { - knex.select(1) + config.db.select(1) .from('features') .then(function() { res.json({ health: 'GOOD' }); diff --git a/lib/routes/index.js b/lib/routes/index.js index 0c25412d3d..6e3515fa64 100644 --- a/lib/routes/index.js +++ b/lib/routes/index.js @@ -2,10 +2,10 @@ * TODO: we should also inject config and * services to the routes to ease testing. **/ -exports.create = function (app) { - require('./event')(app); - require('./feature')(app); - require('./feature-archive')(app); - require('./strategy')(app); - require('./health-check')(app); +exports.create = function (app, config) { + require('./event')(app, config); + require('./feature')(app, config); + require('./feature-archive')(app, config); + require('./strategy')(app, config); + require('./health-check')(app, config); }; diff --git a/lib/routes/strategy.js b/lib/routes/strategy.js index 20e635d897..4176d215c4 100644 --- a/lib/routes/strategy.js +++ b/lib/routes/strategy.js @@ -1,7 +1,5 @@ var Promise = require("bluebird"); -var eventStore = require('../eventStore'); var eventType = require('../eventType'); -var strategyDb = require('../db/strategy'); var logger = require('../logger'); var NameExistsError = require('../error/NameExistsError'); var ValidationError = require('../error/ValidationError'); @@ -9,7 +7,10 @@ var NotFoundError = require('../error/NotFoundError'); var validateRequest = require('../error/validateRequest'); var extractUser = require('../extractUser'); -module.exports = function (app) { +module.exports = function (app, config) { + var strategyDb = config.strategyDb; + var eventStore = config.eventStore; + app.get('/strategies', function (req, res) { strategyDb.getStrategies().then(function (strategies) { res.json({ strategies: strategies }); diff --git a/server.js b/server.js index 8590411f1b..e02a37d17a 100644 --- a/server.js +++ b/server.js @@ -1,8 +1,22 @@ var logger = require('./lib/logger'); +var databaseUri = require('./lib/databaseConfig').getDatabaseUrl(); + +// Database dependecies (statefull) +var db = require('./lib/db/dbPool')(databaseUri); +var eventDb = require('./lib/db/event')(db); +var EventStore = require('./lib/eventStore'); +var eventStore = new EventStore(eventDb); +var featureDb = require('./lib/db/feature')(db, eventStore); +var strategyDb = require('./lib/db/strategy')(db, eventStore); var config = { baseUriPath: process.env.BASE_URI_PATH || '', - port: process.env.HTTP_PORT || process.env.PORT || 4242 + port: process.env.HTTP_PORT || process.env.PORT || 4242, + db: db, + eventDb: eventDb, + eventStore: eventStore, + featureDb: featureDb, + strategyDb: strategyDb }; var app = require('./app')(config); @@ -25,7 +39,6 @@ if (app.get('env') === 'development') { })); } - process.on('uncaughtException', function(err) { logger.error('Uncaught Exception:', err.message); logger.error(err.stack); diff --git a/test/databaseConfig.js b/test/databaseConfig.js new file mode 100644 index 0000000000..5f80b7f2c5 --- /dev/null +++ b/test/databaseConfig.js @@ -0,0 +1,11 @@ +'use strict'; +function getDatabaseUri() { + if (!process.env.TEST_DATABASE_URL) { + throw new Error('please set TEST_DATABASE_URL'); + } else { + return process.env.TEST_DATABASE_URL; + } +} +module.exports = { + getDatabaseUri: getDatabaseUri +}; diff --git a/test/featureApiSpec.js b/test/featureApiSpec.js index 39d473429d..0ba1b70310 100644 --- a/test/featureApiSpec.js +++ b/test/featureApiSpec.js @@ -1,4 +1,5 @@ 'use strict'; +var logger = require('../lib/logger'); var assert = require('assert'); var specHelper = require('./specHelper'); var request = specHelper.request; @@ -32,6 +33,7 @@ describe('The features api', function () { }); it('cant get feature that dose not exist', function (done) { + logger.setLevel('FATAL'); request .get('/features/myfeature') .expect('Content-Type', /json/) @@ -47,6 +49,7 @@ describe('The features api', function () { }); it('creates new feature toggle with createdBy', function (done) { + logger.setLevel('FATAL'); request .post('/features') .send({ name: 'com.test.Username', enabled: false }) @@ -63,6 +66,7 @@ describe('The features api', function () { }); it('require new feature toggle to have a name', function (done) { + logger.setLevel('FATAL'); request .post('/features') .send({ name: '' }) @@ -71,6 +75,7 @@ describe('The features api', function () { }); it('can not change status of feature toggle that does not exist', function (done) { + logger.setLevel('FATAL'); request .put('/features/should-not-exist') .send({ name: 'should-not-exist', enabled: false }) @@ -79,6 +84,7 @@ describe('The features api', function () { }); it('can change status of feature toggle that does exist', function (done) { + logger.setLevel('FATAL'); request .put('/features/featureY') .send({ name: 'featureY', enabled: true }) diff --git a/test/specHelper.js b/test/specHelper.js index 02a6563481..7ad8c98790 100644 --- a/test/specHelper.js +++ b/test/specHelper.js @@ -3,10 +3,22 @@ process.env.NODE_ENV = 'test'; var Promise = require('bluebird'); var request = require('supertest'); -var app = require('../app')({ baseUriPath: '' }); -var knex = require('../lib/db/dbPool'); -var featureDb = require('../lib/db/feature'); -var strategyDb = require('../lib/db/strategy'); +var databaseUri = require('./databaseConfig').getDatabaseUri(); +var knex = require('../lib/db/dbPool')(databaseUri); +var eventDb = require('../lib/db/event')(knex); +var EventStore = require('../lib/eventStore'); +var eventStore = new EventStore(eventDb); +var featureDb = require('../lib/db/feature')(knex, eventStore); +var strategyDb = require('../lib/db/strategy')(knex, eventStore); + +var app = require('../app')({ + baseUriPath: '', + db: knex, + eventDb: eventDb, + eventStore: eventStore, + featureDb: featureDb, + strategyDb: strategyDb +}); Promise.promisifyAll(request); request = request(app); From 3e9788e617f4a1dcfc7936777e432871131122c3 Mon Sep 17 00:00:00 2001 From: Ivar Date: Sun, 1 May 2016 22:59:43 +0200 Subject: [PATCH 15/15] formatting --- app.js | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/app.js b/app.js index 8f643b3b34..feaa0ab007 100644 --- a/app.js +++ b/app.js @@ -12,28 +12,22 @@ module.exports = function(config) { var router = express.Router(); // eslint-disable-line var baseUriPath = config.baseUriPath || ''; - app.use(favicon(__dirname + '/public/favicon.ico')); - - app.use(validator([])); - app.set('trust proxy'); + app.set('port', config.port); app.locals.baseUriPath = baseUriPath; + app.use(cookieParser()); + app.use(favicon(__dirname + '/public/favicon.ico')); + app.use(validator([])); + app.use(baseUriPath, express.static(__dirname + '/public')); + app.use(bodyParser.json({ strict: false })); app.use(log4js.connectLogger(logger, { format: ':remote-addr :status :method :url :response-timems', level: 'auto' // 3XX=WARN, 4xx/5xx=ERROR })); - app.set('port', config.port); - - app.use(baseUriPath, express.static(__dirname + '/public')); - app.use(bodyParser.json({ strict: false })); - - app.use(cookieParser()); - // Setup API routes routes.create(router, config); - app.use(baseUriPath, router); return app;