Commit d8e95309 authored by Miguel Rincon's avatar Miguel Rincon

Cleanup anomaly mock data

As we want to check that our charts can display with no data we want
to be able to test more flexible data inputs to our components.
parent 0fbb3372
......@@ -3,28 +3,14 @@ import { TEST_HOST } from 'helpers/test_constants';
import Anomaly from '~/monitoring/components/charts/anomaly.vue';
import { colorValues } from '~/monitoring/constants';
import {
anomalyDeploymentData,
mockProjectDir,
anomalyMockGraphData,
anomalyMockResultValues,
} from '../../mock_data';
import { anomalyDeploymentData, mockProjectDir } from '../../mock_data';
import { anomalyGraphData } from '../../graph_data';
import MonitorTimeSeriesChart from '~/monitoring/components/charts/time_series.vue';
const mockProjectPath = `${TEST_HOST}${mockProjectDir}`;
const makeAnomalyGraphData = (datasetName, template = anomalyMockGraphData) => {
const metrics = anomalyMockResultValues[datasetName].map((values, index) => ({
...template.metrics[index],
result: [
{
metrics: {},
values,
},
],
}));
return { ...template, metrics };
};
const TEST_UPPER = 11;
const TEST_LOWER = 9;
describe('Anomaly chart component', () => {
let wrapper;
......@@ -38,13 +24,22 @@ describe('Anomaly chart component', () => {
const getTimeSeriesProps = () => findTimeSeries().props();
describe('wrapped monitor-time-series-chart component', () => {
const dataSetName = 'noAnomaly';
const dataSet = anomalyMockResultValues[dataSetName];
const mockValues = ['10', '10', '10'];
const mockGraphData = anomalyGraphData(
{},
{
upper: mockValues.map(() => String(TEST_UPPER)),
values: mockValues,
lower: mockValues.map(() => String(TEST_LOWER)),
},
);
const inputThresholds = ['some threshold'];
beforeEach(() => {
setupAnomalyChart({
graphData: makeAnomalyGraphData(dataSetName),
graphData: mockGraphData,
deploymentData: anomalyDeploymentData,
thresholds: inputThresholds,
projectPath: mockProjectPath,
......@@ -65,21 +60,21 @@ describe('Anomaly chart component', () => {
it('receives "metric" with all data', () => {
const { graphData } = getTimeSeriesProps();
const query = graphData.metrics[0];
const expectedQuery = makeAnomalyGraphData(dataSetName).metrics[0];
expect(query).toEqual(expectedQuery);
const metric = graphData.metrics[0];
const expectedMetric = mockGraphData.metrics[0];
expect(metric).toEqual(expectedMetric);
});
it('receives the "metric" results', () => {
const { graphData } = getTimeSeriesProps();
const { result } = graphData.metrics[0];
const { values } = result[0];
const [metricDataset] = dataSet;
expect(values).toEqual(expect.any(Array));
values.forEach(([, y], index) => {
expect(y).toBeCloseTo(metricDataset[index][1]);
});
expect(values).toEqual([
[expect.any(String), 10],
[expect.any(String), 10],
[expect.any(String), 10],
]);
});
});
......@@ -108,14 +103,13 @@ describe('Anomaly chart component', () => {
it('upper boundary values are stacked on top of lower boundary', () => {
const [lowerSeries, upperSeries] = series;
const [, upperDataset, lowerDataset] = dataSet;
lowerSeries.data.forEach(([, y], i) => {
expect(y).toBeCloseTo(lowerDataset[i][1]);
lowerSeries.data.forEach(([, y]) => {
expect(y).toBeCloseTo(TEST_LOWER);
});
upperSeries.data.forEach(([, y], i) => {
expect(y).toBeCloseTo(upperDataset[i][1] - lowerDataset[i][1]);
upperSeries.data.forEach(([, y]) => {
expect(y).toBeCloseTo(TEST_UPPER - TEST_LOWER);
});
});
});
......@@ -140,11 +134,10 @@ describe('Anomaly chart component', () => {
}),
);
});
it('does not display anomalies', () => {
const { symbolSize, itemStyle } = seriesConfig;
const [metricDataset] = dataSet;
metricDataset.forEach((v, dataIndex) => {
mockValues.forEach((v, dataIndex) => {
const size = symbolSize(null, { dataIndex });
const color = itemStyle.color({ dataIndex });
......@@ -155,9 +148,10 @@ describe('Anomaly chart component', () => {
});
it('can format y values (to use in tooltips)', () => {
expect(parseFloat(wrapper.vm.yValueFormatted(0, 0))).toEqual(dataSet[0][0][1]);
expect(parseFloat(wrapper.vm.yValueFormatted(1, 0))).toEqual(dataSet[1][0][1]);
expect(parseFloat(wrapper.vm.yValueFormatted(2, 0))).toEqual(dataSet[2][0][1]);
mockValues.forEach((v, dataIndex) => {
const formatted = wrapper.vm.yValueFormatted(0, dataIndex);
expect(parseFloat(formatted)).toEqual(parseFloat(v));
});
});
});
......@@ -179,12 +173,18 @@ describe('Anomaly chart component', () => {
});
describe('with no boundary data', () => {
const dataSetName = 'noBoundary';
const dataSet = anomalyMockResultValues[dataSetName];
const noBoundaryData = anomalyGraphData(
{},
{
upper: [],
values: ['10', '10', '10'],
lower: [],
},
);
beforeEach(() => {
setupAnomalyChart({
graphData: makeAnomalyGraphData(dataSetName),
graphData: noBoundaryData,
deploymentData: anomalyDeploymentData,
});
});
......@@ -204,7 +204,7 @@ describe('Anomaly chart component', () => {
});
it('can format y values (to use in tooltips)', () => {
expect(parseFloat(wrapper.vm.yValueFormatted(0, 0))).toEqual(dataSet[0][0][1]);
expect(parseFloat(wrapper.vm.yValueFormatted(0, 0))).toEqual(10);
expect(wrapper.vm.yValueFormatted(1, 0)).toBe(''); // missing boundary
expect(wrapper.vm.yValueFormatted(2, 0)).toBe(''); // missing boundary
});
......@@ -212,12 +212,20 @@ describe('Anomaly chart component', () => {
});
describe('with one anomaly', () => {
const dataSetName = 'oneAnomaly';
const dataSet = anomalyMockResultValues[dataSetName];
const mockValues = ['10', '20', '10'];
const oneAnomalyData = anomalyGraphData(
{},
{
upper: mockValues.map(() => TEST_UPPER),
values: mockValues,
lower: mockValues.map(() => TEST_LOWER),
},
);
beforeEach(() => {
setupAnomalyChart({
graphData: makeAnomalyGraphData(dataSetName),
graphData: oneAnomalyData,
deploymentData: anomalyDeploymentData,
});
});
......@@ -226,13 +234,12 @@ describe('Anomaly chart component', () => {
it('displays one anomaly', () => {
const { seriesConfig } = getTimeSeriesProps();
const { symbolSize, itemStyle } = seriesConfig;
const [metricDataset] = dataSet;
const bigDots = metricDataset.filter((v, dataIndex) => {
const bigDots = mockValues.filter((v, dataIndex) => {
const size = symbolSize(null, { dataIndex });
return size > 0.1;
});
const redDots = metricDataset.filter((v, dataIndex) => {
const redDots = mockValues.filter((v, dataIndex) => {
const color = itemStyle.color({ dataIndex });
return color === colorValues.anomalySymbol;
});
......@@ -244,13 +251,21 @@ describe('Anomaly chart component', () => {
});
describe('with offset', () => {
const dataSetName = 'negativeBoundary';
const dataSet = anomalyMockResultValues[dataSetName];
const expectedOffset = 4; // Lowst point in mock data is -3.70, it gets rounded
const mockValues = ['10', '11', '12'];
const mockUpper = ['20', '20', '20'];
const mockLower = ['-1', '-2', '-3.70'];
const expectedOffset = 4; // Lowest point in mock data is -3.70, it gets rounded
beforeEach(() => {
setupAnomalyChart({
graphData: makeAnomalyGraphData(dataSetName),
graphData: anomalyGraphData(
{},
{
upper: mockUpper,
values: mockValues,
lower: mockLower,
},
),
deploymentData: anomalyDeploymentData,
});
});
......@@ -266,11 +281,11 @@ describe('Anomaly chart component', () => {
const { graphData } = getTimeSeriesProps();
const { result } = graphData.metrics[0];
const { values } = result[0];
const [metricDataset] = dataSet;
expect(values).toEqual(expect.any(Array));
values.forEach(([, y], index) => {
expect(y).toBeCloseTo(metricDataset[index][1] + expectedOffset);
expect(y).toBeCloseTo(parseFloat(mockValues[index]) + expectedOffset);
});
});
});
......@@ -281,14 +296,12 @@ describe('Anomaly chart component', () => {
const { option } = getTimeSeriesProps();
const { series } = option;
const [lowerSeries, upperSeries] = series;
const [, upperDataset, lowerDataset] = dataSet;
lowerSeries.data.forEach(([, y], i) => {
expect(y).toBeCloseTo(lowerDataset[i][1] + expectedOffset);
expect(y).toBeCloseTo(parseFloat(mockLower[i]) + expectedOffset);
});
upperSeries.data.forEach(([, y], i) => {
expect(y).toBeCloseTo(upperDataset[i][1] - lowerDataset[i][1]);
expect(y).toBeCloseTo(parseFloat(mockUpper[i] - mockLower[i]));
});
});
});
......
......@@ -9,7 +9,6 @@ import AlertWidget from '~/monitoring/components/alert_widget.vue';
import DashboardPanel from '~/monitoring/components/dashboard_panel.vue';
import {
anomalyMockGraphData,
mockLogsHref,
mockLogsPath,
mockNamespace,
......@@ -19,7 +18,7 @@ import {
barMockData,
} from '../mock_data';
import { dashboardProps, graphData, graphDataEmpty } from '../fixture_data';
import { singleStatGraphData } from '../graph_data';
import { anomalyGraphData, singleStatGraphData } from '../graph_data';
import { panelTypes } from '~/monitoring/constants';
......@@ -233,7 +232,7 @@ describe('Dashboard Panel', () => {
${dataWithType(panelTypes.AREA_CHART)} | ${MonitorTimeSeriesChart} | ${true}
${dataWithType(panelTypes.LINE_CHART)} | ${MonitorTimeSeriesChart} | ${true}
${singleStatGraphData()} | ${MonitorSingleStatChart} | ${true}
${anomalyMockGraphData} | ${MonitorAnomalyChart} | ${false}
${anomalyGraphData()} | ${MonitorAnomalyChart} | ${false}
${dataWithType(panelTypes.COLUMN)} | ${MonitorColumnChart} | ${false}
${dataWithType(panelTypes.STACKED_COLUMN)} | ${MonitorStackedColumnChart} | ${false}
${graphDataPrometheusQueryRangeMultiTrack} | ${MonitorHeatmapChart} | ${false}
......
......@@ -124,3 +124,41 @@ export const singleStatGraphData = (panelOptions = {}, dataOptions = {}) => {
...panelOptions,
});
};
/**
* Generate mock graph data according to options
*
* @param {Object} panelOptions - Panel options as in YML.
* @param {Object} dataOptions
* @param {Array} dataOptions.values - Metric values
* @param {Array} dataOptions.upper - Upper boundary values
* @param {Array} dataOptions.lower - Lower boundary values
*/
export const anomalyGraphData = (panelOptions = {}, dataOptions = {}) => {
const { values, upper, lower } = dataOptions;
return mapPanelToViewModel({
title: 'Anomaly Panel',
type: panelTypes.ANOMALY_CHART,
x_label: 'X Axis',
y_label: 'Y Axis',
metrics: [
{
label: `Metric`,
state: metricStates.OK,
result: matrixSingleResult({ values }),
},
{
label: `Upper boundary`,
state: metricStates.OK,
result: matrixSingleResult({ values: upper }),
},
{
label: `Lower boundary`,
state: metricStates.OK,
result: matrixSingleResult({ values: lower }),
},
],
...panelOptions,
});
};
......@@ -51,136 +51,6 @@ export const anomalyDeploymentData = [
},
];
export const anomalyMockResultValues = {
noAnomaly: [
[
['2019-08-19T19:00:00.000Z', 1.25],
['2019-08-19T20:00:00.000Z', 1.45],
['2019-08-19T21:00:00.000Z', 1.55],
['2019-08-19T22:00:00.000Z', 1.48],
],
[
// upper boundary
['2019-08-19T19:00:00.000Z', 2],
['2019-08-19T20:00:00.000Z', 2.55],
['2019-08-19T21:00:00.000Z', 2.65],
['2019-08-19T22:00:00.000Z', 3.0],
],
[
// lower boundary
['2019-08-19T19:00:00.000Z', 0.45],
['2019-08-19T20:00:00.000Z', 0.65],
['2019-08-19T21:00:00.000Z', 0.7],
['2019-08-19T22:00:00.000Z', 0.8],
],
],
noBoundary: [
[
['2019-08-19T19:00:00.000Z', 1.25],
['2019-08-19T20:00:00.000Z', 1.45],
['2019-08-19T21:00:00.000Z', 1.55],
['2019-08-19T22:00:00.000Z', 1.48],
],
[
// empty upper boundary
],
[
// empty lower boundary
],
],
oneAnomaly: [
[
['2019-08-19T19:00:00.000Z', 1.25],
['2019-08-19T20:00:00.000Z', 3.45], // anomaly
['2019-08-19T21:00:00.000Z', 1.55],
],
[
// upper boundary
['2019-08-19T19:00:00.000Z', 2],
['2019-08-19T20:00:00.000Z', 2.55],
['2019-08-19T21:00:00.000Z', 2.65],
],
[
// lower boundary
['2019-08-19T19:00:00.000Z', 0.45],
['2019-08-19T20:00:00.000Z', 0.65],
['2019-08-19T21:00:00.000Z', 0.7],
],
],
negativeBoundary: [
[
['2019-08-19T19:00:00.000Z', 1.25],
['2019-08-19T20:00:00.000Z', 3.45], // anomaly
['2019-08-19T21:00:00.000Z', 1.55],
],
[
// upper boundary
['2019-08-19T19:00:00.000Z', 2],
['2019-08-19T20:00:00.000Z', 2.55],
['2019-08-19T21:00:00.000Z', 2.65],
],
[
// lower boundary
['2019-08-19T19:00:00.000Z', -1.25],
['2019-08-19T20:00:00.000Z', -2.65],
['2019-08-19T21:00:00.000Z', -3.7], // lowest point
],
],
};
export const anomalyMockGraphData = {
title: 'Requests Per Second Mock Data',
type: 'anomaly-chart',
weight: 3,
metrics: [
{
metricId: '90',
id: 'metric',
query_range: 'MOCK_PROMETHEUS_METRIC_QUERY_RANGE',
unit: 'RPS',
label: 'Metrics RPS',
metric_id: 90,
prometheus_endpoint_path: 'MOCK_METRIC_PEP',
result: [
{
metric: {},
values: [['2019-08-19T19:00:00.000Z', 0]],
},
],
},
{
metricId: '91',
id: 'upper',
query_range: '...',
unit: 'RPS',
label: 'Upper Limit Metrics RPS',
metric_id: 91,
prometheus_endpoint_path: 'MOCK_UPPER_PEP',
result: [
{
metric: {},
values: [['2019-08-19T19:00:00.000Z', 0]],
},
],
},
{
metricId: '92',
id: 'lower',
query_range: '...',
unit: 'RPS',
label: 'Lower Limit Metrics RPS',
metric_id: 92,
prometheus_endpoint_path: 'MOCK_LOWER_PEP',
result: [
{
metric: {},
values: [['2019-08-19T19:00:00.000Z', 0]],
},
],
},
],
};
export const deploymentData = [
{
id: 111,
......
import * as monitoringUtils from '~/monitoring/utils';
import * as urlUtils from '~/lib/utils/url_utility';
import { TEST_HOST } from 'jest/helpers/test_constants';
import { mockProjectDir, anomalyMockGraphData, barMockData } from './mock_data';
import { mockProjectDir, barMockData } from './mock_data';
import { singleStatGraphData, anomalyGraphData } from './graph_data';
import { metricsDashboardViewModel, graphData } from './fixture_data';
import { singleStatGraphData } from './graph_data';
const mockPath = `${TEST_HOST}${mockProjectDir}/-/environments/29/metrics`;
......@@ -102,12 +102,12 @@ describe('monitoring/utils', () => {
let fourMetrics;
beforeEach(() => {
oneMetric = singleStatGraphData();
threeMetrics = anomalyMockGraphData;
threeMetrics = anomalyGraphData();
const metrics = [...threeMetrics.metrics];
metrics.push(threeMetrics.metrics[0]);
fourMetrics = {
...anomalyMockGraphData,
...anomalyGraphData(),
metrics,
};
});
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment