Commit ea3117fc authored by Paul Slaughter's avatar Paul Slaughter

Merge branch 'cleanup-mock-anomaly-data' into 'master'

Use graph data generation for anomaly chart tests

See merge request gitlab-org/gitlab!36297
parents d2440650 d8e95309
...@@ -3,28 +3,14 @@ import { TEST_HOST } from 'helpers/test_constants'; ...@@ -3,28 +3,14 @@ import { TEST_HOST } from 'helpers/test_constants';
import Anomaly from '~/monitoring/components/charts/anomaly.vue'; import Anomaly from '~/monitoring/components/charts/anomaly.vue';
import { colorValues } from '~/monitoring/constants'; import { colorValues } from '~/monitoring/constants';
import { import { anomalyDeploymentData, mockProjectDir } from '../../mock_data';
anomalyDeploymentData, import { anomalyGraphData } from '../../graph_data';
mockProjectDir,
anomalyMockGraphData,
anomalyMockResultValues,
} from '../../mock_data';
import MonitorTimeSeriesChart from '~/monitoring/components/charts/time_series.vue'; import MonitorTimeSeriesChart from '~/monitoring/components/charts/time_series.vue';
const mockProjectPath = `${TEST_HOST}${mockProjectDir}`; const mockProjectPath = `${TEST_HOST}${mockProjectDir}`;
const makeAnomalyGraphData = (datasetName, template = anomalyMockGraphData) => { const TEST_UPPER = 11;
const metrics = anomalyMockResultValues[datasetName].map((values, index) => ({ const TEST_LOWER = 9;
...template.metrics[index],
result: [
{
metrics: {},
values,
},
],
}));
return { ...template, metrics };
};
describe('Anomaly chart component', () => { describe('Anomaly chart component', () => {
let wrapper; let wrapper;
...@@ -38,13 +24,22 @@ describe('Anomaly chart component', () => { ...@@ -38,13 +24,22 @@ describe('Anomaly chart component', () => {
const getTimeSeriesProps = () => findTimeSeries().props(); const getTimeSeriesProps = () => findTimeSeries().props();
describe('wrapped monitor-time-series-chart component', () => { describe('wrapped monitor-time-series-chart component', () => {
const dataSetName = 'noAnomaly'; const mockValues = ['10', '10', '10'];
const dataSet = anomalyMockResultValues[dataSetName];
const mockGraphData = anomalyGraphData(
{},
{
upper: mockValues.map(() => String(TEST_UPPER)),
values: mockValues,
lower: mockValues.map(() => String(TEST_LOWER)),
},
);
const inputThresholds = ['some threshold']; const inputThresholds = ['some threshold'];
beforeEach(() => { beforeEach(() => {
setupAnomalyChart({ setupAnomalyChart({
graphData: makeAnomalyGraphData(dataSetName), graphData: mockGraphData,
deploymentData: anomalyDeploymentData, deploymentData: anomalyDeploymentData,
thresholds: inputThresholds, thresholds: inputThresholds,
projectPath: mockProjectPath, projectPath: mockProjectPath,
...@@ -65,21 +60,21 @@ describe('Anomaly chart component', () => { ...@@ -65,21 +60,21 @@ describe('Anomaly chart component', () => {
it('receives "metric" with all data', () => { it('receives "metric" with all data', () => {
const { graphData } = getTimeSeriesProps(); const { graphData } = getTimeSeriesProps();
const query = graphData.metrics[0]; const metric = graphData.metrics[0];
const expectedQuery = makeAnomalyGraphData(dataSetName).metrics[0]; const expectedMetric = mockGraphData.metrics[0];
expect(query).toEqual(expectedQuery); expect(metric).toEqual(expectedMetric);
}); });
it('receives the "metric" results', () => { it('receives the "metric" results', () => {
const { graphData } = getTimeSeriesProps(); const { graphData } = getTimeSeriesProps();
const { result } = graphData.metrics[0]; const { result } = graphData.metrics[0];
const { values } = result[0]; const { values } = result[0];
const [metricDataset] = dataSet;
expect(values).toEqual(expect.any(Array));
values.forEach(([, y], index) => { expect(values).toEqual([
expect(y).toBeCloseTo(metricDataset[index][1]); [expect.any(String), 10],
}); [expect.any(String), 10],
[expect.any(String), 10],
]);
}); });
}); });
...@@ -108,14 +103,13 @@ describe('Anomaly chart component', () => { ...@@ -108,14 +103,13 @@ describe('Anomaly chart component', () => {
it('upper boundary values are stacked on top of lower boundary', () => { it('upper boundary values are stacked on top of lower boundary', () => {
const [lowerSeries, upperSeries] = series; const [lowerSeries, upperSeries] = series;
const [, upperDataset, lowerDataset] = dataSet;
lowerSeries.data.forEach(([, y], i) => { lowerSeries.data.forEach(([, y]) => {
expect(y).toBeCloseTo(lowerDataset[i][1]); expect(y).toBeCloseTo(TEST_LOWER);
}); });
upperSeries.data.forEach(([, y], i) => { upperSeries.data.forEach(([, y]) => {
expect(y).toBeCloseTo(upperDataset[i][1] - lowerDataset[i][1]); expect(y).toBeCloseTo(TEST_UPPER - TEST_LOWER);
}); });
}); });
}); });
...@@ -140,11 +134,10 @@ describe('Anomaly chart component', () => { ...@@ -140,11 +134,10 @@ describe('Anomaly chart component', () => {
}), }),
); );
}); });
it('does not display anomalies', () => { it('does not display anomalies', () => {
const { symbolSize, itemStyle } = seriesConfig; const { symbolSize, itemStyle } = seriesConfig;
const [metricDataset] = dataSet; mockValues.forEach((v, dataIndex) => {
metricDataset.forEach((v, dataIndex) => {
const size = symbolSize(null, { dataIndex }); const size = symbolSize(null, { dataIndex });
const color = itemStyle.color({ dataIndex }); const color = itemStyle.color({ dataIndex });
...@@ -155,9 +148,10 @@ describe('Anomaly chart component', () => { ...@@ -155,9 +148,10 @@ describe('Anomaly chart component', () => {
}); });
it('can format y values (to use in tooltips)', () => { it('can format y values (to use in tooltips)', () => {
expect(parseFloat(wrapper.vm.yValueFormatted(0, 0))).toEqual(dataSet[0][0][1]); mockValues.forEach((v, dataIndex) => {
expect(parseFloat(wrapper.vm.yValueFormatted(1, 0))).toEqual(dataSet[1][0][1]); const formatted = wrapper.vm.yValueFormatted(0, dataIndex);
expect(parseFloat(wrapper.vm.yValueFormatted(2, 0))).toEqual(dataSet[2][0][1]); expect(parseFloat(formatted)).toEqual(parseFloat(v));
});
}); });
}); });
...@@ -179,12 +173,18 @@ describe('Anomaly chart component', () => { ...@@ -179,12 +173,18 @@ describe('Anomaly chart component', () => {
}); });
describe('with no boundary data', () => { describe('with no boundary data', () => {
const dataSetName = 'noBoundary'; const noBoundaryData = anomalyGraphData(
const dataSet = anomalyMockResultValues[dataSetName]; {},
{
upper: [],
values: ['10', '10', '10'],
lower: [],
},
);
beforeEach(() => { beforeEach(() => {
setupAnomalyChart({ setupAnomalyChart({
graphData: makeAnomalyGraphData(dataSetName), graphData: noBoundaryData,
deploymentData: anomalyDeploymentData, deploymentData: anomalyDeploymentData,
}); });
}); });
...@@ -204,7 +204,7 @@ describe('Anomaly chart component', () => { ...@@ -204,7 +204,7 @@ describe('Anomaly chart component', () => {
}); });
it('can format y values (to use in tooltips)', () => { 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(1, 0)).toBe(''); // missing boundary
expect(wrapper.vm.yValueFormatted(2, 0)).toBe(''); // missing boundary expect(wrapper.vm.yValueFormatted(2, 0)).toBe(''); // missing boundary
}); });
...@@ -212,12 +212,20 @@ describe('Anomaly chart component', () => { ...@@ -212,12 +212,20 @@ describe('Anomaly chart component', () => {
}); });
describe('with one anomaly', () => { describe('with one anomaly', () => {
const dataSetName = 'oneAnomaly'; const mockValues = ['10', '20', '10'];
const dataSet = anomalyMockResultValues[dataSetName];
const oneAnomalyData = anomalyGraphData(
{},
{
upper: mockValues.map(() => TEST_UPPER),
values: mockValues,
lower: mockValues.map(() => TEST_LOWER),
},
);
beforeEach(() => { beforeEach(() => {
setupAnomalyChart({ setupAnomalyChart({
graphData: makeAnomalyGraphData(dataSetName), graphData: oneAnomalyData,
deploymentData: anomalyDeploymentData, deploymentData: anomalyDeploymentData,
}); });
}); });
...@@ -226,13 +234,12 @@ describe('Anomaly chart component', () => { ...@@ -226,13 +234,12 @@ describe('Anomaly chart component', () => {
it('displays one anomaly', () => { it('displays one anomaly', () => {
const { seriesConfig } = getTimeSeriesProps(); const { seriesConfig } = getTimeSeriesProps();
const { symbolSize, itemStyle } = seriesConfig; const { symbolSize, itemStyle } = seriesConfig;
const [metricDataset] = dataSet;
const bigDots = metricDataset.filter((v, dataIndex) => { const bigDots = mockValues.filter((v, dataIndex) => {
const size = symbolSize(null, { dataIndex }); const size = symbolSize(null, { dataIndex });
return size > 0.1; return size > 0.1;
}); });
const redDots = metricDataset.filter((v, dataIndex) => { const redDots = mockValues.filter((v, dataIndex) => {
const color = itemStyle.color({ dataIndex }); const color = itemStyle.color({ dataIndex });
return color === colorValues.anomalySymbol; return color === colorValues.anomalySymbol;
}); });
...@@ -244,13 +251,21 @@ describe('Anomaly chart component', () => { ...@@ -244,13 +251,21 @@ describe('Anomaly chart component', () => {
}); });
describe('with offset', () => { describe('with offset', () => {
const dataSetName = 'negativeBoundary'; const mockValues = ['10', '11', '12'];
const dataSet = anomalyMockResultValues[dataSetName]; const mockUpper = ['20', '20', '20'];
const expectedOffset = 4; // Lowst point in mock data is -3.70, it gets rounded const mockLower = ['-1', '-2', '-3.70'];
const expectedOffset = 4; // Lowest point in mock data is -3.70, it gets rounded
beforeEach(() => { beforeEach(() => {
setupAnomalyChart({ setupAnomalyChart({
graphData: makeAnomalyGraphData(dataSetName), graphData: anomalyGraphData(
{},
{
upper: mockUpper,
values: mockValues,
lower: mockLower,
},
),
deploymentData: anomalyDeploymentData, deploymentData: anomalyDeploymentData,
}); });
}); });
...@@ -266,11 +281,11 @@ describe('Anomaly chart component', () => { ...@@ -266,11 +281,11 @@ describe('Anomaly chart component', () => {
const { graphData } = getTimeSeriesProps(); const { graphData } = getTimeSeriesProps();
const { result } = graphData.metrics[0]; const { result } = graphData.metrics[0];
const { values } = result[0]; const { values } = result[0];
const [metricDataset] = dataSet;
expect(values).toEqual(expect.any(Array)); expect(values).toEqual(expect.any(Array));
values.forEach(([, y], index) => { 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', () => { ...@@ -281,14 +296,12 @@ describe('Anomaly chart component', () => {
const { option } = getTimeSeriesProps(); const { option } = getTimeSeriesProps();
const { series } = option; const { series } = option;
const [lowerSeries, upperSeries] = series; const [lowerSeries, upperSeries] = series;
const [, upperDataset, lowerDataset] = dataSet;
lowerSeries.data.forEach(([, y], i) => { lowerSeries.data.forEach(([, y], i) => {
expect(y).toBeCloseTo(lowerDataset[i][1] + expectedOffset); expect(y).toBeCloseTo(parseFloat(mockLower[i]) + expectedOffset);
}); });
upperSeries.data.forEach(([, y], i) => { 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'; ...@@ -9,7 +9,6 @@ import AlertWidget from '~/monitoring/components/alert_widget.vue';
import DashboardPanel from '~/monitoring/components/dashboard_panel.vue'; import DashboardPanel from '~/monitoring/components/dashboard_panel.vue';
import { import {
anomalyMockGraphData,
mockLogsHref, mockLogsHref,
mockLogsPath, mockLogsPath,
mockNamespace, mockNamespace,
...@@ -19,7 +18,7 @@ import { ...@@ -19,7 +18,7 @@ import {
barMockData, barMockData,
} from '../mock_data'; } from '../mock_data';
import { dashboardProps, graphData, graphDataEmpty } from '../fixture_data'; import { dashboardProps, graphData, graphDataEmpty } from '../fixture_data';
import { singleStatGraphData } from '../graph_data'; import { anomalyGraphData, singleStatGraphData } from '../graph_data';
import { panelTypes } from '~/monitoring/constants'; import { panelTypes } from '~/monitoring/constants';
...@@ -233,7 +232,7 @@ describe('Dashboard Panel', () => { ...@@ -233,7 +232,7 @@ describe('Dashboard Panel', () => {
${dataWithType(panelTypes.AREA_CHART)} | ${MonitorTimeSeriesChart} | ${true} ${dataWithType(panelTypes.AREA_CHART)} | ${MonitorTimeSeriesChart} | ${true}
${dataWithType(panelTypes.LINE_CHART)} | ${MonitorTimeSeriesChart} | ${true} ${dataWithType(panelTypes.LINE_CHART)} | ${MonitorTimeSeriesChart} | ${true}
${singleStatGraphData()} | ${MonitorSingleStatChart} | ${true} ${singleStatGraphData()} | ${MonitorSingleStatChart} | ${true}
${anomalyMockGraphData} | ${MonitorAnomalyChart} | ${false} ${anomalyGraphData()} | ${MonitorAnomalyChart} | ${false}
${dataWithType(panelTypes.COLUMN)} | ${MonitorColumnChart} | ${false} ${dataWithType(panelTypes.COLUMN)} | ${MonitorColumnChart} | ${false}
${dataWithType(panelTypes.STACKED_COLUMN)} | ${MonitorStackedColumnChart} | ${false} ${dataWithType(panelTypes.STACKED_COLUMN)} | ${MonitorStackedColumnChart} | ${false}
${graphDataPrometheusQueryRangeMultiTrack} | ${MonitorHeatmapChart} | ${false} ${graphDataPrometheusQueryRangeMultiTrack} | ${MonitorHeatmapChart} | ${false}
......
...@@ -124,3 +124,41 @@ export const singleStatGraphData = (panelOptions = {}, dataOptions = {}) => { ...@@ -124,3 +124,41 @@ export const singleStatGraphData = (panelOptions = {}, dataOptions = {}) => {
...panelOptions, ...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 = [ ...@@ -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 = [ export const deploymentData = [
{ {
id: 111, id: 111,
......
import * as monitoringUtils from '~/monitoring/utils'; import * as monitoringUtils from '~/monitoring/utils';
import * as urlUtils from '~/lib/utils/url_utility'; import * as urlUtils from '~/lib/utils/url_utility';
import { TEST_HOST } from 'jest/helpers/test_constants'; 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 { metricsDashboardViewModel, graphData } from './fixture_data';
import { singleStatGraphData } from './graph_data';
const mockPath = `${TEST_HOST}${mockProjectDir}/-/environments/29/metrics`; const mockPath = `${TEST_HOST}${mockProjectDir}/-/environments/29/metrics`;
...@@ -102,12 +102,12 @@ describe('monitoring/utils', () => { ...@@ -102,12 +102,12 @@ describe('monitoring/utils', () => {
let fourMetrics; let fourMetrics;
beforeEach(() => { beforeEach(() => {
oneMetric = singleStatGraphData(); oneMetric = singleStatGraphData();
threeMetrics = anomalyMockGraphData; threeMetrics = anomalyGraphData();
const metrics = [...threeMetrics.metrics]; const metrics = [...threeMetrics.metrics];
metrics.push(threeMetrics.metrics[0]); metrics.push(threeMetrics.metrics[0]);
fourMetrics = { fourMetrics = {
...anomalyMockGraphData, ...anomalyGraphData(),
metrics, 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