mirror of
https://github.com/Unleash/unleash.git
synced 2025-02-23 00:22:19 +01:00
add tests, rename folders to ava defaults for helpers/fixtures, remove migration og
This commit is contained in:
parent
df99a547e8
commit
bb4cf30d22
@ -12,10 +12,53 @@ test('should work without state', (t) => {
|
|||||||
|
|
||||||
t.truthy(metrics.getMetricsOverview());
|
t.truthy(metrics.getMetricsOverview());
|
||||||
t.truthy(metrics.getTogglesMetrics());
|
t.truthy(metrics.getTogglesMetrics());
|
||||||
|
t.truthy(metrics.toJSON());
|
||||||
|
|
||||||
metrics.destroy();
|
metrics.destroy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test.cb('data should expire', (t) => {
|
||||||
|
const clock = sinon.useFakeTimers();
|
||||||
|
|
||||||
|
const metrics = new UnleashClientMetrics();
|
||||||
|
|
||||||
|
metrics.addPayload({
|
||||||
|
appName,
|
||||||
|
instanceId,
|
||||||
|
bucket: {
|
||||||
|
start: Date.now() - 2000,
|
||||||
|
stop: Date.now() - 1000,
|
||||||
|
toggles: {
|
||||||
|
toggleX: {
|
||||||
|
yes: 123,
|
||||||
|
no: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
let lastHourExpires = 0;
|
||||||
|
metrics.lastHourList.on('expire', () => {
|
||||||
|
lastHourExpires++;
|
||||||
|
});
|
||||||
|
|
||||||
|
let lastMinExpires = 0;
|
||||||
|
metrics.lastMinuteList.on('expire', () => {
|
||||||
|
lastMinExpires++;
|
||||||
|
});
|
||||||
|
|
||||||
|
clock.tick(60 * 1000);
|
||||||
|
t.true(lastMinExpires === 1);
|
||||||
|
t.true(lastHourExpires === 0);
|
||||||
|
|
||||||
|
clock.tick(60 * 60 * 1000);
|
||||||
|
t.true(lastMinExpires === 1);
|
||||||
|
t.true(lastHourExpires === 1);
|
||||||
|
|
||||||
|
sinon.restore();
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
|
||||||
test('addPayload', t => {
|
test('addPayload', t => {
|
||||||
const metrics = new UnleashClientMetrics();
|
const metrics = new UnleashClientMetrics();
|
||||||
metrics.addPayload({
|
metrics.addPayload({
|
||||||
|
@ -15,13 +15,6 @@ class Node {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* linked list
|
|
||||||
* ranged list, assumes start to end(tail) is a known order
|
|
||||||
* remove() is only implemented in reverse order for the usecase
|
|
||||||
* emits events on eviction
|
|
||||||
*/
|
|
||||||
module.exports = class List extends EventEmitter {
|
module.exports = class List extends EventEmitter {
|
||||||
constructor () {
|
constructor () {
|
||||||
super();
|
super();
|
||||||
@ -116,17 +109,17 @@ module.exports = class List extends EventEmitter {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
toArrayReverse () {
|
// toArrayReverse () {
|
||||||
const result = [];
|
// const result = [];
|
||||||
|
|
||||||
if (this.tail) {
|
// if (this.tail) {
|
||||||
let cursor = this.tail;
|
// let cursor = this.tail;
|
||||||
while (cursor) {
|
// while (cursor) {
|
||||||
result.push(cursor.value);
|
// result.push(cursor.value);
|
||||||
cursor = cursor.prev;
|
// cursor = cursor.prev;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
return result;
|
// return result;
|
||||||
}
|
// }
|
||||||
};
|
};
|
||||||
|
@ -77,6 +77,16 @@ test('list can be cleared and re-add entries', (t) => {
|
|||||||
t.true(list.toArray().length === 3);
|
t.true(list.toArray().length === 3);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should not iterate empty list ', (t) => {
|
||||||
|
const list = new List();
|
||||||
|
|
||||||
|
let iterateCount = 0;
|
||||||
|
list.iterate(() => {
|
||||||
|
iterateCount++;
|
||||||
|
});
|
||||||
|
t.true(iterateCount === 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
test('should iterate', (t) => {
|
test('should iterate', (t) => {
|
||||||
const list = getList();
|
const list = getList();
|
||||||
@ -105,3 +115,13 @@ test('should reverse iterate', (t) => {
|
|||||||
});
|
});
|
||||||
t.true(iterateCount === 5);
|
t.true(iterateCount === 5);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should not reverse iterate empty list', (t) => {
|
||||||
|
const list = new List();
|
||||||
|
|
||||||
|
let iterateCount = 0;
|
||||||
|
list.iterateReverse(() => {
|
||||||
|
iterateCount++;
|
||||||
|
});
|
||||||
|
t.true(iterateCount === 0);
|
||||||
|
});
|
||||||
|
@ -1,17 +1,19 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const POLL_INTERVAL = 10000;
|
|
||||||
const { EventEmitter } = require('events');
|
const { EventEmitter } = require('events');
|
||||||
|
|
||||||
module.exports = class UnleashClientMetrics extends EventEmitter {
|
module.exports = class UnleashClientMetrics extends EventEmitter {
|
||||||
constructor (metricsDb) {
|
constructor (metricsDb, interval = 10000) {
|
||||||
super();
|
super();
|
||||||
|
this.interval = interval;
|
||||||
this.db = metricsDb;
|
this.db = metricsDb;
|
||||||
this.highestIdSeen = 0;
|
this.highestIdSeen = 0;
|
||||||
this.db.getMetricsLastHour().then(metrics => {
|
this.db.getMetricsLastHour().then(metrics => {
|
||||||
this.addMetrics(metrics);
|
this.addMetrics(metrics);
|
||||||
this.startPoller();
|
this.startPoller();
|
||||||
|
this.emit('ready');
|
||||||
});
|
});
|
||||||
|
this.timer = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
addMetrics (metrics) {
|
addMetrics (metrics) {
|
||||||
@ -22,13 +24,20 @@ module.exports = class UnleashClientMetrics extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
startPoller () {
|
startPoller () {
|
||||||
setInterval(() => {
|
this.timer = setInterval(() => {
|
||||||
this.db.getNewMetrics(this.highestIdSeen)
|
this.db.getNewMetrics(this.highestIdSeen)
|
||||||
.then(metrics => this.addMetrics(metrics));
|
.then(metrics => this.addMetrics(metrics));
|
||||||
}, POLL_INTERVAL).unref();
|
}, this.interval);
|
||||||
|
this.timer.unref();
|
||||||
}
|
}
|
||||||
|
|
||||||
insert (metrics) {
|
insert (metrics) {
|
||||||
return this.db.insert(metrics);
|
return this.db.insert(metrics);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
destroy () {
|
||||||
|
try {
|
||||||
|
clearTimeout(this.timer);
|
||||||
|
} catch (e) {}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
66
lib/client-metrics/service.test.js
Normal file
66
lib/client-metrics/service.test.js
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const { test } = require('ava');
|
||||||
|
const MetricsService = require('./service');
|
||||||
|
const sinon = require('sinon');
|
||||||
|
|
||||||
|
function getMockDb () {
|
||||||
|
const list = [{ id: 2 }, { id: 3 }, { id: 4 }];
|
||||||
|
const db = {
|
||||||
|
getMetricsLastHour () {
|
||||||
|
return Promise.resolve([{ id: 1 }]);
|
||||||
|
},
|
||||||
|
|
||||||
|
getNewMetrics () {
|
||||||
|
return Promise.resolve([list.pop() || { id: 0 }]);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
db,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
test.cb('should call database on startup', (t) => {
|
||||||
|
const mock = getMockDb();
|
||||||
|
const service = new MetricsService(mock.db);
|
||||||
|
t.plan(2);
|
||||||
|
|
||||||
|
service.on('metrics', ([metric]) => {
|
||||||
|
t.true(service.highestIdSeen === 1);
|
||||||
|
t.true(metric.id === 1);
|
||||||
|
t.end();
|
||||||
|
service.destroy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test.cb('should poll for updates', (t) => {
|
||||||
|
const clock = sinon.useFakeTimers();
|
||||||
|
|
||||||
|
const mock = getMockDb();
|
||||||
|
const service = new MetricsService(mock.db, 100);
|
||||||
|
|
||||||
|
const metrics = [];
|
||||||
|
service.on('metrics', (_metrics) => {
|
||||||
|
_metrics.forEach(m => m && metrics.push(m));
|
||||||
|
});
|
||||||
|
|
||||||
|
t.true(metrics.length === 0);
|
||||||
|
|
||||||
|
service.on('ready', () => {
|
||||||
|
t.true(metrics.length === 1);
|
||||||
|
|
||||||
|
clock.tick(300);
|
||||||
|
clock.restore();
|
||||||
|
|
||||||
|
process.nextTick(() => {
|
||||||
|
t.true(metrics.length === 4);
|
||||||
|
t.true(metrics[0].id === 1);
|
||||||
|
t.true(metrics[1].id === 4);
|
||||||
|
t.true(metrics[2].id === 3);
|
||||||
|
t.true(metrics[3].id === 2);
|
||||||
|
service.destroy();
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -5,13 +5,14 @@ const List = require('./list');
|
|||||||
const moment = require('moment');
|
const moment = require('moment');
|
||||||
|
|
||||||
// this list must have entries with sorted ttl range
|
// this list must have entries with sorted ttl range
|
||||||
module.exports = class FIFOTTLList extends EventEmitter {
|
module.exports = class TTLList extends EventEmitter {
|
||||||
constructor ({
|
constructor ({
|
||||||
interval = 1000,
|
interval = 1000,
|
||||||
expireAmount = 1,
|
expireAmount = 1,
|
||||||
expireType = 'hours',
|
expireType = 'hours',
|
||||||
} = {}) {
|
} = {}) {
|
||||||
super();
|
super();
|
||||||
|
this.interval = interval;
|
||||||
this.expireAmount = expireAmount;
|
this.expireAmount = expireAmount;
|
||||||
this.expireType = expireType;
|
this.expireType = expireType;
|
||||||
|
|
||||||
@ -20,10 +21,18 @@ module.exports = class FIFOTTLList extends EventEmitter {
|
|||||||
this.list.on('evicted', ({ value, ttl }) => {
|
this.list.on('evicted', ({ value, ttl }) => {
|
||||||
this.emit('expire', value, ttl);
|
this.emit('expire', value, ttl);
|
||||||
});
|
});
|
||||||
|
this.startTimer();
|
||||||
|
}
|
||||||
|
|
||||||
this.timer = setInterval(() => {
|
startTimer () {
|
||||||
this.timedCheck();
|
if (this.list) {
|
||||||
}, interval);
|
this.timer = setTimeout(() => {
|
||||||
|
if (this.list) {
|
||||||
|
this.timedCheck();
|
||||||
|
}
|
||||||
|
}, this.interval);
|
||||||
|
this.timer.unref();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
add (value, timestamp = new Date()) {
|
add (value, timestamp = new Date()) {
|
||||||
@ -34,11 +43,13 @@ module.exports = class FIFOTTLList extends EventEmitter {
|
|||||||
timedCheck () {
|
timedCheck () {
|
||||||
const now = moment(new Date());
|
const now = moment(new Date());
|
||||||
this.list.reverseRemoveUntilTrue(({ value }) => now.isBefore(value.ttl));
|
this.list.reverseRemoveUntilTrue(({ value }) => now.isBefore(value.ttl));
|
||||||
|
this.startTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
destroy () {
|
destroy () {
|
||||||
clearTimeout(this.timer);
|
// https://github.com/nodejs/node/issues/9561
|
||||||
delete this.timer;
|
// clearTimeout(this.timer);
|
||||||
|
// this.timer = null;
|
||||||
this.list = null;
|
this.list = null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const test = require('ava');
|
const test = require('ava');
|
||||||
const mapper = require('../../../lib/helper/legacy-feature-mapper');
|
const mapper = require('./legacy-feature-mapper');
|
||||||
|
|
||||||
test('adds old fields to feature', t => {
|
test('adds old fields to feature', t => {
|
||||||
const feature = {
|
const feature = {
|
@ -8,7 +8,7 @@ const ValidationError = require('../error/validation-error.js');
|
|||||||
const validateRequest = require('../error/validate-request');
|
const validateRequest = require('../error/validate-request');
|
||||||
const extractUser = require('../extract-user');
|
const extractUser = require('../extract-user');
|
||||||
|
|
||||||
const legacyFeatureMapper = require('../helper/legacy-feature-mapper');
|
const legacyFeatureMapper = require('../data-helper/legacy-feature-mapper');
|
||||||
const version = 1;
|
const version = 1;
|
||||||
|
|
||||||
const handleErrors = (req, res, error) => {
|
const handleErrors = (req, res, error) => {
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
const joi = require('joi');
|
const joi = require('joi');
|
||||||
|
|
||||||
const clientMetricsSchema = joi.object().keys({
|
const clientMetricsSchema = joi.object().keys({
|
||||||
@ -21,4 +23,4 @@ const clientRegisterSchema = joi.object().keys({
|
|||||||
interval: joi.number().required(),
|
interval: joi.number().required(),
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = { clientMetricsSchema, clientRegisterSchema }
|
module.exports = { clientMetricsSchema, clientRegisterSchema }
|
||||||
|
@ -39,7 +39,7 @@
|
|||||||
"start:dev:pg-chain": "export DATABASE_URL=postgres://$PGUSER:$PGPASSWORD@localhost:$PGPORT/postgres ; db-migrate up && npm run start:dev",
|
"start:dev:pg-chain": "export DATABASE_URL=postgres://$PGUSER:$PGPASSWORD@localhost:$PGPORT/postgres ; db-migrate up && npm run start:dev",
|
||||||
"db-migrate": "db-migrate up",
|
"db-migrate": "db-migrate up",
|
||||||
"db-migrate:down": "db-migrate down",
|
"db-migrate:down": "db-migrate down",
|
||||||
"test": "PORT=4243 ava **/**/*test.js",
|
"test": "PORT=4243 ava test lib/*/*.test.js",
|
||||||
"test:docker": "./scripts/docker-postgres.sh",
|
"test:docker": "./scripts/docker-postgres.sh",
|
||||||
"test:watch": "npm run test -- --watch",
|
"test:watch": "npm run test -- --watch",
|
||||||
"test:pg-virtualenv": "pg_virtualenv npm run test:pg-virtualenv-chai",
|
"test:pg-virtualenv": "pg_virtualenv npm run test:pg-virtualenv-chai",
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const test = require('ava');
|
const test = require('ava');
|
||||||
const { setupApp } = require('./util/test-helper');
|
const { setupApp } = require('./helpers/test-helper');
|
||||||
const logger = require('../../lib/logger');
|
const logger = require('../../lib/logger');
|
||||||
|
|
||||||
test.beforeEach(() => {
|
test.beforeEach(() => {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const { test } = require('ava');
|
const { test } = require('ava');
|
||||||
const { setupApp } = require('./util/test-helper');
|
const { setupApp } = require('./helpers/test-helper');
|
||||||
const logger = require('../../lib/logger');
|
const logger = require('../../lib/logger');
|
||||||
|
|
||||||
test.beforeEach(() => {
|
test.beforeEach(() => {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const test = require('ava');
|
const test = require('ava');
|
||||||
const { setupApp } = require('./util/test-helper');
|
const { setupApp } = require('./helpers/test-helper');
|
||||||
const logger = require('../../lib/logger');
|
const logger = require('../../lib/logger');
|
||||||
|
|
||||||
test.beforeEach(() => {
|
test.beforeEach(() => {
|
||||||
|
@ -7,6 +7,7 @@ const migrator = require('../../../migrator');
|
|||||||
const { createStores } = require('../../../lib/db');
|
const { createStores } = require('../../../lib/db');
|
||||||
const { createDb } = require('../../../lib/db/db-pool');
|
const { createDb } = require('../../../lib/db/db-pool');
|
||||||
const _app = require('../../../app');
|
const _app = require('../../../app');
|
||||||
|
require('db-migrate-shared').log.silence(true);
|
||||||
|
|
||||||
// because of migrator bug
|
// because of migrator bug
|
||||||
delete process.env.DATABASE_URL;
|
delete process.env.DATABASE_URL;
|
@ -1,6 +1,6 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
const test = require('ava');
|
const test = require('ava');
|
||||||
const { setupApp } = require('./util/test-helper');
|
const { setupApp } = require('./helpers/test-helper');
|
||||||
const logger = require('../../lib/logger');
|
const logger = require('../../lib/logger');
|
||||||
|
|
||||||
test.beforeEach(() => {
|
test.beforeEach(() => {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const test = require('ava');
|
const test = require('ava');
|
||||||
const { setupApp } = require('./util/test-helper');
|
const { setupApp } = require('./helpers/test-helper');
|
||||||
const logger = require('../../lib/logger');
|
const logger = require('../../lib/logger');
|
||||||
|
|
||||||
test.beforeEach(() => {
|
test.beforeEach(() => {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const test = require('ava');
|
const test = require('ava');
|
||||||
const { setupApp } = require('./util/test-helper');
|
const { setupApp } = require('./helpers/test-helper');
|
||||||
const logger = require('../../lib/logger');
|
const logger = require('../../lib/logger');
|
||||||
|
|
||||||
test.beforeEach(() => {
|
test.beforeEach(() => {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const test = require('ava');
|
const test = require('ava');
|
||||||
const store = require('./mocks/store');
|
const store = require('./fixtures/store');
|
||||||
const supertest = require('supertest');
|
const supertest = require('supertest');
|
||||||
const logger = require('../../../lib/logger');
|
const logger = require('../../../lib/logger');
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const test = require('ava');
|
const test = require('ava');
|
||||||
const store = require('./mocks/store');
|
const store = require('./fixtures/store');
|
||||||
const supertest = require('supertest');
|
const supertest = require('supertest');
|
||||||
const logger = require('../../../lib/logger');
|
const logger = require('../../../lib/logger');
|
||||||
|
|
||||||
@ -29,7 +29,6 @@ test('should give 500 when db is failing', t => {
|
|||||||
db.select = () => ({
|
db.select = () => ({
|
||||||
from: () => Promise.reject(new Error('db error')),
|
from: () => Promise.reject(new Error('db error')),
|
||||||
});
|
});
|
||||||
|
|
||||||
return request
|
return request
|
||||||
.get('/health')
|
.get('/health')
|
||||||
.expect(500)
|
.expect(500)
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const test = require('ava');
|
const test = require('ava');
|
||||||
const store = require('./mocks/store');
|
const store = require('./fixtures/store');
|
||||||
const supertest = require('supertest');
|
const supertest = require('supertest');
|
||||||
const logger = require('../../../lib/logger');
|
const logger = require('../../../lib/logger');
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const test = require('ava');
|
const test = require('ava');
|
||||||
const store = require('./mocks/store');
|
const store = require('./fixtures/store');
|
||||||
const supertest = require('supertest');
|
const supertest = require('supertest');
|
||||||
const logger = require('../../../lib/logger');
|
const logger = require('../../../lib/logger');
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user