diff --git a/.eslintrc b/.eslintrc index 2c8ac6c0ac..ecfcaa749a 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,12 +1,22 @@ { "extends": [ "finn", - "finn/node" + "finn/node", + "finn-prettier" ], "parserOptions": { "ecmaVersion": "2017" }, "rules": { - "max-nested-callbacks": "off" + "max-nested-callbacks": "off", + "new-cap": [ + "error", + { + "capIsNewExceptions": [ + "Router", + "Mitm" + ] + } + ] } } diff --git a/lib/app.js b/lib/app.js index a78b61f0d7..a810675936 100644 --- a/lib/app.js +++ b/lib/app.js @@ -14,7 +14,7 @@ const errorHandler = require('errorhandler'); const { REQUEST_TIME } = require('./events'); -module.exports = function (config) { +module.exports = function(config) { const app = express(); const baseUriPath = config.baseUriPath || ''; @@ -34,10 +34,17 @@ module.exports = function (config) { app.use(favicon(path.join(publicFolder, 'favicon.ico'))); } - app.use(responseTime((req, res, time) => { - const timingInfo = { path: req.path, method: req.method, statusCode: res.statusCode, time }; - config.eventBus.emit(REQUEST_TIME, timingInfo); - })); + app.use( + responseTime((req, res, time) => { + const timingInfo = { + path: req.path, + method: req.method, + statusCode: res.statusCode, + time, + }; + config.eventBus.emit(REQUEST_TIME, timingInfo); + }) + ); app.use(validator([])); @@ -48,10 +55,12 @@ module.exports = function (config) { app.use(bodyParser.json({ strict: false })); if (config.enableRequestLogger) { - app.use(log4js.connectLogger(logger, { - format: ':status :method :url :response-timems', - level: 'auto', // 3XX=WARN, 4xx/5xx=ERROR - })); + app.use( + log4js.connectLogger(logger, { + format: ':status :method :url :response-timems', + level: 'auto', // 3XX=WARN, 4xx/5xx=ERROR + }) + ); } if (typeof config.preRouterHook === 'function') { diff --git a/lib/app.test.js b/lib/app.test.js index 2124cb10a2..16e4fad8a3 100644 --- a/lib/app.test.js +++ b/lib/app.test.js @@ -16,16 +16,20 @@ test('should not throw when valid config', t => { test('should call preHook', t => { let called = 0; - getApp({ preHook: () => { - called++; - } }); + getApp({ + preHook: () => { + called++; + }, + }); t.true(called === 1); }); test('should call preRouterHook', t => { let called = 0; - getApp({ preRouterHook: () => { - called++; - } }); + getApp({ + preRouterHook: () => { + called++; + }, + }); t.true(called === 1); }); diff --git a/lib/client-metrics/client-metrics.test.js b/lib/client-metrics/client-metrics.test.js index 2ff289314b..d972b11666 100644 --- a/lib/client-metrics/client-metrics.test.js +++ b/lib/client-metrics/client-metrics.test.js @@ -10,7 +10,7 @@ const { EventEmitter } = require('events'); const appName = 'appName'; const instanceId = 'instanceId'; -test('should work without state', (t) => { +test('should work without state', t => { const store = new EventEmitter(); const metrics = new UnleashClientMetrics(store); @@ -20,7 +20,7 @@ test('should work without state', (t) => { metrics.destroy(); }); -test.cb('data should expire', (t) => { +test.cb('data should expire', t => { const clock = sinon.useFakeTimers(); const store = new EventEmitter(); @@ -84,9 +84,14 @@ test('should listen to metrics from store', t => { t.truthy(metrics.apps[appName].count === 123); t.truthy(metrics.globalCount === 123); - t.deepEqual(metrics.getTogglesMetrics().lastHour.toggleX, { yes: 123, no: 0 }); - t.deepEqual(metrics.getTogglesMetrics().lastMinute.toggleX, { yes: 123, no: 0 }); - + t.deepEqual(metrics.getTogglesMetrics().lastHour.toggleX, { + yes: 123, + no: 0, + }); + t.deepEqual(metrics.getTogglesMetrics().lastMinute.toggleX, { + yes: 123, + no: 0, + }); metrics.addPayload({ appName, @@ -104,8 +109,14 @@ test('should listen to metrics from store', t => { }); t.truthy(metrics.globalCount === 143); - t.deepEqual(metrics.getTogglesMetrics().lastHour.toggleX, { yes: 133, no: 10 }); - t.deepEqual(metrics.getTogglesMetrics().lastMinute.toggleX, { yes: 133, no: 10 }); + t.deepEqual(metrics.getTogglesMetrics().lastHour.toggleX, { + yes: 133, + no: 10, + }); + t.deepEqual(metrics.getTogglesMetrics().lastMinute.toggleX, { + yes: 133, + no: 10, + }); metrics.destroy(); }); @@ -146,7 +157,6 @@ test('should build up list of seend toggles when new metrics arrives', t => { metrics.destroy(); }); - test('should handle a lot of toggles', t => { const store = new EventEmitter(); const metrics = new UnleashClientMetrics(store); @@ -244,7 +254,6 @@ test('should have correct values for lastMinute', t => { clock.restore(); }); - test('should have correct values for lastHour', t => { const clock = sinon.useFakeTimers(); diff --git a/lib/client-metrics/index.js b/lib/client-metrics/index.js index eb0fc0148d..dfb911cee4 100644 --- a/lib/client-metrics/index.js +++ b/lib/client-metrics/index.js @@ -4,7 +4,7 @@ const Projection = require('./projection.js'); const TTLList = require('./ttl-list.js'); module.exports = class UnleashClientMetrics { - constructor (clientMetricsStore) { + constructor(clientMetricsStore) { this.globalCount = 0; this.apps = {}; @@ -21,20 +21,26 @@ module.exports = class UnleashClientMetrics { expireAmount: 1, }); - this.lastHourList.on('expire', (toggles) => { + this.lastHourList.on('expire', toggles => { Object.keys(toggles).forEach(toggleName => { - this.lastHourProjection.substract(toggleName, toggles[toggleName]); + this.lastHourProjection.substract( + toggleName, + toggles[toggleName] + ); }); }); - this.lastMinuteList.on('expire', (toggles) => { + this.lastMinuteList.on('expire', toggles => { Object.keys(toggles).forEach(toggleName => { - this.lastMinuteProjection.substract(toggleName, toggles[toggleName]); + this.lastMinuteProjection.substract( + toggleName, + toggles[toggleName] + ); }); }); - clientMetricsStore.on('metrics', (m) => this.addPayload(m)); + clientMetricsStore.on('metrics', m => this.addPayload(m)); } - getAppsWithToggles () { + getAppsWithToggles() { const apps = []; Object.keys(this.apps).forEach(appName => { const seenToggles = Object.keys(this.apps[appName].seenToggles); @@ -43,14 +49,18 @@ module.exports = class UnleashClientMetrics { }); return apps; } - getSeenTogglesByAppName (appName) { - return this.apps[appName] ? Object.keys(this.apps[appName].seenToggles) : []; + getSeenTogglesByAppName(appName) { + return this.apps[appName] + ? Object.keys(this.apps[appName].seenToggles) + : []; } - getSeenAppsPerToggle () { + getSeenAppsPerToggle() { const toggles = {}; Object.keys(this.apps).forEach(appName => { - Object.keys(this.apps[appName].seenToggles).forEach((seenToggleName) => { + Object.keys( + this.apps[appName].seenToggles + ).forEach(seenToggleName => { if (!toggles[seenToggleName]) { toggles[seenToggleName] = []; } @@ -60,36 +70,39 @@ module.exports = class UnleashClientMetrics { return toggles; } - getTogglesMetrics () { + getTogglesMetrics() { return { lastHour: this.lastHourProjection.getProjection(), lastMinute: this.lastMinuteProjection.getProjection(), }; } - addPayload (data) { + addPayload(data) { const { appName, bucket } = data; const app = this.getApp(appName); this.addBucket(app, bucket); } - getApp (appName) { - this.apps[appName] = this.apps[appName] || { seenToggles: {}, count: 0 }; + getApp(appName) { + this.apps[appName] = this.apps[appName] || { + seenToggles: {}, + count: 0, + }; return this.apps[appName]; } - addBucket (app, bucket) { + addBucket(app, bucket) { let count = 0; // TODO stop should be createdAt const { stop, toggles } = bucket; const toggleNames = Object.keys(toggles); - toggleNames.forEach((n) => { + toggleNames.forEach(n => { const entry = toggles[n]; this.lastHourProjection.add(n, entry); this.lastMinuteProjection.add(n, entry); - count += (entry.yes + entry.no); + count += entry.yes + entry.no; }); this.lastHourList.add(toggles, stop); @@ -100,13 +113,13 @@ module.exports = class UnleashClientMetrics { this.addSeenToggles(app, toggleNames); } - addSeenToggles (app, toggleNames) { + addSeenToggles(app, toggleNames) { toggleNames.forEach(t => { app.seenToggles[t] = true; }); } - destroy () { + destroy() { this.lastHourList.destroy(); this.lastMinuteList.destroy(); } diff --git a/lib/client-metrics/list.js b/lib/client-metrics/list.js index a77859124f..80f2150ec6 100644 --- a/lib/client-metrics/list.js +++ b/lib/client-metrics/list.js @@ -3,12 +3,12 @@ const { EventEmitter } = require('events'); class Node { - constructor (value) { + constructor(value) { this.value = value; this.next = null; } - link (next) { + link(next) { this.next = next; next.prev = this; return this; @@ -16,13 +16,13 @@ class Node { } module.exports = class List extends EventEmitter { - constructor () { + constructor() { super(); this.start = null; this.tail = null; } - add (obj) { + add(obj) { const node = new Node(obj); if (this.start) { this.start = node.link(this.start); @@ -33,7 +33,7 @@ module.exports = class List extends EventEmitter { return node; } - iterate (fn) { + iterate(fn) { if (!this.start) { return; } @@ -48,7 +48,7 @@ module.exports = class List extends EventEmitter { } } - iterateReverse (fn) { + iterateReverse(fn) { if (!this.tail) { return; } @@ -63,7 +63,7 @@ module.exports = class List extends EventEmitter { } } - reverseRemoveUntilTrue (fn) { + reverseRemoveUntilTrue(fn) { if (!this.tail) { return; } @@ -95,7 +95,7 @@ module.exports = class List extends EventEmitter { } } - toArray () { + toArray() { const result = []; if (this.start) { diff --git a/lib/client-metrics/list.test.js b/lib/client-metrics/list.test.js index c65415cdcd..04897b3185 100644 --- a/lib/client-metrics/list.test.js +++ b/lib/client-metrics/list.test.js @@ -1,9 +1,9 @@ 'use strict'; -const test = require('ava'); +const { test } = require('ava'); const List = require('./list'); -function getList () { +function getList() { const list = new List(); list.add(1); list.add(2); @@ -15,10 +15,10 @@ function getList () { return list; } -test('should emit "evicted" events for objects leaving list', (t) => { +test('should emit "evicted" events for objects leaving list', t => { const list = getList(); const evictedList = []; - list.on('evicted', (value) => { + list.on('evicted', value => { evictedList.push(value); }); @@ -43,7 +43,7 @@ test('should emit "evicted" events for objects leaving list', (t) => { t.true(evictedList.length === 8); }); -test('list should be able remove until given value', (t) => { +test('list should be able remove until given value', t => { const list = getList(); t.true(list.toArray().length === 7); @@ -58,7 +58,7 @@ test('list should be able remove until given value', (t) => { t.true(list.toArray().length === 3); }); -test('list can be cleared and re-add entries', (t) => { +test('list can be cleared and re-add entries', t => { const list = getList(); list.add(8); @@ -77,7 +77,7 @@ test('list can be cleared and re-add entries', (t) => { t.true(list.toArray().length === 3); }); -test('should not iterate empty list ', (t) => { +test('should not iterate empty list ', t => { const list = new List(); let iterateCount = 0; @@ -87,8 +87,7 @@ test('should not iterate empty list ', (t) => { t.true(iterateCount === 0); }); - -test('should iterate', (t) => { +test('should iterate', t => { const list = getList(); let iterateCount = 0; @@ -102,7 +101,7 @@ test('should iterate', (t) => { t.true(iterateCount === 4); }); -test('should reverse iterate', (t) => { +test('should reverse iterate', t => { const list = getList(); let iterateCount = 0; @@ -116,7 +115,7 @@ test('should reverse iterate', (t) => { t.true(iterateCount === 5); }); -test('should not reverse iterate empty list', (t) => { +test('should not reverse iterate empty list', t => { const list = new List(); let iterateCount = 0; diff --git a/lib/client-metrics/projection.js b/lib/client-metrics/projection.js index c72536e7bc..edfe84a417 100644 --- a/lib/client-metrics/projection.js +++ b/lib/client-metrics/projection.js @@ -1,15 +1,15 @@ 'use strict'; module.exports = class Projection { - constructor () { + constructor() { this.store = {}; } - getProjection () { + getProjection() { return this.store; } - add (name, countObj) { + add(name, countObj) { if (this.store[name]) { this.store[name].yes += countObj.yes; this.store[name].no += countObj.no; @@ -21,7 +21,7 @@ module.exports = class Projection { } } - substract (name, countObj) { + substract(name, countObj) { if (this.store[name]) { this.store[name].yes -= countObj.yes; this.store[name].no -= countObj.no; diff --git a/lib/client-metrics/ttl-list.js b/lib/client-metrics/ttl-list.js index 8049645b50..177f9409f1 100644 --- a/lib/client-metrics/ttl-list.js +++ b/lib/client-metrics/ttl-list.js @@ -6,11 +6,9 @@ const moment = require('moment'); // this list must have entries with sorted ttl range module.exports = class TTLList extends EventEmitter { - constructor ({ - interval = 1000, - expireAmount = 1, - expireType = 'hours', - } = {}) { + constructor( + { interval = 1000, expireAmount = 1, expireType = 'hours' } = {} + ) { super(); this.interval = interval; this.expireAmount = expireAmount; @@ -24,7 +22,7 @@ module.exports = class TTLList extends EventEmitter { this.startTimer(); } - startTimer () { + startTimer() { if (this.list) { this.timer = setTimeout(() => { if (this.list) { @@ -35,7 +33,7 @@ module.exports = class TTLList extends EventEmitter { } } - add (value, timestamp = new Date()) { + add(value, timestamp = new Date()) { const ttl = moment(timestamp).add(this.expireAmount, this.expireType); if (moment().isBefore(ttl)) { this.list.add({ ttl, value }); @@ -44,13 +42,15 @@ module.exports = class TTLList extends EventEmitter { } } - timedCheck () { + timedCheck() { const now = moment(); - this.list.reverseRemoveUntilTrue(({ value }) => now.isBefore(value.ttl)); + this.list.reverseRemoveUntilTrue(({ value }) => + now.isBefore(value.ttl) + ); this.startTimer(); } - destroy () { + destroy() { // https://github.com/nodejs/node/issues/9561 // clearTimeout(this.timer); // this.timer = null; diff --git a/lib/client-metrics/ttl-list.test.js b/lib/client-metrics/ttl-list.test.js index 0687ea929a..0d6d560d65 100644 --- a/lib/client-metrics/ttl-list.test.js +++ b/lib/client-metrics/ttl-list.test.js @@ -1,18 +1,18 @@ 'use strict'; -const test = require('ava'); +const { test } = require('ava'); const TTLList = require('./ttl-list'); const moment = require('moment'); const sinon = require('sinon'); -test.cb('should emit expire', (t) => { +test.cb('should emit expire', t => { const list = new TTLList({ interval: 20, expireAmount: 10, expireType: 'milliseconds', }); - list.on('expire', (entry) => { + list.on('expire', entry => { list.destroy(); t.true(entry.n === 1); t.end(); @@ -21,7 +21,7 @@ test.cb('should emit expire', (t) => { list.add({ n: 1 }); }); -test.cb('should slice off list', (t) => { +test.cb('should slice off list', t => { const clock = sinon.useFakeTimers(); const list = new TTLList({ @@ -30,7 +30,6 @@ test.cb('should slice off list', (t) => { expireType: 'milliseconds', }); - list.add({ n: '1' }, moment().add(1, 'milliseconds')); list.add({ n: '2' }, moment().add(50, 'milliseconds')); list.add({ n: '3' }, moment().add(200, 'milliseconds')); @@ -38,7 +37,7 @@ test.cb('should slice off list', (t) => { const expired = []; - list.on('expire', (entry) => { + list.on('expire', entry => { // console.timeEnd(entry.n); expired.push(entry); }); diff --git a/lib/db/client-applications-store.js b/lib/db/client-applications-store.js index e4d4a79993..f520e8af23 100644 --- a/lib/db/client-applications-store.js +++ b/lib/db/client-applications-store.js @@ -1,10 +1,19 @@ /* eslint camelcase:off */ 'use strict'; -const COLUMNS = ['app_name', 'created_at', 'updated_at', 'description', 'strategies', 'url', 'color', 'icon']; +const COLUMNS = [ + 'app_name', + 'created_at', + 'updated_at', + 'description', + 'strategies', + 'url', + 'color', + 'icon', +]; const TABLE = 'client_applications'; -const mapRow = (row) => ({ +const mapRow = row => ({ appName: row.app_name, createdAt: row.created_at, updatedAt: row.updated_at, @@ -25,24 +34,23 @@ const remapRow = (input, old = {}) => ({ strategies: JSON.stringify(input.strategies || old.strategies), }); - class ClientApplicationsDb { - constructor (db) { + constructor(db) { this.db = db; } - updateRow (details, prev) { + updateRow(details, prev) { details.updatedAt = 'now()'; return this.db(TABLE) .where('app_name', details.appName) .update(remapRow(details, prev)); } - insertNewRow (details) { + insertNewRow(details) { return this.db(TABLE).insert(remapRow(details)); } - upsert (data) { + upsert(data) { if (!data) { throw new Error('Missing data to add / update'); } @@ -58,20 +66,17 @@ class ClientApplicationsDb { }); } - getAll () { - return this.db - .select(COLUMNS) - .from(TABLE) - .map(mapRow); + getAll() { + return this.db.select(COLUMNS).from(TABLE).map(mapRow); } - getApplication (appName) { + getApplication(appName) { return this.db - .select(COLUMNS) - .where('app_name', appName) - .from(TABLE) - .map(mapRow) - .then(list => list[0]); + .select(COLUMNS) + .where('app_name', appName) + .from(TABLE) + .map(mapRow) + .then(list => list[0]); } /** @@ -83,19 +88,21 @@ class ClientApplicationsDb { * ) as foo * WHERE foo.strategyName = '"other"'; */ - getAppsForStrategy (strategyName) { + getAppsForStrategy(strategyName) { return this.db .select(COLUMNS) .from(TABLE) .map(mapRow) - .then(apps => apps - .filter(app => app.strategies.includes(strategyName))); + .then(apps => + apps.filter(app => app.strategies.includes(strategyName)) + ); } - getApplications (filter) { - return filter && filter.strategyName ? - this.getAppsForStrategy(filter.strategyName) : this.getAll(); + getApplications(filter) { + return filter && filter.strategyName + ? this.getAppsForStrategy(filter.strategyName) + : this.getAll(); } -}; +} module.exports = ClientApplicationsDb; diff --git a/lib/db/client-instance-store.js b/lib/db/client-instance-store.js index 6f99285a22..6d17af88cf 100644 --- a/lib/db/client-instance-store.js +++ b/lib/db/client-instance-store.js @@ -2,10 +2,16 @@ 'use strict'; const logger = require('../logger'); -const COLUMNS = ['app_name', 'instance_id', 'client_ip', 'last_seen', 'created_at']; +const COLUMNS = [ + 'app_name', + 'instance_id', + 'client_ip', + 'last_seen', + 'created_at', +]; const TABLE = 'client_instances'; -const mapRow = (row) => ({ +const mapRow = row => ({ appName: row.app_name, instanceId: row.instance_id, clientIp: row.client_ip, @@ -19,21 +25,23 @@ const mapRow = (row) => ({ // }); class ClientInstanceStore { - - constructor (db) { + constructor(db) { this.db = db; setTimeout(() => this._removeInstancesOlderThanTwoDays(), 10).unref(); - setInterval(() => this._removeInstancesOlderThanTwoDays(), 24 * 61 * 60 * 1000).unref(); + setInterval( + () => this._removeInstancesOlderThanTwoDays(), + 24 * 61 * 60 * 1000 + ).unref(); } - _removeInstancesOlderThanTwoDays () { + _removeInstancesOlderThanTwoDays() { this.db(TABLE) - .whereRaw('created_at < now() - interval \'2 days\'') + .whereRaw("created_at < now() - interval '2 days'") .del() - .then((res) => res > 0 && logger.info(`Deleted ${res} instances`)); + .then(res => res > 0 && logger.info(`Deleted ${res} instances`)); } - updateRow (details) { + updateRow(details) { return this.db(TABLE) .where('app_name', details.appName) .where('instance_id', details.instanceId) @@ -43,7 +51,7 @@ class ClientInstanceStore { }); } - insertNewRow (details) { + insertNewRow(details) { return this.db(TABLE).insert({ app_name: details.appName, instance_id: details.instanceId, @@ -51,7 +59,7 @@ class ClientInstanceStore { }); } - insert (details) { + insert(details) { return this.db(TABLE) .count('*') .where('app_name', details.appName) @@ -66,7 +74,7 @@ class ClientInstanceStore { }); } - getAll () { + getAll() { return this.db .select(COLUMNS) .from(TABLE) @@ -74,7 +82,7 @@ class ClientInstanceStore { .map(mapRow); } - getByAppName (appName) { + getByAppName(appName) { return this.db .select() .from(TABLE) @@ -83,7 +91,7 @@ class ClientInstanceStore { .map(mapRow); } - getApplications () { + getApplications() { return this.db .distinct('app_name') .select(['app_name']) @@ -91,6 +99,6 @@ class ClientInstanceStore { .orderBy('app_name', 'desc') .map(mapRow); } -}; +} module.exports = ClientInstanceStore; diff --git a/lib/db/client-metrics-db.js b/lib/db/client-metrics-db.js index b555606d06..37f57db3ac 100644 --- a/lib/db/client-metrics-db.js +++ b/lib/db/client-metrics-db.js @@ -5,46 +5,49 @@ const logger = require('../logger'); const METRICS_COLUMNS = ['id', 'created_at', 'metrics']; const TABLE = 'client_metrics'; -const mapRow = (row) => ({ +const mapRow = row => ({ id: row.id, createdAt: row.created_at, metrics: row.metrics, }); class ClientMetricsDb { - constructor (db) { + constructor(db) { this.db = db; // Clear old metrics regulary setTimeout(() => this.removeMetricsOlderThanOneHour(), 10).unref(); - setInterval(() => this.removeMetricsOlderThanOneHour(), 60 * 1000).unref(); + setInterval( + () => this.removeMetricsOlderThanOneHour(), + 60 * 1000 + ).unref(); } - removeMetricsOlderThanOneHour () { + removeMetricsOlderThanOneHour() { this.db(TABLE) - .whereRaw('created_at < now() - interval \'1 hour\'') + .whereRaw("created_at < now() - interval '1 hour'") .del() - .then((res) => res > 0 && logger.info(`Deleted ${res} metrics`)); + .then(res => res > 0 && logger.info(`Deleted ${res} metrics`)); } // Insert new client metrics - insert (metrics) { + insert(metrics) { return this.db(TABLE).insert({ metrics }); } // Used at startup to load all metrics last week into memory! - getMetricsLastHour () { + getMetricsLastHour() { return this.db .select(METRICS_COLUMNS) .from(TABLE) .limit(2000) - .whereRaw('created_at > now() - interval \'1 hour\'') + .whereRaw("created_at > now() - interval '1 hour'") .orderBy('created_at', 'asc') .map(mapRow); } // Used to poll for new metrics - getNewMetrics (lastKnownId) { + getNewMetrics(lastKnownId) { return this.db .select(METRICS_COLUMNS) .from(TABLE) @@ -53,6 +56,6 @@ class ClientMetricsDb { .orderBy('created_at', 'asc') .map(mapRow); } -}; +} module.exports = ClientMetricsDb; diff --git a/lib/db/client-metrics-store.js b/lib/db/client-metrics-store.js index 293906a054..18522b6390 100644 --- a/lib/db/client-metrics-store.js +++ b/lib/db/client-metrics-store.js @@ -7,31 +7,32 @@ const { EventEmitter } = require('events'); const TEN_SECONDS = 10 * 1000; class ClientMetricsStore extends EventEmitter { - - constructor (metricsDb, pollInterval = TEN_SECONDS) { + constructor(metricsDb, pollInterval = TEN_SECONDS) { super(); this.metricsDb = metricsDb; this.highestIdSeen = 0; // Build internal state - metricsDb.getMetricsLastHour() - .then((metrics) => this._emitMetrics(metrics)) + metricsDb + .getMetricsLastHour() + .then(metrics => this._emitMetrics(metrics)) .then(() => this._startPoller(pollInterval)) .then(() => this.emit('ready')) - .catch((err) => logger.error(err)); + .catch(err => logger.error(err)); } - _startPoller (pollInterval) { + _startPoller(pollInterval) { this.timer = setInterval(() => this._fetchNewAndEmit(), pollInterval); this.timer.unref(); } - _fetchNewAndEmit () { - this.metricsDb.getNewMetrics(this.highestIdSeen) - .then((metrics) => this._emitMetrics(metrics)); + _fetchNewAndEmit() { + this.metricsDb + .getNewMetrics(this.highestIdSeen) + .then(metrics => this._emitMetrics(metrics)); } - _emitMetrics (metrics) { + _emitMetrics(metrics) { if (metrics && metrics.length > 0) { this.highestIdSeen = metrics[metrics.length - 1].id; metrics.forEach(m => this.emit('metrics', m.metrics)); @@ -39,15 +40,15 @@ class ClientMetricsStore extends EventEmitter { } // Insert new client metrics - insert (metrics) { + insert(metrics) { return this.metricsDb.insert(metrics); } - destroy () { + destroy() { try { clearInterval(this.timer); } catch (e) {} } -}; +} module.exports = ClientMetricsStore; diff --git a/lib/db/client-metrics-store.test.js b/lib/db/client-metrics-store.test.js index 5364b1eca5..c8175e29b0 100644 --- a/lib/db/client-metrics-store.test.js +++ b/lib/db/client-metrics-store.test.js @@ -4,33 +4,31 @@ const { test } = require('ava'); const ClientMetricStore = require('./client-metrics-store'); const sinon = require('sinon'); -function getMockDb () { +function getMockDb() { const list = [ { id: 4, metrics: { appName: 'test' } }, { id: 3, metrics: { appName: 'test' } }, { id: 2, metrics: { appName: 'test' } }, ]; return { - getMetricsLastHour () { + getMetricsLastHour() { return Promise.resolve([{ id: 1, metrics: { appName: 'test' } }]); }, - getNewMetrics () { + getNewMetrics() { return Promise.resolve([list.pop() || { id: 0 }]); }, }; } - -test.cb('should call database on startup', (t) => { +test.cb('should call database on startup', t => { const mock = getMockDb(); const store = new ClientMetricStore(mock); t.plan(2); - - store.on('metrics', (metrics) => { + store.on('metrics', metrics => { t.true(store.highestIdSeen === 1); t.true(metrics.appName === 'test'); store.destroy(); @@ -39,15 +37,14 @@ test.cb('should call database on startup', (t) => { }); }); - -test.cb('should poll for updates', (t) => { +test.cb('should poll for updates', t => { const clock = sinon.useFakeTimers(); const mock = getMockDb(); const store = new ClientMetricStore(mock, 100); const metrics = []; - store.on('metrics', (m) => metrics.push(m)); + store.on('metrics', m => metrics.push(m)); t.true(metrics.length === 0); @@ -63,4 +60,3 @@ test.cb('should poll for updates', (t) => { }); }); }); - diff --git a/lib/db/db-pool.js b/lib/db/db-pool.js index 7fc9f3971f..fca93aafe4 100644 --- a/lib/db/db-pool.js +++ b/lib/db/db-pool.js @@ -2,7 +2,12 @@ const knex = require('knex'); -module.exports.createDb = function ({ databaseUrl, poolMin = 2, poolMax = 20, databaseSchema = 'public' }) { +module.exports.createDb = function({ + databaseUrl, + poolMin = 2, + poolMax = 20, + databaseSchema = 'public', +}) { const db = knex({ client: 'pg', connection: databaseUrl, diff --git a/lib/db/event-store.js b/lib/db/event-store.js index 8773ad0181..bee3771c93 100644 --- a/lib/db/event-store.js +++ b/lib/db/event-store.js @@ -5,22 +5,22 @@ const { EventEmitter } = require('events'); const EVENT_COLUMNS = ['id', 'type', 'created_by', 'created_at', 'data']; class EventStore extends EventEmitter { - - constructor (db) { + constructor(db) { super(); this.db = db; } - store (event) { - return this.db('events').insert({ - type: event.type, + store(event) { + return this.db('events') + .insert({ + type: event.type, created_by: event.createdBy, // eslint-disable-line - data: event.data, - }) - .then(() => this.emit(event.type, event)); + data: event.data, + }) + .then(() => this.emit(event.type, event)); } - getEvents () { + getEvents() { return this.db .select(EVENT_COLUMNS) .from('events') @@ -29,17 +29,17 @@ class EventStore extends EventEmitter { .map(this.rowToEvent); } - getEventsFilterByName (name) { + getEventsFilterByName(name) { return this.db - .select(EVENT_COLUMNS) - .from('events') - .limit(100) - .whereRaw('data ->> \'name\' = ?', [name]) - .orderBy('created_at', 'desc') - .map(this.rowToEvent); + .select(EVENT_COLUMNS) + .from('events') + .limit(100) + .whereRaw("data ->> 'name' = ?", [name]) + .orderBy('created_at', 'desc') + .map(this.rowToEvent); } - rowToEvent (row) { + rowToEvent(row) { return { id: row.id, type: row.type, @@ -48,7 +48,6 @@ class EventStore extends EventEmitter { data: row.data, }; } -}; +} module.exports = EventStore; - diff --git a/lib/db/feature-toggle-store.js b/lib/db/feature-toggle-store.js index ff1c8d2a6d..2c3fbe71bb 100644 --- a/lib/db/feature-toggle-store.js +++ b/lib/db/feature-toggle-store.js @@ -1,21 +1,40 @@ 'use strict'; -const { FEATURE_CREATED, FEATURE_UPDATED, FEATURE_ARCHIVED, FEATURE_REVIVED } = require('../event-type'); +const { + FEATURE_CREATED, + FEATURE_UPDATED, + FEATURE_ARCHIVED, + FEATURE_REVIVED, +} = require('../event-type'); const logger = require('../logger'); const NotFoundError = require('../error/notfound-error'); -const FEATURE_COLUMNS = ['name', 'description', 'enabled', 'strategies', 'created_at']; +const FEATURE_COLUMNS = [ + 'name', + 'description', + 'enabled', + 'strategies', + 'created_at', +]; const TABLE = 'features'; class FeatureToggleStore { - constructor (db, eventStore) { + constructor(db, eventStore) { this.db = db; - eventStore.on(FEATURE_CREATED, event => this._createFeature(event.data)); - eventStore.on(FEATURE_UPDATED, event => this._updateFeature(event.data)); - eventStore.on(FEATURE_ARCHIVED, event => this._archiveFeature(event.data)); - eventStore.on(FEATURE_REVIVED, event => this._reviveFeature(event.data)); + eventStore.on(FEATURE_CREATED, event => + this._createFeature(event.data) + ); + eventStore.on(FEATURE_UPDATED, event => + this._updateFeature(event.data) + ); + eventStore.on(FEATURE_ARCHIVED, event => + this._archiveFeature(event.data) + ); + eventStore.on(FEATURE_REVIVED, event => + this._reviveFeature(event.data) + ); } - getFeatures () { + getFeatures() { return this.db .select(FEATURE_COLUMNS) .from(TABLE) @@ -24,7 +43,7 @@ class FeatureToggleStore { .map(this.rowToFeature); } - getFeature (name) { + getFeature(name) { return this.db .first(FEATURE_COLUMNS) .from(TABLE) @@ -32,7 +51,7 @@ class FeatureToggleStore { .then(this.rowToFeature); } - getArchivedFeatures () { + getArchivedFeatures() { return this.db .select(FEATURE_COLUMNS) .from(TABLE) @@ -41,7 +60,7 @@ class FeatureToggleStore { .map(this.rowToFeature); } - rowToFeature (row) { + rowToFeature(row) { if (!row) { throw new NotFoundError('No feature toggle found'); } @@ -54,7 +73,7 @@ class FeatureToggleStore { }; } - eventDataToRow (data) { + eventDataToRow(data) { return { name: data.name, description: data.description, @@ -64,32 +83,40 @@ class FeatureToggleStore { }; } - _createFeature (data) { + _createFeature(data) { return this.db(TABLE) .insert(this.eventDataToRow(data)) - .catch(err => logger.error('Could not insert feature, error was: ', err)); + .catch(err => + logger.error('Could not insert feature, error was: ', err) + ); } - _updateFeature (data) { + _updateFeature(data) { return this.db(TABLE) .where({ name: data.name }) .update(this.eventDataToRow(data)) - .catch(err => logger.error('Could not update feature, error was: ', err)); + .catch(err => + logger.error('Could not update feature, error was: ', err) + ); } - _archiveFeature ({ name }) { + _archiveFeature({ name }) { return this.db(TABLE) .where({ name }) .update({ archived: 1 }) - .catch(err => logger.error('Could not archive feature, error was: ', err)); + .catch(err => + logger.error('Could not archive feature, error was: ', err) + ); } - _reviveFeature ({ name }) { + _reviveFeature({ name }) { return this.db(TABLE) .where({ name }) .update({ archived: 0, enabled: 0 }) - .catch(err => logger.error('Could not archive feature, error was: ', err)); + .catch(err => + logger.error('Could not archive feature, error was: ', err) + ); } -}; +} module.exports = FeatureToggleStore; diff --git a/lib/db/index.js b/lib/db/index.js index c7f196ddef..3db8f6e6cc 100644 --- a/lib/db/index.js +++ b/lib/db/index.js @@ -9,7 +9,7 @@ const ClientMetricsDb = require('./client-metrics-db'); const ClientMetricsStore = require('./client-metrics-store'); const ClientApplicationsStore = require('./client-applications-store'); -module.exports.createStores = (config) => { +module.exports.createStores = config => { const db = createDb(config); const eventStore = new EventStore(db); const clientMetricsDb = new ClientMetricsDb(db); diff --git a/lib/db/strategy-store.js b/lib/db/strategy-store.js index 027111ed62..bee8e41fd3 100644 --- a/lib/db/strategy-store.js +++ b/lib/db/strategy-store.js @@ -1,27 +1,32 @@ 'use strict'; -const { STRATEGY_CREATED, STRATEGY_DELETED, STRATEGY_UPDATED } = require('../event-type'); +const { + STRATEGY_CREATED, + STRATEGY_DELETED, + STRATEGY_UPDATED, +} = require('../event-type'); const logger = require('../logger'); const NotFoundError = require('../error/notfound-error'); const STRATEGY_COLUMNS = ['name', 'description', 'parameters']; const TABLE = 'strategies'; class StrategyStore { - constructor (db, eventStore) { + constructor(db, eventStore) { this.db = db; - eventStore.on(STRATEGY_CREATED, event => this._createStrategy(event.data)); - eventStore.on(STRATEGY_UPDATED, event => this._updateStrategy(event.data)); + eventStore.on(STRATEGY_CREATED, event => + this._createStrategy(event.data) + ); + eventStore.on(STRATEGY_UPDATED, event => + this._updateStrategy(event.data) + ); eventStore.on(STRATEGY_DELETED, event => { - db(TABLE) - .where('name', event.data.name) - .del() - .catch(err => { - logger.error('Could not delete strategy, error was: ', err); - }); + db(TABLE).where('name', event.data.name).del().catch(err => { + logger.error('Could not delete strategy, error was: ', err); + }); }); } - getStrategies () { + getStrategies() { return this.db .select(STRATEGY_COLUMNS) .from(TABLE) @@ -29,7 +34,7 @@ class StrategyStore { .map(this.rowToStrategy); } - getStrategy (name) { + getStrategy(name) { return this.db .first(STRATEGY_COLUMNS) .from(TABLE) @@ -37,7 +42,7 @@ class StrategyStore { .then(this.rowToStrategy); } - rowToStrategy (row) { + rowToStrategy(row) { if (!row) { throw new NotFoundError('No strategy found'); } @@ -49,7 +54,7 @@ class StrategyStore { }; } - eventDataToRow (data) { + eventDataToRow(data) { return { name: data.name, description: data.description, @@ -57,19 +62,22 @@ class StrategyStore { }; } - _createStrategy (data) { + _createStrategy(data) { this.db(TABLE) .insert(this.eventDataToRow(data)) - .catch(err => logger.error('Could not insert strategy, error was: ', err)); + .catch(err => + logger.error('Could not insert strategy, error was: ', err) + ); } - _updateStrategy (data) { + _updateStrategy(data) { this.db(TABLE) .where({ name: data.name }) .update(this.eventDataToRow(data)) - .catch(err => logger.error('Could not update strategy, error was: ', err)); + .catch(err => + logger.error('Could not update strategy, error was: ', err) + ); } -}; +} module.exports = StrategyStore; - diff --git a/lib/error/name-exists-error.js b/lib/error/name-exists-error.js index 518b0ba18a..644e054cef 100644 --- a/lib/error/name-exists-error.js +++ b/lib/error/name-exists-error.js @@ -1,7 +1,7 @@ 'use strict'; class NameExistsError extends Error { - constructor (message) { + constructor(message) { super(); Error.captureStackTrace(this, this.constructor); diff --git a/lib/error/notfound-error.js b/lib/error/notfound-error.js index 7bfff69860..1c4a92ab69 100644 --- a/lib/error/notfound-error.js +++ b/lib/error/notfound-error.js @@ -1,7 +1,7 @@ 'use strict'; class NotFoundError extends Error { - constructor (message) { + constructor(message) { super(); Error.captureStackTrace(this, this.constructor); diff --git a/lib/error/validate-request.js b/lib/error/validate-request.js index c7f07f56ac..21066c695e 100644 --- a/lib/error/validate-request.js +++ b/lib/error/validate-request.js @@ -2,7 +2,7 @@ const ValidationError = require('./validation-error'); -function validateRequest (req) { +function validateRequest(req) { return new Promise((resolve, reject) => { if (req.validationErrors()) { reject(new ValidationError('Invalid syntax')); diff --git a/lib/error/validation-error.js b/lib/error/validation-error.js index 7cf4688fcb..43995b34c4 100644 --- a/lib/error/validation-error.js +++ b/lib/error/validation-error.js @@ -1,7 +1,7 @@ 'use strict'; class ValidationError extends Error { - constructor (message) { + constructor(message) { super(); Error.captureStackTrace(this, this.constructor); diff --git a/lib/event-differ.js b/lib/event-differ.js index 1c41e245a4..b29a849fec 100644 --- a/lib/event-differ.js +++ b/lib/event-differ.js @@ -11,11 +11,7 @@ const { } = require('./event-type'); const diff = require('deep-diff').diff; -const strategyTypes = [ - STRATEGY_CREATED, - STRATEGY_DELETED, - STRATEGY_UPDATED, -]; +const strategyTypes = [STRATEGY_CREATED, STRATEGY_DELETED, STRATEGY_UPDATED]; const featureTypes = [ FEATURE_CREATED, @@ -24,7 +20,7 @@ const featureTypes = [ FEATURE_REVIVED, ]; -function baseTypeFor (event) { +function baseTypeFor(event) { if (featureTypes.indexOf(event.type) !== -1) { return 'features'; } else if (strategyTypes.indexOf(event.type) !== -1) { @@ -33,14 +29,15 @@ function baseTypeFor (event) { throw new Error(`unknown event type: ${JSON.stringify(event)}`); } -function groupByBaseTypeAndName (events) { +function groupByBaseTypeAndName(events) { const groups = {}; events.forEach(event => { const baseType = baseTypeFor(event); groups[baseType] = groups[baseType] || {}; - groups[baseType][event.data.name] = groups[baseType][event.data.name] || []; + groups[baseType][event.data.name] = + groups[baseType][event.data.name] || []; groups[baseType][event.data.name].push(event); }); @@ -48,7 +45,7 @@ function groupByBaseTypeAndName (events) { return groups; } -function eachConsecutiveEvent (events, callback) { +function eachConsecutiveEvent(events, callback) { const groups = groupByBaseTypeAndName(events); Object.keys(groups).forEach(baseType => { @@ -70,7 +67,7 @@ function eachConsecutiveEvent (events, callback) { }); } -function addDiffs (events) { +function addDiffs(events) { eachConsecutiveEvent(events, (left, right) => { if (right) { left.diffs = diff(right.data, left.data); @@ -81,7 +78,6 @@ function addDiffs (events) { }); } - module.exports = { addDiffs, }; diff --git a/lib/event-differ.test.js b/lib/event-differ.test.js index 9082961db9..3dd76dfdcf 100644 --- a/lib/event-differ.test.js +++ b/lib/event-differ.test.js @@ -1,6 +1,6 @@ 'use strict'; -const test = require('ava'); +const { test } = require('ava'); const eventDiffer = require('./event-differ'); const { FEATURE_CREATED, FEATURE_UPDATED } = require('./event-type'); const logger = require('./logger'); @@ -27,11 +27,23 @@ test('diffs a feature-update event', t => { const events = [ { type: FEATURE_UPDATED, - data: { name: feature, description: desc, strategy: 'default', enabled: true, parameters: { value: 2 } }, + data: { + name: feature, + description: desc, + strategy: 'default', + enabled: true, + parameters: { value: 2 }, + }, }, { type: FEATURE_CREATED, - data: { name: feature, description: desc, strategy: 'default', enabled: false, parameters: { value: 1 } }, + data: { + name: feature, + description: desc, + strategy: 'default', + enabled: false, + parameters: { value: 1 }, + }, }, ]; @@ -57,19 +69,43 @@ test('diffs only against features with the same name', t => { const events = [ { type: FEATURE_UPDATED, - data: { name: 'bar', description: 'desc', strategy: 'default', enabled: true, parameters: {} }, + data: { + name: 'bar', + description: 'desc', + strategy: 'default', + enabled: true, + parameters: {}, + }, }, { type: FEATURE_UPDATED, - data: { name: 'foo', description: 'desc', strategy: 'default', enabled: false, parameters: {} }, + data: { + name: 'foo', + description: 'desc', + strategy: 'default', + enabled: false, + parameters: {}, + }, }, { type: FEATURE_CREATED, - data: { name: 'bar', description: 'desc', strategy: 'default', enabled: false, parameters: {} }, + data: { + name: 'bar', + description: 'desc', + strategy: 'default', + enabled: false, + parameters: {}, + }, }, { type: FEATURE_CREATED, - data: { name: 'foo', description: 'desc', strategy: 'default', enabled: true, parameters: {} }, + data: { + name: 'foo', + description: 'desc', + strategy: 'default', + enabled: true, + parameters: {}, + }, }, ]; @@ -85,11 +121,23 @@ test('sets an empty array of diffs if nothing was changed', t => { const events = [ { type: FEATURE_UPDATED, - data: { name: 'foo', description: 'desc', strategy: 'default', enabled: true, parameters: {} }, + data: { + name: 'foo', + description: 'desc', + strategy: 'default', + enabled: true, + parameters: {}, + }, }, { type: FEATURE_CREATED, - data: { name: 'foo', description: 'desc', strategy: 'default', enabled: true, parameters: {} }, + data: { + name: 'foo', + description: 'desc', + strategy: 'default', + enabled: true, + parameters: {}, + }, }, ]; @@ -101,11 +149,16 @@ test('sets diffs to null if there was nothing to diff against', t => { const events = [ { type: FEATURE_UPDATED, - data: { name: 'foo', description: 'desc', strategy: 'default', enabled: true, parameters: {} }, + data: { + name: 'foo', + description: 'desc', + strategy: 'default', + enabled: true, + parameters: {}, + }, }, ]; eventDiffer.addDiffs(events); t.true(events[0].diffs === null); }); - diff --git a/lib/extract-user.js b/lib/extract-user.js index 311548def7..a6f3fdcbc4 100644 --- a/lib/extract-user.js +++ b/lib/extract-user.js @@ -1,6 +1,6 @@ 'use strict'; -function extractUsername (req) { +function extractUsername(req) { return req.cookies.username || 'unknown'; } module.exports = extractUsername; diff --git a/lib/logger.js b/lib/logger.js index fde8342a70..553ee98d48 100644 --- a/lib/logger.js +++ b/lib/logger.js @@ -2,9 +2,7 @@ const log4js = require('log4js'); log4js.configure({ - appenders: [ - { type: 'console' }, - ], + appenders: [{ type: 'console' }], }); const logger = log4js.getLogger('unleash'); diff --git a/lib/metrics.js b/lib/metrics.js index 599facbff5..551614eed8 100644 --- a/lib/metrics.js +++ b/lib/metrics.js @@ -9,9 +9,14 @@ exports.startMonitoring = (enable, eventBus) => { const client = require('prom-client'); - const requestDuration = new client.Summary('http_request_duration_milliseconds', 'App response time', ['path', 'method', 'status'], { - percentiles: [0.1, 0.5, 0.9, 0.99], - }); + const requestDuration = new client.Summary( + 'http_request_duration_milliseconds', + 'App response time', + ['path', 'method', 'status'], + { + percentiles: [0.1, 0.5, 0.9, 0.99], + } + ); eventBus.on(events.REQUEST_TIME, ({ path, method, time, statusCode }) => { requestDuration.labels(path, method, statusCode).observe(time); diff --git a/lib/metrics.test.js b/lib/metrics.test.js index 26161b10bb..5fd25a2ae5 100644 --- a/lib/metrics.test.js +++ b/lib/metrics.test.js @@ -1,6 +1,6 @@ 'use strict'; -const test = require('ava'); +const { test } = require('ava'); const { EventEmitter } = require('events'); const eventBus = new EventEmitter(); const { REQUEST_TIME } = require('./events'); @@ -9,8 +9,16 @@ const prometheusRegister = require('prom-client/lib/register'); test('should collect metrics for requests', t => { startMonitoring(true, eventBus); - eventBus.emit(REQUEST_TIME, { path: 'somePath', method: 'GET', statusCode: 200, time: 1337 }); + eventBus.emit(REQUEST_TIME, { + path: 'somePath', + method: 'GET', + statusCode: 200, + time: 1337, + }); const metrics = prometheusRegister.metrics(); - t.regex(metrics, /http_request_duration_milliseconds{quantile="0.99",status="200",method="GET",path="somePath"} 1337/); + t.regex( + metrics, + /http_request_duration_milliseconds{quantile="0.99",status="200",method="GET",path="somePath"} 1337/ + ); }); diff --git a/lib/options.js b/lib/options.js index f6f63c28f5..72362fee0f 100644 --- a/lib/options.js +++ b/lib/options.js @@ -14,16 +14,19 @@ const DEFAULT_OPTIONS = { }; module.exports = { - createOptions: (opts) => { + createOptions: opts => { const options = Object.assign({}, DEFAULT_OPTIONS, opts); // If we are running in development we should assume local db if (isDev() && !options.databaseUrl) { - options.databaseUrl = 'postgres://unleash_user:passord@localhost:5432/unleash'; + options.databaseUrl = + 'postgres://unleash_user:passord@localhost:5432/unleash'; } if (!options.databaseUrl) { - throw new Error('You must either pass databaseUrl option or set environemnt variable DATABASE_URL'); + throw new Error( + 'You must either pass databaseUrl option or set environemnt variable DATABASE_URL' + ); } return options; }, diff --git a/lib/options.test.js b/lib/options.test.js index c6400659e8..3d853f6ee8 100644 --- a/lib/options.test.js +++ b/lib/options.test.js @@ -1,6 +1,6 @@ 'use strict'; -const test = require('ava'); +const { test } = require('ava'); delete process.env.DATABASE_URL; @@ -18,7 +18,10 @@ test('should set default databaseUrl for develpment', t => { const options = createOptions({}); - t.true(options.databaseUrl === 'postgres://unleash_user:passord@localhost:5432/unleash'); + t.true( + options.databaseUrl === + 'postgres://unleash_user:passord@localhost:5432/unleash' + ); }); test('should not override provided options', t => { diff --git a/lib/server-impl.js b/lib/server-impl.js index b251461fbc..1734cac4de 100644 --- a/lib/server-impl.js +++ b/lib/server-impl.js @@ -10,15 +10,18 @@ const { startMonitoring } = require('./metrics'); const { createStores } = require('./db'); const { createOptions } = require('./options'); -function createApp (options) { +function createApp(options) { // Database dependecies (statefull) const stores = createStores(options); const eventBus = new EventEmitter(); - const config = Object.assign({ - stores, - eventBus, - }, options); + const config = Object.assign( + { + stores, + eventBus, + }, + options + ); const app = getApp(config); const server = app.listen(app.get('port'), () => { @@ -30,7 +33,7 @@ function createApp (options) { return { app, server, eventBus }; } -function start (opts) { +function start(opts) { const options = createOptions(opts); return migrator({ databaseUrl: options.databaseUrl }) diff --git a/lib/server-impl.test.js b/lib/server-impl.test.js index 0a295f2900..eed8532cd5 100644 --- a/lib/server-impl.test.js +++ b/lib/server-impl.test.js @@ -1,6 +1,6 @@ 'use strict'; -const test = require('ava'); +const { test } = require('ava'); const proxyquire = require('proxyquire'); const getApp = proxyquire('./app', { @@ -13,21 +13,21 @@ const getApp = proxyquire('./app', { const serverImpl = proxyquire('./server-impl', { './app': getApp, './metrics': { - startMonitoring (o) { + startMonitoring(o) { return o; }, }, './db': { - createStores (o) { + createStores(o) { return o; }, }, './options': { - createOptions (o) { + createOptions(o) { return o; }, }, - '../migrator' () { + '../migrator'() { return Promise.resolve(); }, });