2017-03-30 18:21:22 +03:00
|
|
|
import _ from 'lodash';
|
2017-09-21 16:40:18 +02:00
|
|
|
import { describe, beforeEach, it, expect } from '../../../../../test/lib/common';
|
2017-03-30 18:21:22 +03:00
|
|
|
import TimeSeries from 'app/core/time_series2';
|
2017-08-02 21:27:10 +03:00
|
|
|
import {convertToHeatMap, convertToCards, elasticHistogramToHeatmap,
|
|
|
|
|
calculateBucketSize, isHeatmapDataEqual} from '../heatmap_data_converter';
|
2017-03-30 18:21:22 +03:00
|
|
|
|
|
|
|
|
describe('isHeatmapDataEqual', () => {
|
|
|
|
|
let ctx: any = {};
|
|
|
|
|
|
|
|
|
|
beforeEach(() => {
|
|
|
|
|
ctx.heatmapA = {
|
|
|
|
|
'1422774000000': {
|
|
|
|
|
x: 1422774000000,
|
|
|
|
|
buckets: {
|
|
|
|
|
'1': { y: 1, values: [1, 1.5] },
|
|
|
|
|
'2': { y: 2, values: [1] }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
ctx.heatmapB = {
|
|
|
|
|
'1422774000000': {
|
|
|
|
|
x: 1422774000000,
|
|
|
|
|
buckets: {
|
|
|
|
|
'1': { y: 1, values: [1.5, 1] },
|
|
|
|
|
'2': { y: 2, values: [1] }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should proper compare objects', () => {
|
|
|
|
|
let heatmapC = _.cloneDeep(ctx.heatmapA);
|
|
|
|
|
heatmapC['1422774000000'].buckets['1'].values = [1, 1.5];
|
|
|
|
|
|
|
|
|
|
let heatmapD = _.cloneDeep(ctx.heatmapA);
|
|
|
|
|
heatmapD['1422774000000'].buckets['1'].values = [1.5, 1, 1.6];
|
|
|
|
|
|
|
|
|
|
let heatmapE = _.cloneDeep(ctx.heatmapA);
|
|
|
|
|
heatmapE['1422774000000'].buckets['1'].values = [1, 1.6];
|
|
|
|
|
|
2017-03-30 20:55:10 +03:00
|
|
|
let empty = {};
|
|
|
|
|
let emptyValues = _.cloneDeep(ctx.heatmapA);
|
|
|
|
|
emptyValues['1422774000000'].buckets['1'].values = [];
|
|
|
|
|
|
2017-10-22 07:03:26 +02:00
|
|
|
expect(isHeatmapDataEqual(ctx.heatmapA, ctx.heatmapB)).toBe(true);
|
|
|
|
|
expect(isHeatmapDataEqual(ctx.heatmapB, ctx.heatmapA)).toBe(true);
|
2017-03-30 20:55:10 +03:00
|
|
|
|
2017-10-22 07:03:26 +02:00
|
|
|
expect(isHeatmapDataEqual(ctx.heatmapA, heatmapC)).toBe(true);
|
|
|
|
|
expect(isHeatmapDataEqual(heatmapC, ctx.heatmapA)).toBe(true);
|
2017-03-30 20:55:10 +03:00
|
|
|
|
2017-10-22 07:03:26 +02:00
|
|
|
expect(isHeatmapDataEqual(ctx.heatmapA, heatmapD)).toBe(false);
|
|
|
|
|
expect(isHeatmapDataEqual(heatmapD, ctx.heatmapA)).toBe(false);
|
2017-03-30 20:55:10 +03:00
|
|
|
|
2017-10-22 07:03:26 +02:00
|
|
|
expect(isHeatmapDataEqual(ctx.heatmapA, heatmapE)).toBe(false);
|
|
|
|
|
expect(isHeatmapDataEqual(heatmapE, ctx.heatmapA)).toBe(false);
|
2017-03-30 20:55:10 +03:00
|
|
|
|
2017-10-22 07:03:26 +02:00
|
|
|
expect(isHeatmapDataEqual(empty, ctx.heatmapA)).toBe(false);
|
|
|
|
|
expect(isHeatmapDataEqual(ctx.heatmapA, empty)).toBe(false);
|
2017-03-30 20:55:10 +03:00
|
|
|
|
2017-10-22 07:03:26 +02:00
|
|
|
expect(isHeatmapDataEqual(emptyValues, ctx.heatmapA)).toBe(false);
|
|
|
|
|
expect(isHeatmapDataEqual(ctx.heatmapA, emptyValues)).toBe(false);
|
2017-03-30 18:21:22 +03:00
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2017-03-31 11:44:44 +03:00
|
|
|
describe('calculateBucketSize', () => {
|
|
|
|
|
let ctx: any = {};
|
|
|
|
|
|
|
|
|
|
describe('when logBase is 1 (linear scale)', () => {
|
|
|
|
|
|
|
|
|
|
beforeEach(() => {
|
|
|
|
|
ctx.logBase = 1;
|
|
|
|
|
ctx.bounds_set = [
|
|
|
|
|
{ bounds: [], size: 0 },
|
|
|
|
|
{ bounds: [0], size: 0 },
|
|
|
|
|
{ bounds: [4], size: 4 },
|
|
|
|
|
{ bounds: [0, 1, 2, 3, 4], size: 1 },
|
|
|
|
|
{ bounds: [0, 1, 3, 5, 7], size: 1 },
|
|
|
|
|
{ bounds: [0, 3, 7, 9, 15], size: 2 },
|
|
|
|
|
{ bounds: [0, 7, 3, 15, 9], size: 2 },
|
|
|
|
|
{ bounds: [0, 5, 10, 15, 50], size: 5 }
|
|
|
|
|
];
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should properly calculate bucket size', () => {
|
|
|
|
|
_.each(ctx.bounds_set, (b) => {
|
|
|
|
|
let bucketSize = calculateBucketSize(b.bounds, ctx.logBase);
|
2017-10-22 07:03:26 +02:00
|
|
|
expect(bucketSize).toBe(b.size);
|
2017-03-31 11:44:44 +03:00
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
describe('when logBase is 2', () => {
|
|
|
|
|
|
|
|
|
|
beforeEach(() => {
|
|
|
|
|
ctx.logBase = 2;
|
|
|
|
|
ctx.bounds_set = [
|
|
|
|
|
{ bounds: [], size: 0 },
|
|
|
|
|
{ bounds: [0], size: 0 },
|
|
|
|
|
{ bounds: [4], size: 4 },
|
|
|
|
|
{ bounds: [1, 2, 4, 8], size: 1 },
|
|
|
|
|
{ bounds: [1, Math.SQRT2, 2, 8, 16], size: 0.5 }
|
|
|
|
|
];
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should properly calculate bucket size', () => {
|
|
|
|
|
_.each(ctx.bounds_set, (b) => {
|
|
|
|
|
let bucketSize = calculateBucketSize(b.bounds, ctx.logBase);
|
2017-10-22 07:03:26 +02:00
|
|
|
expect(isEqual(bucketSize, b.size)).toBe(true);
|
2017-03-31 11:44:44 +03:00
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2017-03-30 18:21:22 +03:00
|
|
|
describe('HeatmapDataConverter', () => {
|
|
|
|
|
let ctx: any = {};
|
|
|
|
|
|
|
|
|
|
beforeEach(() => {
|
|
|
|
|
ctx.series = [];
|
|
|
|
|
ctx.series.push(new TimeSeries({
|
2017-05-05 17:28:33 +02:00
|
|
|
datapoints: [[1, 1422774000000], [1, 1422774000010], [2, 1422774060000]],
|
2017-03-30 18:21:22 +03:00
|
|
|
alias: 'series1'
|
|
|
|
|
}));
|
|
|
|
|
ctx.series.push(new TimeSeries({
|
2017-05-05 17:28:33 +02:00
|
|
|
datapoints: [[2, 1422774000000], [2, 1422774000010], [3, 1422774060000]],
|
2017-03-30 18:21:22 +03:00
|
|
|
alias: 'series2'
|
|
|
|
|
}));
|
2017-05-05 17:28:33 +02:00
|
|
|
ctx.series.push(new TimeSeries({
|
|
|
|
|
datapoints: [[5, 1422774000000], [3, 1422774000010], [4, 1422774060000]],
|
|
|
|
|
alias: 'series3'
|
|
|
|
|
}));
|
2017-03-30 18:21:22 +03:00
|
|
|
|
|
|
|
|
ctx.xBucketSize = 60000; // 60s
|
2017-05-05 17:28:33 +02:00
|
|
|
ctx.yBucketSize = 2;
|
2017-03-30 18:21:22 +03:00
|
|
|
ctx.logBase = 1;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
describe('when logBase is 1 (linear scale)', () => {
|
|
|
|
|
beforeEach(() => {
|
|
|
|
|
ctx.logBase = 1;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should build proper heatmap data', () => {
|
|
|
|
|
let expectedHeatmap = {
|
|
|
|
|
'1422774000000': {
|
|
|
|
|
x: 1422774000000,
|
|
|
|
|
buckets: {
|
2017-05-05 17:28:33 +02:00
|
|
|
'0': {y: 0, values: [1, 1], count: 2, bounds: {bottom: 0, top: 2}},
|
|
|
|
|
'2': {y: 2, values: [2, 2, 3], count: 3, bounds: {bottom: 2, top: 4}},
|
|
|
|
|
'4': {y: 4, values: [5], count: 1, bounds: {bottom: 4, top: 6}},
|
2017-03-30 18:21:22 +03:00
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
'1422774060000': {
|
|
|
|
|
x: 1422774060000,
|
|
|
|
|
buckets: {
|
2017-05-05 17:28:33 +02:00
|
|
|
'2': {y: 2, values: [2, 3], count: 3, bounds: {bottom: 2, top: 4}},
|
|
|
|
|
'4': {y: 4, values: [4], count: 1, bounds: {bottom: 4, top: 6}},
|
2017-03-30 18:21:22 +03:00
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let heatmap = convertToHeatMap(ctx.series, ctx.yBucketSize, ctx.xBucketSize, ctx.logBase);
|
2017-10-22 07:03:26 +02:00
|
|
|
expect(isHeatmapDataEqual(heatmap, expectedHeatmap)).toBe(true);
|
2017-03-30 18:21:22 +03:00
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2017-05-05 17:28:33 +02:00
|
|
|
describe.skip('when logBase is 2', () => {
|
2017-03-30 18:21:22 +03:00
|
|
|
|
|
|
|
|
beforeEach(() => {
|
|
|
|
|
ctx.logBase = 2;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should build proper heatmap data', () => {
|
|
|
|
|
let expectedHeatmap = {
|
|
|
|
|
'1422774000000': {
|
|
|
|
|
x: 1422774000000,
|
|
|
|
|
buckets: {
|
|
|
|
|
'1': { y: 1, values: [1] },
|
|
|
|
|
'2': { y: 2, values: [2] }
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
'1422774060000': {
|
|
|
|
|
x: 1422774060000,
|
|
|
|
|
buckets: {
|
|
|
|
|
'2': { y: 2, values: [2, 3] }
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let heatmap = convertToHeatMap(ctx.series, ctx.yBucketSize, ctx.xBucketSize, ctx.logBase);
|
2017-10-22 07:03:26 +02:00
|
|
|
expect(isHeatmapDataEqual(heatmap, expectedHeatmap)).toBe(true);
|
2017-03-30 18:21:22 +03:00
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|
2017-03-30 20:55:10 +03:00
|
|
|
|
|
|
|
|
describe('ES Histogram converter', () => {
|
|
|
|
|
let ctx: any = {};
|
|
|
|
|
|
|
|
|
|
beforeEach(() => {
|
|
|
|
|
ctx.series = [];
|
|
|
|
|
ctx.series.push(new TimeSeries({
|
|
|
|
|
datapoints: [[1, 1422774000000], [0, 1422774060000]],
|
|
|
|
|
alias: '1', label: '1'
|
|
|
|
|
}));
|
|
|
|
|
ctx.series.push(new TimeSeries({
|
2017-05-05 16:15:08 +02:00
|
|
|
datapoints: [[5, 1422774000000], [3, 1422774060000]],
|
2017-03-30 20:55:10 +03:00
|
|
|
alias: '2', label: '2'
|
|
|
|
|
}));
|
|
|
|
|
ctx.series.push(new TimeSeries({
|
|
|
|
|
datapoints: [[0, 1422774000000], [1, 1422774060000]],
|
|
|
|
|
alias: '3', label: '3'
|
|
|
|
|
}));
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
describe('when converting ES histogram', () => {
|
|
|
|
|
|
|
|
|
|
beforeEach(() => {
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should build proper heatmap data', () => {
|
|
|
|
|
let expectedHeatmap = {
|
|
|
|
|
'1422774000000': {
|
|
|
|
|
x: 1422774000000,
|
|
|
|
|
buckets: {
|
2017-11-13 17:20:12 +03:00
|
|
|
'1': { y: 1, count: 1, values: [], points: [], bounds: {bottom: 1, top: null}},
|
|
|
|
|
'2': { y: 2, count: 5, values: [], points: [], bounds: {bottom: 2, top: null}},
|
|
|
|
|
'3': { y: 3, count: 0, values: [], points: [], bounds: {bottom: 3, top: null}}
|
2017-03-30 20:55:10 +03:00
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
'1422774060000': {
|
|
|
|
|
x: 1422774060000,
|
|
|
|
|
buckets: {
|
2017-11-13 17:20:12 +03:00
|
|
|
'1': { y: 1, count: 0, values: [], points: [], bounds: {bottom: 1, top: null}},
|
|
|
|
|
'2': { y: 2, count: 3, values: [], points: [], bounds: {bottom: 2, top: null}},
|
|
|
|
|
'3': { y: 3, count: 1, values: [], points: [], bounds: {bottom: 3, top: null}}
|
2017-03-30 20:55:10 +03:00
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let heatmap = elasticHistogramToHeatmap(ctx.series);
|
2017-11-13 17:20:12 +03:00
|
|
|
expect(heatmap).toEqual(expectedHeatmap);
|
2017-03-30 20:55:10 +03:00
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2017-08-02 21:27:10 +03:00
|
|
|
describe('convertToCards', () => {
|
|
|
|
|
let buckets = {};
|
|
|
|
|
|
|
|
|
|
beforeEach(() => {
|
|
|
|
|
buckets = {
|
|
|
|
|
'1422774000000': {
|
|
|
|
|
x: 1422774000000,
|
|
|
|
|
buckets: {
|
|
|
|
|
'1': { y: 1, values: [1], count: 1, bounds: {} },
|
|
|
|
|
'2': { y: 2, values: [2], count: 1, bounds: {} }
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
'1422774060000': {
|
|
|
|
|
x: 1422774060000,
|
|
|
|
|
buckets: {
|
|
|
|
|
'2': { y: 2, values: [2, 3], count: 2, bounds: {} }
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should build proper cards data', () => {
|
|
|
|
|
let expectedCards = [
|
|
|
|
|
{x: 1422774000000, y: 1, count: 1, values: [1], yBounds: {}},
|
|
|
|
|
{x: 1422774000000, y: 2, count: 1, values: [2], yBounds: {}},
|
|
|
|
|
{x: 1422774060000, y: 2, count: 2, values: [2, 3], yBounds: {}}
|
|
|
|
|
];
|
2017-09-21 16:40:18 +02:00
|
|
|
let res = convertToCards(buckets);
|
2017-10-22 07:03:26 +02:00
|
|
|
expect(res.cards).toMatchObject(expectedCards);
|
2017-08-02 21:27:10 +03:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should build proper cards stats', () => {
|
2017-09-21 16:40:18 +02:00
|
|
|
let expectedStats = {min: 1, max: 2};
|
|
|
|
|
let res = convertToCards(buckets);
|
2017-10-22 07:03:26 +02:00
|
|
|
expect(res.cardStats).toMatchObject(expectedStats);
|
2017-08-02 21:27:10 +03:00
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2017-03-31 11:44:44 +03:00
|
|
|
/**
|
|
|
|
|
* Compare two numbers with given precision. Suitable for compare float numbers after conversions with precision loss.
|
|
|
|
|
* @param a
|
|
|
|
|
* @param b
|
|
|
|
|
* @param precision
|
|
|
|
|
*/
|
|
|
|
|
function isEqual(a: number, b: number, precision = 0.000001): boolean {
|
|
|
|
|
if (a === b) {
|
|
|
|
|
return true;
|
|
|
|
|
} else {
|
|
|
|
|
return Math.abs(1 - a / b) <= precision;
|
|
|
|
|
}
|
|
|
|
|
}
|