2016-11-13 18:14:29 +01:00
|
|
|
'use strict';
|
|
|
|
|
|
|
|
const { test } = require('ava');
|
|
|
|
const UnleashClientMetrics = require('./index');
|
2016-12-29 11:09:01 +01:00
|
|
|
const moment = require('moment');
|
2016-11-13 18:14:29 +01:00
|
|
|
const sinon = require('sinon');
|
|
|
|
|
2016-11-28 17:11:11 +01:00
|
|
|
const { EventEmitter } = require('events');
|
|
|
|
|
2016-11-13 18:14:29 +01:00
|
|
|
const appName = 'appName';
|
|
|
|
const instanceId = 'instanceId';
|
|
|
|
|
2017-06-28 10:17:14 +02:00
|
|
|
test('should work without state', t => {
|
2016-11-28 17:11:11 +01:00
|
|
|
const store = new EventEmitter();
|
|
|
|
const metrics = new UnleashClientMetrics(store);
|
2016-11-13 18:14:29 +01:00
|
|
|
|
2016-12-05 13:26:53 +01:00
|
|
|
t.truthy(metrics.getAppsWithToggles());
|
2016-11-13 18:14:29 +01:00
|
|
|
t.truthy(metrics.getTogglesMetrics());
|
|
|
|
|
|
|
|
metrics.destroy();
|
|
|
|
});
|
|
|
|
|
2017-06-28 10:17:14 +02:00
|
|
|
test.cb('data should expire', t => {
|
2016-11-13 20:33:23 +01:00
|
|
|
const clock = sinon.useFakeTimers();
|
|
|
|
|
2016-11-28 17:11:11 +01:00
|
|
|
const store = new EventEmitter();
|
|
|
|
const metrics = new UnleashClientMetrics(store);
|
2016-11-13 20:33:23 +01:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
2016-12-29 11:07:06 +01:00
|
|
|
clock.restore();
|
2016-11-13 20:33:23 +01:00
|
|
|
t.end();
|
|
|
|
});
|
|
|
|
|
2016-11-28 17:11:11 +01:00
|
|
|
test('should listen to metrics from store', t => {
|
|
|
|
const store = new EventEmitter();
|
|
|
|
const metrics = new UnleashClientMetrics(store);
|
2016-12-04 14:09:37 +01:00
|
|
|
store.emit('metrics', {
|
2016-11-13 18:14:29 +01:00
|
|
|
appName,
|
|
|
|
instanceId,
|
|
|
|
bucket: {
|
|
|
|
start: new Date(),
|
|
|
|
stop: new Date(),
|
|
|
|
toggles: {
|
|
|
|
toggleX: {
|
|
|
|
yes: 123,
|
|
|
|
no: 0,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
2016-11-13 21:25:37 +01:00
|
|
|
t.truthy(metrics.apps[appName].count === 123);
|
2016-11-13 18:14:29 +01:00
|
|
|
t.truthy(metrics.globalCount === 123);
|
|
|
|
|
2017-06-28 10:17:14 +02:00
|
|
|
t.deepEqual(metrics.getTogglesMetrics().lastHour.toggleX, {
|
|
|
|
yes: 123,
|
|
|
|
no: 0,
|
|
|
|
});
|
|
|
|
t.deepEqual(metrics.getTogglesMetrics().lastMinute.toggleX, {
|
|
|
|
yes: 123,
|
|
|
|
no: 0,
|
|
|
|
});
|
2016-11-13 18:14:29 +01:00
|
|
|
|
|
|
|
metrics.addPayload({
|
|
|
|
appName,
|
|
|
|
instanceId,
|
|
|
|
bucket: {
|
|
|
|
start: new Date(),
|
|
|
|
stop: new Date(),
|
|
|
|
toggles: {
|
|
|
|
toggleX: {
|
|
|
|
yes: 10,
|
|
|
|
no: 10,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
|
|
|
t.truthy(metrics.globalCount === 143);
|
2017-06-28 10:17:14 +02:00
|
|
|
t.deepEqual(metrics.getTogglesMetrics().lastHour.toggleX, {
|
|
|
|
yes: 133,
|
|
|
|
no: 10,
|
|
|
|
});
|
|
|
|
t.deepEqual(metrics.getTogglesMetrics().lastMinute.toggleX, {
|
|
|
|
yes: 133,
|
|
|
|
no: 10,
|
|
|
|
});
|
2016-11-13 18:14:29 +01:00
|
|
|
|
|
|
|
metrics.destroy();
|
|
|
|
});
|
|
|
|
|
2016-11-28 17:11:11 +01:00
|
|
|
test('should build up list of seend toggles when new metrics arrives', t => {
|
|
|
|
const store = new EventEmitter();
|
|
|
|
const metrics = new UnleashClientMetrics(store);
|
|
|
|
store.emit('metrics', {
|
|
|
|
appName,
|
|
|
|
instanceId,
|
|
|
|
bucket: {
|
|
|
|
start: new Date(),
|
|
|
|
stop: new Date(),
|
|
|
|
toggles: {
|
|
|
|
toggleX: {
|
|
|
|
yes: 123,
|
|
|
|
no: 0,
|
|
|
|
},
|
|
|
|
toggleY: {
|
|
|
|
yes: 50,
|
|
|
|
no: 50,
|
|
|
|
},
|
2016-11-13 18:14:29 +01:00
|
|
|
},
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
2016-12-05 13:26:53 +01:00
|
|
|
const appToggles = metrics.getAppsWithToggles();
|
2016-11-28 17:11:11 +01:00
|
|
|
const togglesForApp = metrics.getSeenTogglesByAppName(appName);
|
2016-11-13 18:14:29 +01:00
|
|
|
|
2016-11-28 17:11:11 +01:00
|
|
|
t.truthy(appToggles.length === 1);
|
|
|
|
t.truthy(appToggles[0].seenToggles.length === 2);
|
|
|
|
t.truthy(appToggles[0].seenToggles.includes('toggleX'));
|
|
|
|
t.truthy(appToggles[0].seenToggles.includes('toggleY'));
|
2016-11-13 18:14:29 +01:00
|
|
|
|
2016-11-28 17:11:11 +01:00
|
|
|
t.truthy(togglesForApp.length === 2);
|
|
|
|
t.truthy(togglesForApp.includes('toggleX'));
|
|
|
|
t.truthy(togglesForApp.includes('toggleY'));
|
2016-11-13 18:14:29 +01:00
|
|
|
metrics.destroy();
|
|
|
|
});
|
|
|
|
|
2016-11-28 17:11:11 +01:00
|
|
|
test('should handle a lot of toggles', t => {
|
|
|
|
const store = new EventEmitter();
|
|
|
|
const metrics = new UnleashClientMetrics(store);
|
|
|
|
|
|
|
|
const toggleCounts = {};
|
2016-12-04 14:09:37 +01:00
|
|
|
for (let i = 0; i < 100; i++) {
|
2016-12-27 21:03:50 +01:00
|
|
|
toggleCounts[`toggle${i}`] = { yes: i, no: i };
|
2016-11-28 17:11:11 +01:00
|
|
|
}
|
2016-12-04 14:09:37 +01:00
|
|
|
|
2016-11-28 17:11:11 +01:00
|
|
|
store.emit('metrics', {
|
|
|
|
appName,
|
|
|
|
instanceId,
|
|
|
|
bucket: {
|
|
|
|
start: new Date(),
|
|
|
|
stop: new Date(),
|
|
|
|
toggles: toggleCounts,
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
|
|
|
const seenToggles = metrics.getSeenTogglesByAppName(appName);
|
2016-11-13 18:14:29 +01:00
|
|
|
|
2016-11-28 17:11:11 +01:00
|
|
|
t.truthy(seenToggles.length === 100);
|
2016-11-13 18:14:29 +01:00
|
|
|
metrics.destroy();
|
2016-12-04 14:09:37 +01:00
|
|
|
});
|
2016-12-29 11:09:01 +01:00
|
|
|
|
|
|
|
test('should have correct values for lastMinute', t => {
|
|
|
|
const clock = sinon.useFakeTimers();
|
|
|
|
|
|
|
|
const store = new EventEmitter();
|
|
|
|
const metrics = new UnleashClientMetrics(store);
|
|
|
|
|
|
|
|
const now = new Date();
|
|
|
|
const input = [
|
|
|
|
{
|
|
|
|
start: moment(now).subtract(1, 'hour'),
|
|
|
|
stop: moment(now).subtract(59, 'minutes'),
|
|
|
|
toggles: {
|
|
|
|
toggle: { yes: 10, no: 10 },
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
start: moment(now).subtract(30, 'minutes'),
|
|
|
|
stop: moment(now).subtract(29, 'minutes'),
|
|
|
|
toggles: {
|
|
|
|
toggle: { yes: 10, no: 10 },
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
start: moment(now).subtract(2, 'minutes'),
|
|
|
|
stop: moment(now).subtract(1, 'minutes'),
|
|
|
|
toggles: {
|
|
|
|
toggle: { yes: 10, no: 10 },
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
start: moment(now).subtract(2, 'minutes'),
|
|
|
|
stop: moment(now).subtract(59, 'seconds'),
|
|
|
|
toggles: {
|
|
|
|
toggle: { yes: 10, no: 10 },
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
start: moment(now),
|
|
|
|
stop: moment(now).subtract(30, 'seconds'),
|
|
|
|
toggles: {
|
|
|
|
toggle: { yes: 10, no: 10 },
|
|
|
|
},
|
|
|
|
},
|
|
|
|
];
|
|
|
|
|
|
|
|
input.forEach(bucket => {
|
|
|
|
store.emit('metrics', {
|
|
|
|
appName,
|
|
|
|
instanceId,
|
|
|
|
bucket,
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
const seenToggles = metrics.getSeenTogglesByAppName(appName);
|
|
|
|
t.truthy(seenToggles.length === 1);
|
|
|
|
|
|
|
|
// metrics.se
|
|
|
|
let c = metrics.getTogglesMetrics();
|
|
|
|
t.deepEqual(c.lastMinute.toggle, { yes: 20, no: 20 });
|
|
|
|
|
|
|
|
clock.tick(10 * 1000);
|
|
|
|
c = metrics.getTogglesMetrics();
|
|
|
|
t.deepEqual(c.lastMinute.toggle, { yes: 10, no: 10 });
|
|
|
|
|
|
|
|
clock.tick(20 * 1000);
|
|
|
|
c = metrics.getTogglesMetrics();
|
|
|
|
t.deepEqual(c.lastMinute.toggle, { yes: 0, no: 0 });
|
|
|
|
|
|
|
|
metrics.destroy();
|
|
|
|
clock.restore();
|
|
|
|
});
|
|
|
|
|
|
|
|
test('should have correct values for lastHour', t => {
|
|
|
|
const clock = sinon.useFakeTimers();
|
|
|
|
|
|
|
|
const store = new EventEmitter();
|
|
|
|
const metrics = new UnleashClientMetrics(store);
|
|
|
|
|
|
|
|
const now = new Date();
|
|
|
|
const input = [
|
|
|
|
{
|
|
|
|
start: moment(now).subtract(1, 'hour'),
|
|
|
|
stop: moment(now).subtract(59, 'minutes'),
|
|
|
|
toggles: {
|
|
|
|
toggle: { yes: 10, no: 10 },
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
start: moment(now).subtract(30, 'minutes'),
|
|
|
|
stop: moment(now).subtract(29, 'minutes'),
|
|
|
|
toggles: {
|
|
|
|
toggle: { yes: 10, no: 10 },
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
start: moment(now).subtract(15, 'minutes'),
|
|
|
|
stop: moment(now).subtract(14, 'minutes'),
|
|
|
|
toggles: {
|
|
|
|
toggle: { yes: 10, no: 10 },
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
start: moment(now).add(59, 'minutes'),
|
|
|
|
stop: moment(now).add(1, 'hour'),
|
|
|
|
toggles: {
|
|
|
|
toggle: { yes: 11, no: 11 },
|
|
|
|
},
|
|
|
|
},
|
|
|
|
];
|
|
|
|
|
|
|
|
input.forEach(bucket => {
|
|
|
|
store.emit('metrics', {
|
|
|
|
appName,
|
|
|
|
instanceId,
|
|
|
|
bucket,
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
const seenToggles = metrics.getSeenTogglesByAppName(appName);
|
|
|
|
|
|
|
|
t.truthy(seenToggles.length === 1);
|
|
|
|
|
|
|
|
// metrics.se
|
|
|
|
let c = metrics.getTogglesMetrics();
|
|
|
|
t.deepEqual(c.lastHour.toggle, { yes: 41, no: 41 });
|
|
|
|
|
|
|
|
clock.tick(10 * 1000);
|
|
|
|
c = metrics.getTogglesMetrics();
|
|
|
|
t.deepEqual(c.lastHour.toggle, { yes: 41, no: 41 });
|
|
|
|
|
|
|
|
// at 30
|
|
|
|
clock.tick(30 * 60 * 1000);
|
|
|
|
c = metrics.getTogglesMetrics();
|
|
|
|
t.deepEqual(c.lastHour.toggle, { yes: 31, no: 31 });
|
|
|
|
|
|
|
|
// at 45
|
|
|
|
clock.tick(15 * 60 * 1000);
|
|
|
|
c = metrics.getTogglesMetrics();
|
|
|
|
t.deepEqual(c.lastHour.toggle, { yes: 21, no: 21 });
|
|
|
|
|
|
|
|
// at 1:15
|
|
|
|
clock.tick(30 * 60 * 1000);
|
|
|
|
c = metrics.getTogglesMetrics();
|
|
|
|
t.deepEqual(c.lastHour.toggle, { yes: 11, no: 11 });
|
|
|
|
|
|
|
|
// at 2:00
|
|
|
|
clock.tick(45 * 60 * 1000);
|
|
|
|
c = metrics.getTogglesMetrics();
|
|
|
|
t.deepEqual(c.lastHour.toggle, { yes: 0, no: 0 });
|
|
|
|
|
|
|
|
metrics.destroy();
|
|
|
|
clock.restore();
|
|
|
|
});
|
2017-08-04 11:24:58 +02:00
|
|
|
|
|
|
|
test('should not fail when toggle metrics is missing yes/no field', t => {
|
|
|
|
const store = new EventEmitter();
|
|
|
|
const metrics = new UnleashClientMetrics(store);
|
|
|
|
store.emit('metrics', {
|
|
|
|
appName,
|
|
|
|
instanceId,
|
|
|
|
bucket: {
|
|
|
|
start: new Date(),
|
|
|
|
stop: new Date(),
|
|
|
|
toggles: {
|
|
|
|
toggleX: {
|
|
|
|
yes: 123,
|
|
|
|
no: 0,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
|
|
|
metrics.addPayload({
|
|
|
|
appName,
|
|
|
|
instanceId,
|
|
|
|
bucket: {
|
|
|
|
start: new Date(),
|
|
|
|
stop: new Date(),
|
|
|
|
toggles: {
|
|
|
|
toggleX: {
|
|
|
|
blue: 10,
|
|
|
|
green: 10,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
2017-08-08 16:51:26 +02:00
|
|
|
t.is(metrics.globalCount, 123);
|
2017-08-04 11:24:58 +02:00
|
|
|
t.deepEqual(metrics.getTogglesMetrics().lastMinute.toggleX, {
|
|
|
|
yes: 123,
|
|
|
|
no: 0,
|
|
|
|
});
|
|
|
|
|
|
|
|
metrics.destroy();
|
|
|
|
});
|