mirror of
https://github.com/Unleash/unleash.git
synced 2025-01-01 00:08:27 +01:00
commit
4c1b380036
5
.gitignore
vendored
5
.gitignore
vendored
@ -32,3 +32,8 @@ unleash-server.tar.gz
|
|||||||
.idea/*
|
.idea/*
|
||||||
|
|
||||||
.vagrant/
|
.vagrant/
|
||||||
|
|
||||||
|
# Visual Studio Code
|
||||||
|
jsconfig.json
|
||||||
|
typings
|
||||||
|
.vscode
|
@ -71,6 +71,6 @@ npm run docker-test
|
|||||||
|
|
||||||
1. Create `migrations/sql/NNN-your-migration-name.up.sql` with your change in SQL.
|
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.
|
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`.
|
4. Run `db-migrate up`.
|
||||||
5. Generate LB artifact using `scripts/generate-liquibase-artifact` (TODO: make this internal)
|
5. Generate LB artifact using `scripts/generate-liquibase-artifact` (TODO: make this internal)
|
||||||
|
79
app.js
79
app.js
@ -1,55 +1,34 @@
|
|||||||
var express = require('express'),
|
var express = require('express');
|
||||||
bodyParser = require('body-parser'),
|
var favicon = require('serve-favicon');
|
||||||
cookieParser = require('cookie-parser'),
|
var bodyParser = require('body-parser');
|
||||||
log4js = require('log4js'),
|
var cookieParser = require('cookie-parser');
|
||||||
logger = require('./lib/logger'),
|
var validator = require('express-validator');
|
||||||
routes = require('./lib/routes'),
|
var log4js = require('log4js');
|
||||||
eventApi = require('./lib/eventApi'),
|
var logger = require('./lib/logger');
|
||||||
featureApi = require('./lib/featureApi'),
|
var routes = require('./lib/routes');
|
||||||
featureArchiveApi = require('./lib/featureArchiveApi'),
|
|
||||||
strategyApi = require('./lib/strategyApi'),
|
|
||||||
validator = require('express-validator'),
|
|
||||||
app = express(),
|
|
||||||
router = express.Router(), // eslint-disable-line
|
|
||||||
baseUriPath = process.env.BASE_URI_PATH || '';
|
|
||||||
|
|
||||||
if (app.get('env') === 'development') {
|
module.exports = function(config) {
|
||||||
app.use(require('errorhandler')());
|
var app = express();
|
||||||
|
var router = express.Router(); // eslint-disable-line
|
||||||
|
var baseUriPath = config.baseUriPath || '';
|
||||||
|
|
||||||
var webpack = require('webpack'),
|
app.set('trust proxy');
|
||||||
webpackDevMiddleware = require('webpack-dev-middleware'),
|
app.set('port', config.port);
|
||||||
webpackConfig = require('./webpack.config'),
|
app.locals.baseUriPath = baseUriPath;
|
||||||
compiler = webpack(webpackConfig),
|
app.use(cookieParser());
|
||||||
config = {
|
|
||||||
publicPath: '/js',
|
|
||||||
noInfo: true
|
|
||||||
};
|
|
||||||
|
|
||||||
app.use(baseUriPath, webpackDevMiddleware(compiler, config));
|
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.use(validator([]));
|
// Setup API routes
|
||||||
|
routes.create(router, config);
|
||||||
|
app.use(baseUriPath, router);
|
||||||
|
|
||||||
app.set('trust proxy');
|
return app;
|
||||||
app.locals.baseUriPath = baseUriPath;
|
};
|
||||||
|
|
||||||
app.use(log4js.connectLogger(logger, {
|
|
||||||
format: ':remote-addr :status :method :url :response-timems',
|
|
||||||
level: 'auto' // 3XX=WARN, 4xx/5xx=ERROR
|
|
||||||
}));
|
|
||||||
|
|
||||||
app.set('port', process.env.HTTP_PORT || process.env.PORT || 4242);
|
|
||||||
|
|
||||||
app.use(baseUriPath, express.static(__dirname + '/public'));
|
|
||||||
app.use(bodyParser.json({ strict: false }));
|
|
||||||
|
|
||||||
app.use(cookieParser());
|
|
||||||
|
|
||||||
eventApi(router);
|
|
||||||
featureApi(router);
|
|
||||||
featureArchiveApi(router);
|
|
||||||
strategyApi(router);
|
|
||||||
routes(router);
|
|
||||||
app.use(baseUriPath, router);
|
|
||||||
|
|
||||||
module.exports = app;
|
|
||||||
|
@ -1,12 +1,7 @@
|
|||||||
var logger = require('./logger');
|
|
||||||
var nconf = require('nconf');
|
var nconf = require('nconf');
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
var ini = require('ini');
|
var ini = require('ini');
|
||||||
var knex = require('knex');
|
var logger = require('./logger');
|
||||||
|
|
||||||
function isTestEnv() {
|
|
||||||
return process.env.NODE_ENV === 'test';
|
|
||||||
}
|
|
||||||
|
|
||||||
function getDatabaseIniUrl() {
|
function getDatabaseIniUrl() {
|
||||||
// Finn specific way of delivering env variables
|
// Finn specific way of delivering env variables
|
||||||
@ -18,15 +13,6 @@ function getDatabaseIniUrl() {
|
|||||||
return config.DATABASE_URL;
|
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() {
|
function getDatabaseUrl() {
|
||||||
if (process.env.DATABASE_URL) {
|
if (process.env.DATABASE_URL) {
|
||||||
logger.info('unleash started with DATABASE_URL');
|
logger.info('unleash started with DATABASE_URL');
|
||||||
@ -38,15 +24,6 @@ function getDatabaseUrl() {
|
|||||||
throw new Error('please set DATABASE_URL or pass --databaseini');
|
throw new Error('please set DATABASE_URL or pass --databaseini');
|
||||||
}
|
}
|
||||||
|
|
||||||
function createDbPool() {
|
module.exports = {
|
||||||
return knex({
|
getDatabaseUrl: getDatabaseUrl
|
||||||
client: 'pg',
|
};
|
||||||
connection: isTestEnv() ? getTestDatabaseUrl() : getDatabaseUrl(),
|
|
||||||
pool: {
|
|
||||||
min: 2,
|
|
||||||
max: 20
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = createDbPool();
|
|
9
lib/db/dbPool.js
Normal file
9
lib/db/dbPool.js
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
var knex = require('knex');
|
||||||
|
|
||||||
|
module.exports = function(databaseConnection) {
|
||||||
|
return knex({
|
||||||
|
client: 'pg',
|
||||||
|
connection: databaseConnection,
|
||||||
|
pool: { min: 2, max: 20 }
|
||||||
|
});
|
||||||
|
};
|
45
lib/db/event.js
Normal file
45
lib/db/event.js
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
var EVENT_COLUMNS = ['id', 'type', 'created_by', 'created_at', '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 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 rowToEvent(row) {
|
||||||
|
return {
|
||||||
|
id: row.id,
|
||||||
|
type: row.type,
|
||||||
|
createdBy: row.created_by,
|
||||||
|
createdAt: row.created_at,
|
||||||
|
data: row.data
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
store: storeEvent,
|
||||||
|
getEvents: getEvents,
|
||||||
|
getEventsFilterByName: getEventsFilterByName
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
118
lib/db/feature.js
Normal file
118
lib/db/feature.js
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
var eventType = require('../eventType');
|
||||||
|
var logger = require('../logger');
|
||||||
|
var NotFoundError = require('../error/NotFoundError');
|
||||||
|
var FEATURE_COLUMNS = ['name', 'description', 'enabled', 'strategy_name', 'parameters'];
|
||||||
|
|
||||||
|
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.featureArchived, function (event) {
|
||||||
|
return archiveFeature(event.data);
|
||||||
|
});
|
||||||
|
|
||||||
|
eventStore.on(eventType.featureRevived, function (event) {
|
||||||
|
return reviveFeature(event.data);
|
||||||
|
});
|
||||||
|
|
||||||
|
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 {
|
||||||
|
getFeatures: getFeatures,
|
||||||
|
getFeature: getFeature,
|
||||||
|
getArchivedFeatures: getArchivedFeatures,
|
||||||
|
_createFeature: createFeature, // visible for testing
|
||||||
|
_updateFeature: updateFeature // visible for testing
|
||||||
|
};
|
||||||
|
};
|
70
lib/db/strategy.js
Normal file
70
lib/db/strategy.js
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
var eventType = require('../eventType');
|
||||||
|
var logger = require('../logger');
|
||||||
|
var NotFoundError = require('../error/NotFoundError');
|
||||||
|
var STRATEGY_COLUMNS = ['name', 'description', 'parameters_template'];
|
||||||
|
|
||||||
|
module.exports = function(db, eventStore) {
|
||||||
|
eventStore.on(eventType.strategyCreated, function (event) {
|
||||||
|
return createStrategy(event.data);
|
||||||
|
});
|
||||||
|
|
||||||
|
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 db
|
||||||
|
.select(STRATEGY_COLUMNS)
|
||||||
|
.from('strategies')
|
||||||
|
.orderBy('created_at', 'asc')
|
||||||
|
.map(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');
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
getStrategies: getStrategies,
|
||||||
|
getStrategy: getStrategy,
|
||||||
|
_createStrategy: createStrategy // visible for testing
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
@ -1,43 +0,0 @@
|
|||||||
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
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function getEvents() {
|
|
||||||
return knex
|
|
||||||
.select(EVENT_COLUMNS)
|
|
||||||
.from('events')
|
|
||||||
.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
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
store: storeEvent,
|
|
||||||
getEvents: getEvents,
|
|
||||||
getEventsFilterByName: getEventsFilterByName
|
|
||||||
};
|
|
@ -1,17 +1,17 @@
|
|||||||
var util = require('util'),
|
var util = require('util');
|
||||||
eventDb = require('./eventDb'),
|
var EventEmitter = require('events').EventEmitter;
|
||||||
EventEmitter = require('events').EventEmitter;
|
|
||||||
|
|
||||||
function EventStore() {
|
function EventStore(eventDb) {
|
||||||
|
this.eventDb = eventDb;
|
||||||
EventEmitter.call(this);
|
EventEmitter.call(this);
|
||||||
}
|
}
|
||||||
util.inherits(EventStore, EventEmitter);
|
util.inherits(EventStore, EventEmitter);
|
||||||
|
|
||||||
EventStore.prototype.create = function (event) {
|
EventStore.prototype.create = function (event) {
|
||||||
var that = this;
|
var that = this;
|
||||||
return eventDb.store(event).then(function() {
|
return this.eventDb.store(event).then(function() {
|
||||||
return that.emit(event.type, event);
|
that.emit(event.type, event);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = new EventStore();
|
module.exports = EventStore;
|
||||||
|
118
lib/featureDb.js
118
lib/featureDb.js
@ -1,118 +0,0 @@
|
|||||||
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);
|
|
||||||
});
|
|
||||||
|
|
||||||
eventStore.on(eventType.featureUpdated, function (event) {
|
|
||||||
return updateFeature(event.data);
|
|
||||||
});
|
|
||||||
|
|
||||||
eventStore.on(eventType.featureArchived, function (event) {
|
|
||||||
return archiveFeature(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');
|
|
||||||
}
|
|
||||||
|
|
||||||
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 || '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
|
|
||||||
};
|
|
@ -1,7 +1,8 @@
|
|||||||
var eventDb = require('./eventDb');
|
var eventDiffer = require('../eventDiffer');
|
||||||
var eventDiffer = require('./eventDiffer');
|
|
||||||
|
module.exports = function (app, config) {
|
||||||
|
var eventDb = config.eventDb;
|
||||||
|
|
||||||
module.exports = function (app) {
|
|
||||||
app.get('/events', function (req, res) {
|
app.get('/events', function (req, res) {
|
||||||
eventDb.getEvents().then(function (events) {
|
eventDb.getEvents().then(function (events) {
|
||||||
eventDiffer.addDiffs(events);
|
eventDiffer.addDiffs(events);
|
@ -1,11 +1,12 @@
|
|||||||
var logger = require('./logger');
|
var logger = require('../logger');
|
||||||
var eventStore = require('./eventStore');
|
var eventType = require('../eventType');
|
||||||
var eventType = require('./eventType');
|
var ValidationError = require('../error/ValidationError');
|
||||||
var featureDb = require('./featureDb');
|
var validateRequest = require('../error/validateRequest');
|
||||||
var ValidationError = require('./error/ValidationError');
|
|
||||||
var validateRequest = require('./error/validateRequest');
|
module.exports = function (app, config) {
|
||||||
|
var featureDb = config.featureDb;
|
||||||
|
var eventStore = config.eventStore;
|
||||||
|
|
||||||
module.exports = function (app) {
|
|
||||||
app.get('/archive/features', function (req, res) {
|
app.get('/archive/features', function (req, res) {
|
||||||
featureDb.getArchivedFeatures().then(function (archivedFeatures) {
|
featureDb.getArchivedFeatures().then(function (archivedFeatures) {
|
||||||
res.json({ 'features': archivedFeatures });
|
res.json({ 'features': archivedFeatures });
|
@ -1,15 +1,16 @@
|
|||||||
var Promise = require("bluebird");
|
var Promise = require("bluebird");
|
||||||
var logger = require('./logger');
|
var logger = require('../logger');
|
||||||
var eventStore = require('./eventStore');
|
var eventType = require('../eventType');
|
||||||
var eventType = require('./eventType');
|
var NameExistsError = require('../error/NameExistsError');
|
||||||
var featureDb = require('./featureDb');
|
var NotFoundError = require('../error/NotFoundError');
|
||||||
var NameExistsError = require('./error/NameExistsError');
|
var ValidationError = require('../error/ValidationError');
|
||||||
var NotFoundError = require('./error/NotFoundError');
|
var validateRequest = require('../error/validateRequest');
|
||||||
var ValidationError = require('./error/ValidationError');
|
var extractUser = require('../extractUser');
|
||||||
var validateRequest = require('./error/validateRequest');
|
|
||||||
var extractUser = require('./extractUser');
|
module.exports = function (app, config) {
|
||||||
|
var featureDb = config.featureDb;
|
||||||
|
var eventStore = config.eventStore;
|
||||||
|
|
||||||
module.exports = function (app) {
|
|
||||||
app.get('/features', function (req, res) {
|
app.get('/features', function (req, res) {
|
||||||
featureDb.getFeatures().then(function (features) {
|
featureDb.getFeatures().then(function (features) {
|
||||||
res.json({ features: features });
|
res.json({ features: features });
|
@ -1,9 +1,8 @@
|
|||||||
var knex = require('./dbPool');
|
var logger = require('../logger');
|
||||||
var logger = require('./logger');
|
|
||||||
|
|
||||||
module.exports = function (app) {
|
module.exports = function (app, config) {
|
||||||
app.get('/health', function (req, res) {
|
app.get('/health', function (req, res) {
|
||||||
knex.select(1)
|
config.db.select(1)
|
||||||
.from('features')
|
.from('features')
|
||||||
.then(function() {
|
.then(function() {
|
||||||
res.json({ health: 'GOOD' });
|
res.json({ health: 'GOOD' });
|
11
lib/routes/index.js
Normal file
11
lib/routes/index.js
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
/**
|
||||||
|
* TODO: we should also inject config and
|
||||||
|
* services to the routes to ease testing.
|
||||||
|
**/
|
||||||
|
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);
|
||||||
|
};
|
@ -1,15 +1,16 @@
|
|||||||
var Promise = require("bluebird");
|
var Promise = require("bluebird");
|
||||||
var eventStore = require('./eventStore');
|
var eventType = require('../eventType');
|
||||||
var eventType = require('./eventType');
|
var logger = require('../logger');
|
||||||
var strategyDb = require('./strategyDb');
|
var NameExistsError = require('../error/NameExistsError');
|
||||||
var logger = require('./logger');
|
var ValidationError = require('../error/ValidationError');
|
||||||
var NameExistsError = require('./error/NameExistsError');
|
var NotFoundError = require('../error/NotFoundError');
|
||||||
var ValidationError = require('./error/ValidationError');
|
var validateRequest = require('../error/validateRequest');
|
||||||
var NotFoundError = require('./error/NotFoundError');
|
var extractUser = require('../extractUser');
|
||||||
var validateRequest = require('./error/validateRequest');
|
|
||||||
var extractUser = require('./extractUser');
|
module.exports = function (app, config) {
|
||||||
|
var strategyDb = config.strategyDb;
|
||||||
|
var eventStore = config.eventStore;
|
||||||
|
|
||||||
module.exports = function (app) {
|
|
||||||
app.get('/strategies', function (req, res) {
|
app.get('/strategies', function (req, res) {
|
||||||
strategyDb.getStrategies().then(function (strategies) {
|
strategyDb.getStrategies().then(function (strategies) {
|
||||||
res.json({ strategies: strategies });
|
res.json({ strategies: strategies });
|
@ -1,70 +0,0 @@
|
|||||||
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);
|
|
||||||
});
|
|
||||||
|
|
||||||
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);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
function getStrategies() {
|
|
||||||
return knex
|
|
||||||
.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 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) {
|
|
||||||
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
|
|
||||||
};
|
|
||||||
|
|
@ -1 +1 @@
|
|||||||
module.exports = require('../lib/migrationRunner').create('001-initial-schema');
|
module.exports = require('../scripts/migration-runner').create('001-initial-schema');
|
||||||
|
@ -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');
|
||||||
|
@ -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');
|
||||||
|
|
||||||
|
@ -1 +1 @@
|
|||||||
module.exports = require('../lib/migrationRunner').create('004-insert-default-strategy');
|
module.exports = require('../scripts/migration-runner').create('004-insert-default-strategy');
|
||||||
|
@ -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');
|
||||||
|
@ -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');
|
||||||
|
@ -1 +1 @@
|
|||||||
module.exports = require('../lib/migrationRunner').create('006-rename-eventtype');
|
module.exports = require('../scripts/migration-runner').create('006-rename-eventtype');
|
||||||
|
193
package.json
193
package.json
@ -1,96 +1,105 @@
|
|||||||
{
|
{
|
||||||
"name": "unleash-server",
|
"name": "unleash-server",
|
||||||
"description": "unleash your features",
|
"description": "unleash your features",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"unleash",
|
"unleash",
|
||||||
"feature toggle",
|
"feature toggle",
|
||||||
"feature",
|
"feature",
|
||||||
"toggle"
|
"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.8",
|
||||||
|
"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": "<rootDir>/scripts/jest-preprocessor.js",
|
||||||
|
"modulePathIgnorePatterns": [
|
||||||
|
"<rootDir>/node_modules/npm"
|
||||||
],
|
],
|
||||||
"repository": {
|
"unmockedModulePathPatterns": [
|
||||||
"type": "git",
|
"<rootDir>/node_modules/react",
|
||||||
"url": "ssh://git@github.com:finn-no/unleash.git"
|
"<rootDir>/node_modules/reflux"
|
||||||
},
|
],
|
||||||
"bugs": {
|
"moduleFileExtensions": [
|
||||||
"url": "https://github.com/finn-no/unleash/issues"
|
"jsx",
|
||||||
},
|
"js"
|
||||||
"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.12.2",
|
|
||||||
"cookie-parser": "^1.3.3",
|
|
||||||
"db-migrate": "0.9.23",
|
|
||||||
"deep-diff": "^0.3.0",
|
|
||||||
"errorhandler": "1.3.5",
|
|
||||||
"express": "4.12.3",
|
|
||||||
"express-validator": "2.9.0",
|
|
||||||
"ini": "1.3.3",
|
|
||||||
"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",
|
|
||||||
"nconf": "0.7.1",
|
|
||||||
"pg": "^4.5.5",
|
|
||||||
"react": "^0.13.1",
|
|
||||||
"react-router": "^0.13.2",
|
|
||||||
"reflux": "^0.2.10",
|
|
||||||
"reqwest": "^1.1.4",
|
|
||||||
"webpack": "1.7.3",
|
|
||||||
"webpack-dev-middleware": "^1.0.11"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"chai": "2.1.2",
|
|
||||||
"coveralls": "^2.11.2",
|
|
||||||
"eslint": "^2.7.0",
|
|
||||||
"eslint-config-spt": "^2.0.0",
|
|
||||||
"eslint-plugin-react": "^4.3.0",
|
|
||||||
"istanbul": "^0.3.5",
|
|
||||||
"jest-cli": "0.5.4",
|
|
||||||
"mocha": "^2.1.0",
|
|
||||||
"mocha-lcov-reporter": "0.0.2",
|
|
||||||
"nsp": "^1.0.0",
|
|
||||||
"pre-commit": "^1.0.2",
|
|
||||||
"react-tools": "^0.13.1",
|
|
||||||
"supertest": "^0.15.0",
|
|
||||||
"supervisor": "^0.6.0",
|
|
||||||
"xmlbuilder": "^2.5.1"
|
|
||||||
},
|
|
||||||
"jest": {
|
|
||||||
"scriptPreprocessor": "<rootDir>/jest-preprocessor.js",
|
|
||||||
"unmockedModulePathPatterns": [
|
|
||||||
"<rootDir>/node_modules/react",
|
|
||||||
"<rootDir>/node_modules/reflux"
|
|
||||||
],
|
|
||||||
"moduleFileExtensions": [
|
|
||||||
"jsx",
|
|
||||||
"js"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"pre-commit": [
|
|
||||||
"lint"
|
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"pre-commit": [
|
||||||
|
"lint"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
BIN
public/favicon.ico
Normal file
BIN
public/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 34 KiB |
36
server.js
36
server.js
@ -1,10 +1,44 @@
|
|||||||
var app = require('./app');
|
|
||||||
var logger = require('./lib/logger');
|
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,
|
||||||
|
db: db,
|
||||||
|
eventDb: eventDb,
|
||||||
|
eventStore: eventStore,
|
||||||
|
featureDb: featureDb,
|
||||||
|
strategyDb: strategyDb
|
||||||
|
};
|
||||||
|
|
||||||
|
var app = require('./app')(config);
|
||||||
|
|
||||||
var server = app.listen(app.get('port'), function() {
|
var server = app.listen(app.get('port'), function() {
|
||||||
logger.info('unleash started on ' + app.get('port'));
|
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) {
|
process.on('uncaughtException', function(err) {
|
||||||
logger.error('Uncaught Exception:', err.message);
|
logger.error('Uncaught Exception:', err.message);
|
||||||
logger.error(err.stack);
|
logger.error(err.stack);
|
||||||
|
11
test/databaseConfig.js
Normal file
11
test/databaseConfig.js
Normal file
@ -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
|
||||||
|
};
|
@ -1,4 +1,5 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
var logger = require('../lib/logger');
|
||||||
var assert = require('assert');
|
var assert = require('assert');
|
||||||
var specHelper = require('./specHelper');
|
var specHelper = require('./specHelper');
|
||||||
var request = specHelper.request;
|
var request = specHelper.request;
|
||||||
@ -32,6 +33,7 @@ describe('The features api', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('cant get feature that dose not exist', function (done) {
|
it('cant get feature that dose not exist', function (done) {
|
||||||
|
logger.setLevel('FATAL');
|
||||||
request
|
request
|
||||||
.get('/features/myfeature')
|
.get('/features/myfeature')
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
@ -47,6 +49,7 @@ describe('The features api', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('creates new feature toggle with createdBy', function (done) {
|
it('creates new feature toggle with createdBy', function (done) {
|
||||||
|
logger.setLevel('FATAL');
|
||||||
request
|
request
|
||||||
.post('/features')
|
.post('/features')
|
||||||
.send({ name: 'com.test.Username', enabled: false })
|
.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) {
|
it('require new feature toggle to have a name', function (done) {
|
||||||
|
logger.setLevel('FATAL');
|
||||||
request
|
request
|
||||||
.post('/features')
|
.post('/features')
|
||||||
.send({ name: '' })
|
.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) {
|
it('can not change status of feature toggle that does not exist', function (done) {
|
||||||
|
logger.setLevel('FATAL');
|
||||||
request
|
request
|
||||||
.put('/features/should-not-exist')
|
.put('/features/should-not-exist')
|
||||||
.send({ name: 'should-not-exist', enabled: false })
|
.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) {
|
it('can change status of feature toggle that does exist', function (done) {
|
||||||
|
logger.setLevel('FATAL');
|
||||||
request
|
request
|
||||||
.put('/features/featureY')
|
.put('/features/featureY')
|
||||||
.send({ name: 'featureY', enabled: true })
|
.send({ name: 'featureY', enabled: true })
|
||||||
|
@ -1,12 +1,24 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
process.env.NODE_ENV = 'test';
|
process.env.NODE_ENV = 'test';
|
||||||
|
|
||||||
var Promise = require('bluebird');
|
var Promise = require('bluebird');
|
||||||
var request = require('supertest');
|
var request = require('supertest');
|
||||||
var app = require('../app');
|
var databaseUri = require('./databaseConfig').getDatabaseUri();
|
||||||
var knex = require('../lib/dbPool');
|
var knex = require('../lib/db/dbPool')(databaseUri);
|
||||||
var featureDb = require('../lib/featureDb');
|
var eventDb = require('../lib/db/event')(knex);
|
||||||
var strategyDb = require('../lib/strategyDb');
|
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);
|
Promise.promisifyAll(request);
|
||||||
request = request(app);
|
request = request(app);
|
||||||
|
Loading…
Reference in New Issue
Block a user