1
0
mirror of https://github.com/Unleash/unleash.git synced 2024-12-28 00:06:53 +01:00
unleash.unleash/lib/services/client-metrics/client-metrics.test.js
Ivar Conradi Østhus cdfba8f7b1 feat: Adds last-seen dat on toggles
When an application updates metrics for a toggle we now
stores the timestamp on the toggle when it was last seen
used by an application. This will make it much easier to
detect toggles not in use anymore.

closes #642
2020-12-22 11:05:00 +01:00

380 lines
9.7 KiB
JavaScript

'use strict';
const test = require('ava');
const moment = require('moment');
const lolex = require('lolex');
const { EventEmitter } = require('events');
const UnleashClientMetrics = require('./index');
const appName = 'appName';
const instanceId = 'instanceId';
test('should work without state', t => {
const clientMetricsStore = new EventEmitter();
const metrics = new UnleashClientMetrics({ clientMetricsStore });
t.truthy(metrics.getAppsWithToggles());
t.truthy(metrics.getTogglesMetrics());
metrics.destroy();
});
test.cb('data should expire', t => {
const clock = lolex.install();
const clientMetricsStore = new EventEmitter();
const metrics = new UnleashClientMetrics({ clientMetricsStore });
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);
clock.uninstall();
t.end();
});
test('should listen to metrics from store', t => {
const clientMetricsStore = new EventEmitter();
const metrics = new UnleashClientMetrics({ clientMetricsStore });
clientMetricsStore.emit('metrics', {
appName,
instanceId,
bucket: {
start: new Date(),
stop: new Date(),
toggles: {
toggleX: {
yes: 123,
no: 0,
},
},
},
});
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,
});
metrics.addPayload({
appName,
instanceId,
bucket: {
start: new Date(),
stop: new Date(),
toggles: {
toggleX: {
yes: 10,
no: 10,
},
},
},
});
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,
});
metrics.destroy();
});
test('should build up list of seend toggles when new metrics arrives', t => {
const clientMetricsStore = new EventEmitter();
const metrics = new UnleashClientMetrics({ clientMetricsStore });
clientMetricsStore.emit('metrics', {
appName,
instanceId,
bucket: {
start: new Date(),
stop: new Date(),
toggles: {
toggleX: {
yes: 123,
no: 0,
},
toggleY: {
yes: 50,
no: 50,
},
},
},
});
const appToggles = metrics.getAppsWithToggles();
const togglesForApp = metrics.getSeenTogglesByAppName(appName);
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'));
t.truthy(togglesForApp.length === 2);
t.truthy(togglesForApp.includes('toggleX'));
t.truthy(togglesForApp.includes('toggleY'));
metrics.destroy();
});
test('should handle a lot of toggles', t => {
const clientMetricsStore = new EventEmitter();
const metrics = new UnleashClientMetrics({ clientMetricsStore });
const toggleCounts = {};
for (let i = 0; i < 100; i++) {
toggleCounts[`toggle${i}`] = { yes: i, no: i };
}
clientMetricsStore.emit('metrics', {
appName,
instanceId,
bucket: {
start: new Date(),
stop: new Date(),
toggles: toggleCounts,
},
});
const seenToggles = metrics.getSeenTogglesByAppName(appName);
t.truthy(seenToggles.length === 100);
metrics.destroy();
});
test('should have correct values for lastMinute', t => {
const clock = lolex.install();
const clientMetricsStore = new EventEmitter();
const metrics = new UnleashClientMetrics({ clientMetricsStore });
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 => {
clientMetricsStore.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.uninstall();
});
test('should have correct values for lastHour', t => {
const clock = lolex.install();
const clientMetricsStore = new EventEmitter();
const metrics = new UnleashClientMetrics({ clientMetricsStore });
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 => {
clientMetricsStore.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.uninstall();
});
test('should not fail when toggle metrics is missing yes/no field', t => {
const clientMetricsStore = new EventEmitter();
const metrics = new UnleashClientMetrics({ clientMetricsStore });
clientMetricsStore.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,
},
},
},
});
t.is(metrics.globalCount, 123);
t.deepEqual(metrics.getTogglesMetrics().lastMinute.toggleX, {
yes: 123,
no: 0,
});
metrics.destroy();
});