From b369953de94234ab474dd1d4db38692fba091d2a Mon Sep 17 00:00:00 2001 From: sveisvei Date: Thu, 29 Dec 2016 11:07:06 +0100 Subject: [PATCH 1/3] fix typ0 that broke time.now --- lib/client-metrics/client-metrics.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/client-metrics/client-metrics.test.js b/lib/client-metrics/client-metrics.test.js index 3cc6418b4c..69fcb9108e 100644 --- a/lib/client-metrics/client-metrics.test.js +++ b/lib/client-metrics/client-metrics.test.js @@ -58,7 +58,7 @@ test.cb('data should expire', (t) => { t.true(lastMinExpires === 1); t.true(lastHourExpires === 1); - sinon.restore(); + clock.restore(); t.end(); }); From 1cf442487044b4719ddce55d80ab39543872cf59 Mon Sep 17 00:00:00 2001 From: sveisvei Date: Thu, 29 Dec 2016 11:08:41 +0100 Subject: [PATCH 2/3] evict if new item directly is not eligible --- lib/client-metrics/ttl-list.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/client-metrics/ttl-list.js b/lib/client-metrics/ttl-list.js index 208277fcc9..8049645b50 100644 --- a/lib/client-metrics/ttl-list.js +++ b/lib/client-metrics/ttl-list.js @@ -37,11 +37,15 @@ module.exports = class TTLList extends EventEmitter { add (value, timestamp = new Date()) { const ttl = moment(timestamp).add(this.expireAmount, this.expireType); - this.list.add({ ttl, value }); + if (moment().isBefore(ttl)) { + this.list.add({ ttl, value }); + } else { + this.emit('expire', value, ttl); + } } timedCheck () { - const now = moment(new Date()); + const now = moment(); this.list.reverseRemoveUntilTrue(({ value }) => now.isBefore(value.ttl)); this.startTimer(); } From abd16c23bae7c4688d3f443489bbbc11bdbd1e20 Mon Sep 17 00:00:00 2001 From: sveisvei Date: Thu, 29 Dec 2016 11:09:01 +0100 Subject: [PATCH 3/3] add sanity tests for metrics --- lib/client-metrics/client-metrics.test.js | 156 ++++++++++++++++++++++ 1 file changed, 156 insertions(+) diff --git a/lib/client-metrics/client-metrics.test.js b/lib/client-metrics/client-metrics.test.js index 69fcb9108e..2ff289314b 100644 --- a/lib/client-metrics/client-metrics.test.js +++ b/lib/client-metrics/client-metrics.test.js @@ -2,6 +2,7 @@ const { test } = require('ava'); const UnleashClientMetrics = require('./index'); +const moment = require('moment'); const sinon = require('sinon'); const { EventEmitter } = require('events'); @@ -170,3 +171,158 @@ test('should handle a lot of toggles', t => { t.truthy(seenToggles.length === 100); metrics.destroy(); }); + +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(); +});