mirror of
https://github.com/Unleash/unleash.git
synced 2025-01-01 00:08:27 +01:00
Merge pull request #256 from Unleash/metrics_validation
Add metrics validation to avoid NaN #253
This commit is contained in:
commit
810b414945
@ -5,6 +5,7 @@
|
|||||||
- disable edit of built-in strategies
|
- disable edit of built-in strategies
|
||||||
- Strip uknown fields in client requests.
|
- Strip uknown fields in client requests.
|
||||||
- Disable x-powered-by header
|
- Disable x-powered-by header
|
||||||
|
- Improved client-metrics validation to avoid NaN
|
||||||
- Add posibility to inject custom logger provider
|
- Add posibility to inject custom logger provider
|
||||||
|
|
||||||
## 3.0.0-alpha.1
|
## 3.0.0-alpha.1
|
||||||
|
@ -335,3 +335,45 @@ test('should have correct values for lastHour', t => {
|
|||||||
metrics.destroy();
|
metrics.destroy();
|
||||||
clock.restore();
|
clock.restore();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
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,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
t.is(metrics.globalCount, 123);
|
||||||
|
t.deepEqual(metrics.getTogglesMetrics().lastMinute.toggleX, {
|
||||||
|
yes: 123,
|
||||||
|
no: 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
metrics.destroy();
|
||||||
|
});
|
||||||
|
@ -25,7 +25,7 @@ module.exports = class UnleashClientMetrics {
|
|||||||
Object.keys(toggles).forEach(toggleName => {
|
Object.keys(toggles).forEach(toggleName => {
|
||||||
this.lastHourProjection.substract(
|
this.lastHourProjection.substract(
|
||||||
toggleName,
|
toggleName,
|
||||||
toggles[toggleName]
|
this.createCountObject(toggles[toggleName])
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -33,7 +33,7 @@ module.exports = class UnleashClientMetrics {
|
|||||||
Object.keys(toggles).forEach(toggleName => {
|
Object.keys(toggles).forEach(toggleName => {
|
||||||
this.lastMinuteProjection.substract(
|
this.lastMinuteProjection.substract(
|
||||||
toggleName,
|
toggleName,
|
||||||
toggles[toggleName]
|
this.createCountObject(toggles[toggleName])
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -91,6 +91,12 @@ module.exports = class UnleashClientMetrics {
|
|||||||
return this.apps[appName];
|
return this.apps[appName];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
createCountObject(entry) {
|
||||||
|
const yes = typeof entry.yes == 'number' ? entry.yes : 0;
|
||||||
|
const no = typeof entry.no == 'number' ? entry.no : 0;
|
||||||
|
return { yes, no };
|
||||||
|
}
|
||||||
|
|
||||||
addBucket(app, bucket) {
|
addBucket(app, bucket) {
|
||||||
let count = 0;
|
let count = 0;
|
||||||
// TODO stop should be createdAt
|
// TODO stop should be createdAt
|
||||||
@ -99,10 +105,10 @@ module.exports = class UnleashClientMetrics {
|
|||||||
const toggleNames = Object.keys(toggles);
|
const toggleNames = Object.keys(toggles);
|
||||||
|
|
||||||
toggleNames.forEach(n => {
|
toggleNames.forEach(n => {
|
||||||
const entry = toggles[n];
|
const countObj = this.createCountObject(toggles[n]);
|
||||||
this.lastHourProjection.add(n, entry);
|
this.lastHourProjection.add(n, countObj);
|
||||||
this.lastMinuteProjection.add(n, entry);
|
this.lastMinuteProjection.add(n, countObj);
|
||||||
count += entry.yes + entry.no;
|
count += countObj.yes + countObj.no;
|
||||||
});
|
});
|
||||||
|
|
||||||
this.lastHourList.add(toggles, stop);
|
this.lastHourList.add(toggles, stop);
|
||||||
|
@ -2,13 +2,18 @@
|
|||||||
|
|
||||||
const joi = require('joi');
|
const joi = require('joi');
|
||||||
|
|
||||||
|
const countSchema = joi.object().options({ stripUnknown: true }).keys({
|
||||||
|
yes: joi.number().required().min(0).default(0),
|
||||||
|
no: joi.number().required().min(0).default(0),
|
||||||
|
});
|
||||||
|
|
||||||
const clientMetricsSchema = joi.object().options({ stripUnknown: true }).keys({
|
const clientMetricsSchema = joi.object().options({ stripUnknown: true }).keys({
|
||||||
appName: joi.string().required(),
|
appName: joi.string().required(),
|
||||||
instanceId: joi.string().required(),
|
instanceId: joi.string().required(),
|
||||||
bucket: joi.object().required().keys({
|
bucket: joi.object().required().keys({
|
||||||
start: joi.date().required(),
|
start: joi.date().required(),
|
||||||
stop: joi.date().required(),
|
stop: joi.date().required(),
|
||||||
toggles: joi.object(),
|
toggles: joi.object().pattern(/.*/, countSchema),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ test('should validate client metrics', t => {
|
|||||||
.expect(400);
|
.expect(400);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should accept client metrics', t => {
|
test('should accept empty client metrics', t => {
|
||||||
t.plan(0);
|
t.plan(0);
|
||||||
const { request } = getSetup();
|
const { request } = getSetup();
|
||||||
return request
|
return request
|
||||||
@ -47,3 +47,47 @@ test('should accept client metrics', t => {
|
|||||||
})
|
})
|
||||||
.expect(202);
|
.expect(202);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should accept client metrics with yes/no', t => {
|
||||||
|
t.plan(0);
|
||||||
|
const { request } = getSetup();
|
||||||
|
return request
|
||||||
|
.post('/api/client/metrics')
|
||||||
|
.send({
|
||||||
|
appName: 'demo',
|
||||||
|
instanceId: '1',
|
||||||
|
bucket: {
|
||||||
|
start: Date.now(),
|
||||||
|
stop: Date.now(),
|
||||||
|
toggles: {
|
||||||
|
toggleA: {
|
||||||
|
yes: 200,
|
||||||
|
no: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.expect(202);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should not accept client metrics without yes/no', t => {
|
||||||
|
t.plan(0);
|
||||||
|
const { request } = getSetup();
|
||||||
|
return request
|
||||||
|
.post('/api/client/metrics')
|
||||||
|
.send({
|
||||||
|
appName: 'demo',
|
||||||
|
instanceId: '1',
|
||||||
|
bucket: {
|
||||||
|
start: Date.now(),
|
||||||
|
stop: Date.now(),
|
||||||
|
toggles: {
|
||||||
|
toggleA: {
|
||||||
|
blue: 200,
|
||||||
|
green: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.expect(400);
|
||||||
|
});
|
||||||
|
8
test/examples/client-register.json
Normal file
8
test/examples/client-register.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"appName": "appName",
|
||||||
|
"instanceId": "instanceId",
|
||||||
|
"sdkVersion": "test:123",
|
||||||
|
"strategies": ["default", "some-strategy-1"],
|
||||||
|
"started": "2016-11-03T07:16:43.572Z",
|
||||||
|
"interval": 10000
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user