diff options
| author | Felipe Artur <felipefac@gmail.com> | 2019-06-17 15:22:44 -0300 |
|---|---|---|
| committer | Felipe Artur <felipefac@gmail.com> | 2019-06-17 15:22:44 -0300 |
| commit | d9df2f730b4eaab4e2d1b5f5045e34bb14e3486f (patch) | |
| tree | 050490a4e90601ad4d175ba6674b98f35937587e /spec/javascripts/monitoring | |
| parent | 66b9ca952aa4104f99c1275566e8b5c7d28fce01 (diff) | |
| parent | d2929d6edb3a04054a5218cb1b21cb0759ec1ec8 (diff) | |
| download | gitlab-ce-issue_60515.tar.gz | |
Merge branch 'master' into issue_60515issue_60515
Diffstat (limited to 'spec/javascripts/monitoring')
| -rw-r--r-- | spec/javascripts/monitoring/dashboard_spec.js | 63 | ||||
| -rw-r--r-- | spec/javascripts/monitoring/mock_data.js | 65 | ||||
| -rw-r--r-- | spec/javascripts/monitoring/store/actions_spec.js | 174 | ||||
| -rw-r--r-- | spec/javascripts/monitoring/store/mutations_spec.js | 77 |
4 files changed, 323 insertions, 56 deletions
diff --git a/spec/javascripts/monitoring/dashboard_spec.js b/spec/javascripts/monitoring/dashboard_spec.js index f9c3122088e..f4166987aed 100644 --- a/spec/javascripts/monitoring/dashboard_spec.js +++ b/spec/javascripts/monitoring/dashboard_spec.js @@ -20,7 +20,7 @@ const propsData = { tagsPath: '/path/to/tags', projectPath: '/path/to/project', metricsEndpoint: mockApiEndpoint, - deploymentEndpoint: null, + deploymentsEndpoint: null, emptyGettingStartedSvgPath: '/path/to/getting-started.svg', emptyLoadingSvgPath: '/path/to/loading.svg', emptyNoDataSvgPath: '/path/to/no-data.svg', @@ -49,9 +49,6 @@ describe('Dashboard', () => { window.gon = { ...window.gon, ee: false, - features: { - grafanaDashboardLink: true, - }, }; store = createStore(); @@ -382,52 +379,26 @@ describe('Dashboard', () => { describe('external dashboard link', () => { beforeEach(() => { mock.onGet(mockApiEndpoint).reply(200, metricsGroupsAPIResponse); - }); - - describe('with feature flag enabled', () => { - beforeEach(() => { - component = new DashboardComponent({ - el: document.querySelector('.prometheus-graphs'), - propsData: { - ...propsData, - hasMetrics: true, - showPanels: false, - externalDashboardUrl: '/mockUrl', - }, - store, - }); - }); - it('shows the link', done => { - setTimeout(() => { - expect(component.$el.querySelector('.js-external-dashboard-link').innerText).toContain( - 'View full dashboard', - ); - done(); - }); + component = new DashboardComponent({ + el: document.querySelector('.prometheus-graphs'), + propsData: { + ...propsData, + hasMetrics: true, + showPanels: false, + showTimeWindowDropdown: false, + externalDashboardUrl: '/mockUrl', + }, + store, }); }); - describe('without feature flage enabled', () => { - beforeEach(() => { - window.gon.features.grafanaDashboardLink = false; - component = new DashboardComponent({ - el: document.querySelector('.prometheus-graphs'), - propsData: { - ...propsData, - hasMetrics: true, - showPanels: false, - externalDashboardUrl: '', - }, - store, - }); - }); - - it('does not show the link', done => { - setTimeout(() => { - expect(component.$el.querySelector('.js-external-dashboard-link')).toBe(null); - done(); - }); + it('shows the link', done => { + setTimeout(() => { + expect(component.$el.querySelector('.js-external-dashboard-link').innerText).toContain( + 'View full dashboard', + ); + done(); }); }); }); diff --git a/spec/javascripts/monitoring/mock_data.js b/spec/javascripts/monitoring/mock_data.js index d9d8cb66749..82e42fe9ade 100644 --- a/spec/javascripts/monitoring/mock_data.js +++ b/spec/javascripts/monitoring/mock_data.js @@ -857,3 +857,68 @@ export const environmentData = [ updated_at: '2018-07-04T18:44:54.010Z', }, ]; + +export const metricsDashboardResponse = { + dashboard: { + dashboard: 'Environment metrics', + priority: 1, + panel_groups: [ + { + group: 'System metrics (Kubernetes)', + priority: 5, + panels: [ + { + title: 'Memory Usage (Total)', + type: 'area-chart', + y_label: 'Total Memory Used', + weight: 4, + metrics: [ + { + id: 'system_metrics_kubernetes_container_memory_total', + query_range: + 'avg(sum(container_memory_usage_bytes{container_name!="POD",pod_name=~"^%{ci_environment_slug}-(.*)",namespace="%{kube_namespace}"}) by (job)) without (job) /1024/1024/1024', + label: 'Total', + unit: 'GB', + metric_id: 12, + prometheus_endpoint_path: 'http://test', + }, + ], + }, + { + title: 'Core Usage (Total)', + type: 'area-chart', + y_label: 'Total Cores', + weight: 3, + metrics: [ + { + id: 'system_metrics_kubernetes_container_cores_total', + query_range: + 'avg(sum(rate(container_cpu_usage_seconds_total{container_name!="POD",pod_name=~"^%{ci_environment_slug}-(.*)",namespace="%{kube_namespace}"}[15m])) by (job)) without (job)', + label: 'Total', + unit: 'cores', + metric_id: 13, + }, + ], + }, + { + title: 'Memory Usage (Pod average)', + type: 'area-chart', + y_label: 'Memory Used per Pod', + weight: 2, + metrics: [ + { + id: 'system_metrics_kubernetes_container_memory_average', + query_range: + 'avg(sum(container_memory_usage_bytes{container_name!="POD",pod_name=~"^%{ci_environment_slug}-(.*)",namespace="%{kube_namespace}"}) by (job)) without (job) / count(avg(container_memory_usage_bytes{container_name!="POD",pod_name=~"^%{ci_environment_slug}-(.*)",namespace="%{kube_namespace}"}) without (job)) /1024/1024', + label: 'Pod average', + unit: 'MB', + metric_id: 14, + }, + ], + }, + ], + }, + ], + }, + status: 'success', +}; diff --git a/spec/javascripts/monitoring/store/actions_spec.js b/spec/javascripts/monitoring/store/actions_spec.js index a848cd24fe3..083a01c4d74 100644 --- a/spec/javascripts/monitoring/store/actions_spec.js +++ b/spec/javascripts/monitoring/store/actions_spec.js @@ -3,8 +3,13 @@ import MockAdapter from 'axios-mock-adapter'; import store from '~/monitoring/stores'; import * as types from '~/monitoring/stores/mutation_types'; import { + fetchDashboard, + receiveMetricsDashboardSuccess, + receiveMetricsDashboardFailure, fetchDeploymentsData, fetchEnvironmentsData, + fetchPrometheusMetrics, + fetchPrometheusMetric, requestMetricsData, setEndpoints, setGettingStartedEmptyState, @@ -12,7 +17,12 @@ import { import storeState from '~/monitoring/stores/state'; import testAction from 'spec/helpers/vuex_action_helper'; import { resetStore } from '../helpers'; -import { deploymentData, environmentData } from '../mock_data'; +import { + deploymentData, + environmentData, + metricsDashboardResponse, + metricsGroupsAPIResponse, +} from '../mock_data'; describe('Monitoring store actions', () => { let mock; @@ -41,9 +51,9 @@ describe('Monitoring store actions', () => { it('commits RECEIVE_DEPLOYMENTS_DATA_SUCCESS on error', done => { const dispatch = jasmine.createSpy(); const { state } = store; - state.deploymentEndpoint = '/success'; + state.deploymentsEndpoint = '/success'; - mock.onGet(state.deploymentEndpoint).reply(200, { + mock.onGet(state.deploymentsEndpoint).reply(200, { deployments: deploymentData, }); @@ -58,9 +68,9 @@ describe('Monitoring store actions', () => { it('commits RECEIVE_DEPLOYMENTS_DATA_FAILURE on error', done => { const dispatch = jasmine.createSpy(); const { state } = store; - state.deploymentEndpoint = '/error'; + state.deploymentsEndpoint = '/error'; - mock.onGet(state.deploymentEndpoint).reply(500); + mock.onGet(state.deploymentsEndpoint).reply(500); fetchDeploymentsData({ state, dispatch }) .then(() => { @@ -155,4 +165,158 @@ describe('Monitoring store actions', () => { ); }); }); + + describe('fetchDashboard', () => { + let dispatch; + let state; + const response = metricsDashboardResponse; + + beforeEach(() => { + dispatch = jasmine.createSpy(); + state = storeState(); + state.dashboardEndpoint = '/dashboard'; + }); + + it('dispatches receive and success actions', done => { + const params = {}; + mock.onGet(state.dashboardEndpoint).reply(200, response); + + fetchDashboard({ state, dispatch }, params) + .then(() => { + expect(dispatch).toHaveBeenCalledWith('requestMetricsDashboard'); + expect(dispatch).toHaveBeenCalledWith('receiveMetricsDashboardSuccess', { + response, + params, + }); + done(); + }) + .catch(done.fail); + }); + + it('dispatches failure action', done => { + const params = {}; + mock.onGet(state.dashboardEndpoint).reply(500); + + fetchDashboard({ state, dispatch }, params) + .then(() => { + expect(dispatch).toHaveBeenCalledWith( + 'receiveMetricsDashboardFailure', + new Error('Request failed with status code 500'), + ); + done(); + }) + .catch(done.fail); + }); + }); + + describe('receiveMetricsDashboardSuccess', () => { + let commit; + let dispatch; + + beforeEach(() => { + commit = jasmine.createSpy(); + dispatch = jasmine.createSpy(); + }); + + it('stores groups ', () => { + const params = {}; + const response = metricsDashboardResponse; + + receiveMetricsDashboardSuccess({ commit, dispatch }, { response, params }); + + expect(commit).toHaveBeenCalledWith( + types.RECEIVE_METRICS_DATA_SUCCESS, + metricsDashboardResponse.dashboard.panel_groups, + ); + + expect(dispatch).toHaveBeenCalledWith('fetchPrometheusMetrics', params); + }); + }); + + describe('receiveMetricsDashboardFailure', () => { + let commit; + + beforeEach(() => { + commit = jasmine.createSpy(); + }); + + it('commits failure action', () => { + receiveMetricsDashboardFailure({ commit }); + + expect(commit).toHaveBeenCalledWith(types.RECEIVE_METRICS_DATA_FAILURE, undefined); + }); + + it('commits failure action with error', () => { + receiveMetricsDashboardFailure({ commit }, 'uh-oh'); + + expect(commit).toHaveBeenCalledWith(types.RECEIVE_METRICS_DATA_FAILURE, 'uh-oh'); + }); + }); + + describe('fetchPrometheusMetrics', () => { + let commit; + let dispatch; + + beforeEach(() => { + commit = jasmine.createSpy(); + dispatch = jasmine.createSpy(); + }); + + it('commits empty state when state.groups is empty', done => { + const state = storeState(); + const params = {}; + + fetchPrometheusMetrics({ state, commit, dispatch }, params) + .then(() => { + expect(commit).toHaveBeenCalledWith(types.SET_NO_DATA_EMPTY_STATE); + expect(dispatch).not.toHaveBeenCalled(); + done(); + }) + .catch(done.fail); + }); + + it('dispatches fetchPrometheusMetric for each panel query', done => { + const params = {}; + const state = storeState(); + state.groups = metricsDashboardResponse.dashboard.panel_groups; + + const metric = state.groups[0].panels[0].metrics[0]; + + fetchPrometheusMetrics({ state, commit, dispatch }, params) + .then(() => { + expect(dispatch.calls.count()).toEqual(3); + expect(dispatch).toHaveBeenCalledWith('fetchPrometheusMetric', { metric, params }); + done(); + }) + .catch(done.fail); + + done(); + }); + }); + + describe('fetchPrometheusMetric', () => { + it('commits prometheus query result', done => { + const commit = jasmine.createSpy(); + const params = { + start: '1557216349.469', + end: '1557218149.469', + }; + const metric = metricsDashboardResponse.dashboard.panel_groups[0].panels[0].metrics[0]; + const state = storeState(); + + const data = metricsGroupsAPIResponse.data[0].metrics[0].queries[0]; + const response = { data }; + mock.onGet('http://test').reply(200, response); + + fetchPrometheusMetric({ state, commit }, { metric, params }); + + setTimeout(() => { + expect(commit).toHaveBeenCalledWith(types.SET_QUERY_RESULT, { + metricId: metric.metric_id, + result: data.result, + }); + done(); + }); + }); + }); }); diff --git a/spec/javascripts/monitoring/store/mutations_spec.js b/spec/javascripts/monitoring/store/mutations_spec.js index 882ee1dec14..02ff5847b34 100644 --- a/spec/javascripts/monitoring/store/mutations_spec.js +++ b/spec/javascripts/monitoring/store/mutations_spec.js @@ -1,7 +1,7 @@ import mutations from '~/monitoring/stores/mutations'; import * as types from '~/monitoring/stores/mutation_types'; import state from '~/monitoring/stores/state'; -import { metricsGroupsAPIResponse, deploymentData } from '../mock_data'; +import { metricsGroupsAPIResponse, deploymentData, metricsDashboardResponse } from '../mock_data'; describe('Monitoring mutations', () => { let stateCopy; @@ -11,14 +11,16 @@ describe('Monitoring mutations', () => { }); describe(types.RECEIVE_METRICS_DATA_SUCCESS, () => { + let groups; + beforeEach(() => { stateCopy.groups = []; - const groups = metricsGroupsAPIResponse.data; - - mutations[types.RECEIVE_METRICS_DATA_SUCCESS](stateCopy, groups); + groups = metricsGroupsAPIResponse.data; }); it('normalizes values', () => { + mutations[types.RECEIVE_METRICS_DATA_SUCCESS](stateCopy, groups); + const expectedTimestamp = '2017-05-25T08:22:34.925Z'; const expectedValue = 0.0010794445585559514; const [timestamp, value] = stateCopy.groups[0].metrics[0].queries[0].result[0].values[0]; @@ -28,22 +30,27 @@ describe('Monitoring mutations', () => { }); it('contains two groups that contains, one of which has two queries sorted by priority', () => { + mutations[types.RECEIVE_METRICS_DATA_SUCCESS](stateCopy, groups); + expect(stateCopy.groups).toBeDefined(); expect(stateCopy.groups.length).toEqual(2); expect(stateCopy.groups[0].metrics.length).toEqual(2); }); it('assigns queries a metric id', () => { + mutations[types.RECEIVE_METRICS_DATA_SUCCESS](stateCopy, groups); + expect(stateCopy.groups[1].metrics[0].queries[0].metricId).toEqual('100'); }); it('removes the data if all the values from a query are not defined', () => { + mutations[types.RECEIVE_METRICS_DATA_SUCCESS](stateCopy, groups); + expect(stateCopy.groups[1].metrics[0].queries[0].result.length).toEqual(0); }); it('assigns metric id of null if metric has no id', () => { stateCopy.groups = []; - const groups = metricsGroupsAPIResponse.data; const noId = groups.map(group => ({ ...group, ...{ @@ -63,6 +70,26 @@ describe('Monitoring mutations', () => { }); }); }); + + describe('dashboard endpoint enabled', () => { + const dashboardGroups = metricsDashboardResponse.dashboard.panel_groups; + + beforeEach(() => { + stateCopy.useDashboardEndpoint = true; + }); + + it('aliases group panels to metrics for backwards compatibility', () => { + mutations[types.RECEIVE_METRICS_DATA_SUCCESS](stateCopy, dashboardGroups); + + expect(stateCopy.groups[0].metrics[0]).toBeDefined(); + }); + + it('aliases panel metrics to queries for backwards compatibility', () => { + mutations[types.RECEIVE_METRICS_DATA_SUCCESS](stateCopy, dashboardGroups); + + expect(stateCopy.groups[0].metrics[0].queries).toBeDefined(); + }); + }); }); describe(types.RECEIVE_DEPLOYMENTS_DATA_SUCCESS, () => { @@ -82,11 +109,51 @@ describe('Monitoring mutations', () => { metricsEndpoint: 'additional_metrics.json', environmentsEndpoint: 'environments.json', deploymentsEndpoint: 'deployments.json', + dashboardEndpoint: 'dashboard.json', }); expect(stateCopy.metricsEndpoint).toEqual('additional_metrics.json'); expect(stateCopy.environmentsEndpoint).toEqual('environments.json'); expect(stateCopy.deploymentsEndpoint).toEqual('deployments.json'); + expect(stateCopy.dashboardEndpoint).toEqual('dashboard.json'); + }); + }); + + describe('SET_QUERY_RESULT', () => { + const metricId = 12; + const result = [{ values: [[0, 1], [1, 1], [1, 3]] }]; + + beforeEach(() => { + stateCopy.useDashboardEndpoint = true; + const dashboardGroups = metricsDashboardResponse.dashboard.panel_groups; + mutations[types.RECEIVE_METRICS_DATA_SUCCESS](stateCopy, dashboardGroups); + }); + + it('clears empty state', () => { + mutations[types.SET_QUERY_RESULT](stateCopy, { + metricId, + result, + }); + + expect(stateCopy.showEmptyState).toBe(false); + }); + + it('sets metricsWithData value', () => { + mutations[types.SET_QUERY_RESULT](stateCopy, { + metricId, + result, + }); + + expect(stateCopy.metricsWithData).toEqual([12]); + }); + + it('does not store empty results', () => { + mutations[types.SET_QUERY_RESULT](stateCopy, { + metricId, + result: [], + }); + + expect(stateCopy.metricsWithData).toEqual([]); }); }); }); |
