Skip to content
Snippets Groups Projects
Commit f6df7d6a authored by Jose Ivan Vargas Lopez's avatar Jose Ivan Vargas Lopez
Browse files

Added and corrected specs for the additional time series

parent 520ab72b
No related branches found
No related tags found
No related merge requests found
Loading
Loading
@@ -8,6 +8,7 @@
import eventHub from '../event_hub';
import measurements from '../utils/measurements';
import { timeScaleFormat } from '../utils/date_time_formatters';
import createTimeSeries from '../utils/multiple_time_series';
import bp from '../../breakpoints';
 
const bisectDate = d3.bisector(d => d.time).left;
Loading
Loading
@@ -63,16 +64,10 @@
},
 
components: {
<<<<<<< HEAD:app/assets/javascripts/monitoring/components/graph.vue
GraphLegend,
GraphFlag,
GraphDeployment,
=======
monitoringLegends,
monitoringFlag,
monitoringDeployment,
monitoringPaths,
>>>>>>> Refactored the monitoring_column component to process all of the time series:app/assets/javascripts/monitoring/components/monitoring_column.vue
},
 
computed: {
Loading
Loading
@@ -152,34 +147,10 @@
},
 
renderAxesPaths() {
this.timeSeries = this.columnData.queries[0].result.map((timeSeries) => {
const timeSeriesScaleX = d3.time.scale()
.range([0, this.graphWidth - 70]);
const timeSeriesScaleY = d3.scale.linear()
.range([this.graphHeight - this.graphHeightOffset, 0]);
timeSeriesScaleX.domain(d3.extent(timeSeries.values, d => d.time));
timeSeriesScaleY.domain([0, d3.max(timeSeries.values.map(d => d.value))]);
const lineFunction = d3.svg.line()
.x(d => timeSeriesScaleX(d.time))
.y(d => timeSeriesScaleY(d.value));
const areaFunction = d3.svg.area()
.x(d => timeSeriesScaleX(d.time))
.y0(this.graphHeight - this.graphHeightOffset)
.y1(d => timeSeriesScaleY(d.value))
.interpolate('linear');
return {
linePath: lineFunction(timeSeries.values),
areaPath: areaFunction(timeSeries.values),
timeSeriesScaleX,
timeSeriesScaleY,
values: timeSeries.values,
};
});
this.timeSeries = createTimeSeries(this.columnData.queries[0].result,
this.graphWidth,
this.graphHeight,
this.graphHeightOffset);
 
if (this.timeSeries.length > 4) {
this.baseGraphHeight = this.baseGraphHeight += (this.timeSeries.length - 4) * 20;
Loading
Loading
@@ -273,23 +244,6 @@
class="graph-data"
:viewBox="innerViewBox"
ref="graphData">
<<<<<<< HEAD:app/assets/javascripts/monitoring/components/graph.vue
<path
class="metric-area"
:d="area"
:fill="areaColorRgb"
transform="translate(-5, 20)">
</path>
<path
class="metric-line"
:d="line"
:stroke="lineColorRgb"
fill="none"
stroke-width="2"
transform="translate(-5, 20)">
</path>
<graph-deployment
=======
<monitoring-paths
v-for="(path, index) in timeSeries"
:key="index"
Loading
Loading
@@ -307,7 +261,6 @@
@mousemove="handleMouseOverGraph($event)">
</rect>
<monitoring-deployment
>>>>>>> Refactored the monitoring_column component to process all of the time series:app/assets/javascripts/monitoring/components/monitoring_column.vue
:show-deploy-info="showDeployInfo"
:deployment-data="reducedDeploymentData"
:graph-height="graphHeight"
Loading
Loading
<script>
import { formatRelevantDigits } from '../../lib/utils/number_utils';
import { formatRelevantDigits } from '../../../lib/utils/number_utils';
 
export default {
props: {
Loading
Loading
@@ -89,8 +89,14 @@
mounted() {
this.$nextTick(() => {
const bbox = this.$refs.ylabel.getBBox();
this.seriesXPosition = this.$refs.legendTitleSvg[0].getBBox().width;
this.metricUsageXPosition = this.$refs.seriesTitleSvg[0].getBBox().width;
this.metricUsageXPosition = 0;
this.seriesXPosition = 0;
if (this.$refs.legendTitleSvg != null) {
this.seriesXPosition = this.$refs.legendTitleSvg[0].getBBox().width;
}
if (this.$refs.seriesTitleSvg != null) {
this.metricUsageXPosition = this.$refs.seriesTitleSvg[0].getBBox().width;
}
this.yLabelWidth = bbox.width + 10; // Added some padding
this.yLabelHeight = bbox.height + 5;
});
Loading
Loading
import d3 from 'd3';
export default function createTimeSeries(seriesData, graphWidth, graphHeight, graphHeightOffset) {
return seriesData.map((timeSeries) => {
const timeSeriesScaleX = d3.time.scale()
.range([0, graphWidth - 70]);
const timeSeriesScaleY = d3.scale.linear()
.range([graphHeight - graphHeightOffset, 0]);
timeSeriesScaleX.domain(d3.extent(timeSeries.values, d => d.time));
timeSeriesScaleY.domain([0, d3.max(timeSeries.values.map(d => d.value))]);
const lineFunction = d3.svg.line()
.x(d => timeSeriesScaleX(d.time))
.y(d => timeSeriesScaleY(d.value));
const areaFunction = d3.svg.area()
.x(d => timeSeriesScaleX(d.time))
.y0(graphHeight - graphHeightOffset)
.y1(d => timeSeriesScaleY(d.value))
.interpolate('linear');
return {
linePath: lineFunction(timeSeries.values),
areaPath: areaFunction(timeSeries.values),
timeSeriesScaleX,
timeSeriesScaleY,
values: timeSeries.values,
};
});
}
Loading
Loading
@@ -32,10 +32,6 @@ describe('GraphFlag', () => {
.toEqual(component.currentXCoordinate);
expect(getCoordinate(component, '.selected-metric-line', 'x2'))
.toEqual(component.currentXCoordinate);
expect(getCoordinate(component, '.circle-metric', 'cx'))
.toEqual(component.currentXCoordinate);
expect(getCoordinate(component, '.circle-metric', 'cy'))
.toEqual(component.currentYCoordinate);
});
 
it('has a SVG with the class rect-text-metric at the currentFlagPosition', () => {
Loading
Loading
import Vue from 'vue';
import GraphLegend from '~/monitoring/components/graph/legend.vue';
import measurements from '~/monitoring/utils/measurements';
import createTimeSeries from '~/monitoring/utils/multiple_time_series';
import { singleRowMetricsMultipleSeries, convertDatesMultipleSeries } from '../mock_data';
 
const createComponent = (propsData) => {
const Component = Vue.extend(GraphLegend);
Loading
Loading
@@ -10,6 +12,28 @@ const createComponent = (propsData) => {
}).$mount();
};
 
const convertedMetrics = convertDatesMultipleSeries(singleRowMetricsMultipleSeries);
const defaultValuesComponent = {
graphWidth: 500,
graphHeight: 300,
graphHeightOffset: 120,
margin: measurements.large.margin,
measurements: measurements.large,
areaColorRgb: '#f0f0f0',
legendTitle: 'Title',
yAxisLabel: 'Values',
metricUsage: 'Value',
unitOfDisplay: 'Req/Sec',
currentDataIndex: 0,
};
const timeSeries = createTimeSeries(convertedMetrics[0].queries[0].result,
defaultValuesComponent.graphWidth, defaultValuesComponent.graphHeight,
defaultValuesComponent.graphHeightOffset);
defaultValuesComponent.timeSeries = timeSeries;
function getTextFromNode(component, selector) {
return component.$el.querySelector(selector).firstChild.nodeValue.trim();
}
Loading
Loading
@@ -17,95 +41,67 @@ function getTextFromNode(component, selector) {
describe('GraphLegend', () => {
describe('Computed props', () => {
it('textTransform', () => {
const component = createComponent({
graphWidth: 500,
graphHeight: 300,
margin: measurements.large.margin,
measurements: measurements.large,
areaColorRgb: '#f0f0f0',
legendTitle: 'Title',
yAxisLabel: 'Values',
metricUsage: 'Value',
});
const component = createComponent(defaultValuesComponent);
 
expect(component.textTransform).toContain('translate(15, 120) rotate(-90)');
});
 
it('xPosition', () => {
const component = createComponent({
graphWidth: 500,
graphHeight: 300,
margin: measurements.large.margin,
measurements: measurements.large,
areaColorRgb: '#f0f0f0',
legendTitle: 'Title',
yAxisLabel: 'Values',
metricUsage: 'Value',
});
const component = createComponent(defaultValuesComponent);
 
expect(component.xPosition).toEqual(180);
});
 
it('yPosition', () => {
const component = createComponent({
graphWidth: 500,
graphHeight: 300,
margin: measurements.large.margin,
measurements: measurements.large,
areaColorRgb: '#f0f0f0',
legendTitle: 'Title',
yAxisLabel: 'Values',
metricUsage: 'Value',
});
const component = createComponent(defaultValuesComponent);
 
expect(component.yPosition).toEqual(240);
});
 
it('rectTransform', () => {
const component = createComponent({
graphWidth: 500,
graphHeight: 300,
margin: measurements.large.margin,
measurements: measurements.large,
areaColorRgb: '#f0f0f0',
legendTitle: 'Title',
yAxisLabel: 'Values',
metricUsage: 'Value',
});
const component = createComponent(defaultValuesComponent);
 
expect(component.rectTransform).toContain('translate(0, 120) rotate(-90)');
});
});
 
it('has 2 rect-axis-text rect svg elements', () => {
const component = createComponent({
graphWidth: 500,
graphHeight: 300,
margin: measurements.large.margin,
measurements: measurements.large,
areaColorRgb: '#f0f0f0',
legendTitle: 'Title',
yAxisLabel: 'Values',
metricUsage: 'Value',
describe('methods', () => {
it('translateLegendGroup should only change Y direction', () => {
const component = createComponent(defaultValuesComponent);
const translatedCoordinate = component.translateLegendGroup(1);
expect(translatedCoordinate.indexOf('translate(0, ')).not.toEqual(-1);
});
 
it('formatMetricUsage should contain the unit of display and the current value selected via "currentDataIndex"', () => {
const component = createComponent(defaultValuesComponent);
const formattedMetricUsage = component.formatMetricUsage(timeSeries[0]);
const valueFromSeries = timeSeries[0].values[component.currentDataIndex].value;
expect(formattedMetricUsage.indexOf(component.unitOfDisplay)).not.toEqual(-1);
expect(formattedMetricUsage.indexOf(valueFromSeries)).not.toEqual(-1);
});
});
it('has 2 rect-axis-text rect svg elements', () => {
const component = createComponent(defaultValuesComponent);
expect(component.$el.querySelectorAll('.rect-axis-text').length).toEqual(2);
});
 
it('contains text to signal the usage, title and time', () => {
const component = createComponent({
graphWidth: 500,
graphHeight: 300,
margin: measurements.large.margin,
measurements: measurements.large,
areaColorRgb: '#f0f0f0',
legendTitle: 'Title',
yAxisLabel: 'Values',
metricUsage: 'Value',
});
const component = createComponent(defaultValuesComponent);
const titles = component.$el.querySelectorAll('.legend-metric-title');
expect(getTextFromNode(component, '.legend-metric-title')).toEqual(component.legendTitle);
expect(titles[0].textContent.indexOf('Title')).not.toEqual(-1);
expect(titles[1].textContent.indexOf('Series')).not.toEqual(-1);
expect(getTextFromNode(component, '.y-label-text')).toEqual(component.yAxisLabel);
});
it('should contain the same number of legend groups as the timeSeries length', () => {
const component = createComponent(defaultValuesComponent);
 
expect(getTextFromNode(component, '.text-metric-title')).toEqual(component.legendTitle);
expect(getTextFromNode(component, '.text-metric-usage')).toEqual(component.metricUsage);
expect(getTextFromNode(component, '.label-axis-text')).toEqual(component.yAxisLabel);
expect(component.$el.querySelectorAll('.legend-group').length).toEqual(component.timeSeries.length);
});
});
import Vue from 'vue';
import GraphRow from '~/monitoring/components/graph_row.vue';
import MonitoringMixins from '~/monitoring/mixins/monitoring_mixins';
import { deploymentData, singleRowMetrics } from './mock_data';
import { deploymentData, convertDatesMultipleSeries, singleRowMetricsMultipleSeries } from './mock_data';
 
const createComponent = (propsData) => {
const Component = Vue.extend(GraphRow);
Loading
Loading
@@ -11,15 +11,15 @@ const createComponent = (propsData) => {
}).$mount();
};
 
const convertedMetrics = convertDatesMultipleSeries(singleRowMetricsMultipleSeries);
describe('GraphRow', () => {
beforeEach(() => {
spyOn(MonitoringMixins.methods, 'formatDeployments').and.returnValue({});
});
describe('Computed props', () => {
it('bootstrapClass is set to col-md-6 when rowData is higher/equal to 2', () => {
const component = createComponent({
rowData: singleRowMetrics,
rowData: convertedMetrics,
updateAspectRatio: false,
deploymentData,
});
Loading
Loading
@@ -29,7 +29,7 @@ describe('GraphRow', () => {
 
it('bootstrapClass is set to col-md-12 when rowData is lower than 2', () => {
const component = createComponent({
rowData: [singleRowMetrics[0]],
rowData: [convertedMetrics[0]],
updateAspectRatio: false,
deploymentData,
});
Loading
Loading
@@ -40,7 +40,7 @@ describe('GraphRow', () => {
 
it('has one column', () => {
const component = createComponent({
rowData: singleRowMetrics,
rowData: convertedMetrics,
updateAspectRatio: false,
deploymentData,
});
Loading
Loading
@@ -51,7 +51,7 @@ describe('GraphRow', () => {
 
it('has two columns', () => {
const component = createComponent({
rowData: singleRowMetrics,
rowData: convertedMetrics,
updateAspectRatio: false,
deploymentData,
});
Loading
Loading
import Vue from 'vue';
import _ from 'underscore';
import Graph from '~/monitoring/components/graph.vue';
import MonitoringMixins from '~/monitoring/mixins/monitoring_mixins';
import eventHub from '~/monitoring/event_hub';
import { deploymentData, singleRowMetrics } from './mock_data';
import { deploymentData, convertDatesMultipleSeries, singleRowMetricsMultipleSeries } from './mock_data';
 
const createComponent = (propsData) => {
const Component = Vue.extend(Graph);
Loading
Loading
@@ -13,6 +12,8 @@ const createComponent = (propsData) => {
}).$mount();
};
 
const convertedMetrics = convertDatesMultipleSeries(singleRowMetricsMultipleSeries);
describe('Graph', () => {
beforeEach(() => {
spyOn(MonitoringMixins.methods, 'formatDeployments').and.returnValue({});
Loading
Loading
@@ -20,7 +21,7 @@ describe('Graph', () => {
 
it('has a title', () => {
const component = createComponent({
graphData: singleRowMetrics[0],
columnData: convertedMetrics[1],
classType: 'col-md-6',
updateAspectRatio: false,
deploymentData,
Loading
Loading
@@ -29,29 +30,10 @@ describe('Graph', () => {
expect(component.$el.querySelector('.text-center').innerText.trim()).toBe(component.graphData.title);
});
 
it('creates a path for the line and area of the graph', (done) => {
const component = createComponent({
graphData: singleRowMetrics[0],
classType: 'col-md-6',
updateAspectRatio: false,
deploymentData,
});
Vue.nextTick(() => {
expect(component.area).toBeDefined();
expect(component.line).toBeDefined();
expect(typeof component.area).toEqual('string');
expect(typeof component.line).toEqual('string');
expect(_.isFunction(component.xScale)).toBe(true);
expect(_.isFunction(component.yScale)).toBe(true);
done();
});
});
describe('Computed props', () => {
it('axisTransform translates an element Y position depending of its height', () => {
const component = createComponent({
graphData: singleRowMetrics[0],
columnData: convertedMetrics[1],
classType: 'col-md-6',
updateAspectRatio: false,
deploymentData,
Loading
Loading
@@ -64,7 +46,7 @@ describe('Graph', () => {
 
it('outterViewBox gets a width and height property based on the DOM size of the element', () => {
const component = createComponent({
graphData: singleRowMetrics[0],
columnData: convertedMetrics[1],
classType: 'col-md-6',
updateAspectRatio: false,
deploymentData,
Loading
Loading
@@ -79,7 +61,7 @@ describe('Graph', () => {
 
it('sends an event to the eventhub when it has finished resizing', (done) => {
const component = createComponent({
graphData: singleRowMetrics[0],
columnData: convertedMetrics[1],
classType: 'col-md-6',
updateAspectRatio: false,
deploymentData,
Loading
Loading
@@ -95,7 +77,7 @@ describe('Graph', () => {
 
it('has a title for the y-axis and the chart legend that comes from the backend', () => {
const component = createComponent({
graphData: singleRowMetrics[0],
columnData: convertedMetrics[1],
classType: 'col-md-6',
updateAspectRatio: false,
deploymentData,
Loading
Loading
This diff is collapsed.
import Vue from 'vue';
import MonitoringPaths from '~/monitoring/components/monitoring_paths.vue';
import createTimeSeries from '~/monitoring/utils/multiple_time_series';
import { singleRowMetricsMultipleSeries, convertDatesMultipleSeries } from './mock_data';
const createComponent = (propsData) => {
const Component = Vue.extend(MonitoringPaths);
return new Component({
propsData,
}).$mount();
};
const convertedMetrics = convertDatesMultipleSeries(singleRowMetricsMultipleSeries);
const timeSeries = createTimeSeries(convertedMetrics[0].queries[0].result, 428, 272, 120);
describe('Monitoring Paths', () => {
it('renders two paths to represent a line and the area underneath it', () => {
const component = createComponent({
generatedLinePath: timeSeries[0].linePath,
generatedAreaPath: timeSeries[0].areaPath,
lineColor: '#ccc',
areaColor: '#fff',
});
const metricArea = component.$el.querySelector('.metric-area');
const metricLine = component.$el.querySelector('.metric-line');
expect(metricArea.getAttribute('fill')).toBe('#fff');
expect(metricArea.getAttribute('d')).toBe(timeSeries[0].areaPath);
expect(metricLine.getAttribute('stroke')).toBe('#ccc');
expect(metricLine.getAttribute('d')).toBe(timeSeries[0].linePath);
});
});
import createTimeSeries from '~/monitoring/utils/multiple_time_series';
import { convertDatesMultipleSeries, singleRowMetricsMultipleSeries } from '../mock_data';
const convertedMetrics = convertDatesMultipleSeries(singleRowMetricsMultipleSeries);
const timeSeries = createTimeSeries(convertedMetrics[0].queries[0].result, 428, 272, 120);
describe('Multiple time series', () => {
it('createTimeSeries returned array contains an object for each element', () => {
expect(typeof timeSeries[0].linePath).toEqual('string');
expect(typeof timeSeries[0].areaPath).toEqual('string');
expect(typeof timeSeries[0].timeSeriesScaleX).toEqual('function');
expect(typeof timeSeries[0].timeSeriesScaleY).toEqual('function');
expect(timeSeries[0].values instanceof Array).toEqual(true);
});
it('createTimeSeries returns an array', () => {
expect(timeSeries instanceof Array).toEqual(true);
expect(timeSeries.length).toEqual(5);
});
});
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment