diff options
Diffstat (limited to 'spec/frontend/monitoring/utils_spec.js')
-rw-r--r-- | spec/frontend/monitoring/utils_spec.js | 302 |
1 files changed, 270 insertions, 32 deletions
diff --git a/spec/frontend/monitoring/utils_spec.js b/spec/frontend/monitoring/utils_spec.js index 0bb1b987b2e..aa5a4459a72 100644 --- a/spec/frontend/monitoring/utils_spec.js +++ b/spec/frontend/monitoring/utils_spec.js @@ -1,15 +1,13 @@ import * as monitoringUtils from '~/monitoring/utils'; -import { queryToObject, mergeUrlParams, removeParams } from '~/lib/utils/url_utility'; +import * as urlUtils from '~/lib/utils/url_utility'; import { TEST_HOST } from 'jest/helpers/test_constants'; import { mockProjectDir, - graphDataPrometheusQuery, + singleStatMetricsResult, anomalyMockGraphData, barMockData, } from './mock_data'; -import { graphData } from './fixture_data'; - -jest.mock('~/lib/utils/url_utility'); +import { metricsDashboardViewModel, graphData } from './fixture_data'; const mockPath = `${TEST_HOST}${mockProjectDir}/-/environments/29/metrics`; @@ -27,11 +25,6 @@ const rollingRange = { }; describe('monitoring/utils', () => { - afterEach(() => { - mergeUrlParams.mockReset(); - queryToObject.mockReset(); - }); - describe('trackGenerateLinkToChartEventOptions', () => { it('should return Cluster Monitoring options if located on Cluster Health Dashboard', () => { document.body.dataset.page = 'groups:clusters:show'; @@ -89,7 +82,7 @@ describe('monitoring/utils', () => { it('validates data with the query format', () => { const validGraphData = monitoringUtils.graphDataValidatorForValues( true, - graphDataPrometheusQuery, + singleStatMetricsResult, ); expect(validGraphData).toBe(true); @@ -112,7 +105,7 @@ describe('monitoring/utils', () => { let threeMetrics; let fourMetrics; beforeEach(() => { - oneMetric = graphDataPrometheusQuery; + oneMetric = singleStatMetricsResult; threeMetrics = anomalyMockGraphData; const metrics = [...threeMetrics.metrics]; @@ -139,18 +132,25 @@ describe('monitoring/utils', () => { }); describe('timeRangeFromUrl', () => { - const { timeRangeFromUrl } = monitoringUtils; + beforeEach(() => { + jest.spyOn(urlUtils, 'queryToObject'); + }); + + afterEach(() => { + urlUtils.queryToObject.mockRestore(); + }); - it('returns a fixed range when query contains `start` and `end` paramters are given', () => { - queryToObject.mockReturnValueOnce(range); + const { timeRangeFromUrl } = monitoringUtils; + it('returns a fixed range when query contains `start` and `end` parameters are given', () => { + urlUtils.queryToObject.mockReturnValueOnce(range); expect(timeRangeFromUrl()).toEqual(range); }); - it('returns a rolling range when query contains `duration_seconds` paramters are given', () => { + it('returns a rolling range when query contains `duration_seconds` parameters are given', () => { const { seconds } = rollingRange.duration; - queryToObject.mockReturnValueOnce({ + urlUtils.queryToObject.mockReturnValueOnce({ dashboard: '.gitlab/dashboard/my_dashboard.yml', duration_seconds: `${seconds}`, }); @@ -158,23 +158,59 @@ describe('monitoring/utils', () => { expect(timeRangeFromUrl()).toEqual(rollingRange); }); - it('returns null when no time range paramters are given', () => { - const params = { + it('returns null when no time range parameters are given', () => { + urlUtils.queryToObject.mockReturnValueOnce({ dashboard: '.gitlab/dashboards/custom_dashboard.yml', param1: 'value1', param2: 'value2', - }; + }); - expect(timeRangeFromUrl(params, mockPath)).toBe(null); + expect(timeRangeFromUrl()).toBe(null); + }); + }); + + describe('getPromCustomVariablesFromUrl', () => { + const { getPromCustomVariablesFromUrl } = monitoringUtils; + + beforeEach(() => { + jest.spyOn(urlUtils, 'queryToObject'); + }); + + afterEach(() => { + urlUtils.queryToObject.mockRestore(); + }); + + it('returns an object with only the custom variables', () => { + urlUtils.queryToObject.mockReturnValueOnce({ + dashboard: '.gitlab/dashboards/custom_dashboard.yml', + y_label: 'memory usage', + group: 'kubernetes', + title: 'Kubernetes memory total', + start: '2020-05-06', + end: '2020-05-07', + duration_seconds: '86400', + direction: 'left', + anchor: 'top', + pod: 'POD', + 'var-pod': 'POD', + }); + + expect(getPromCustomVariablesFromUrl()).toEqual(expect.objectContaining({ pod: 'POD' })); + }); + + it('returns an empty object when no custom variables are present', () => { + urlUtils.queryToObject.mockReturnValueOnce({ + dashboard: '.gitlab/dashboards/custom_dashboard.yml', + }); + + expect(getPromCustomVariablesFromUrl()).toStrictEqual({}); }); }); describe('removeTimeRangeParams', () => { const { removeTimeRangeParams } = monitoringUtils; - it('returns when query contains `start` and `end` paramters are given', () => { - removeParams.mockReturnValueOnce(mockPath); - + it('returns when query contains `start` and `end` parameters are given', () => { expect(removeTimeRangeParams(`${mockPath}?start=${range.start}&end=${range.end}`)).toEqual( mockPath, ); @@ -184,28 +220,126 @@ describe('monitoring/utils', () => { describe('timeRangeToUrl', () => { const { timeRangeToUrl } = monitoringUtils; - it('returns a fixed range when query contains `start` and `end` paramters are given', () => { + beforeEach(() => { + jest.spyOn(urlUtils, 'mergeUrlParams'); + jest.spyOn(urlUtils, 'removeParams'); + }); + + afterEach(() => { + urlUtils.mergeUrlParams.mockRestore(); + urlUtils.removeParams.mockRestore(); + }); + + it('returns a fixed range when query contains `start` and `end` parameters are given', () => { const toUrl = `${mockPath}?start=${range.start}&end=${range.end}`; const fromUrl = mockPath; - removeParams.mockReturnValueOnce(fromUrl); - mergeUrlParams.mockReturnValueOnce(toUrl); + urlUtils.removeParams.mockReturnValueOnce(fromUrl); + urlUtils.mergeUrlParams.mockReturnValueOnce(toUrl); expect(timeRangeToUrl(range)).toEqual(toUrl); - expect(mergeUrlParams).toHaveBeenCalledWith(range, fromUrl); + expect(urlUtils.mergeUrlParams).toHaveBeenCalledWith(range, fromUrl); }); - it('returns a rolling range when query contains `duration_seconds` paramters are given', () => { + it('returns a rolling range when query contains `duration_seconds` parameters are given', () => { const { seconds } = rollingRange.duration; const toUrl = `${mockPath}?duration_seconds=${seconds}`; const fromUrl = mockPath; - removeParams.mockReturnValueOnce(fromUrl); - mergeUrlParams.mockReturnValueOnce(toUrl); + urlUtils.removeParams.mockReturnValueOnce(fromUrl); + urlUtils.mergeUrlParams.mockReturnValueOnce(toUrl); expect(timeRangeToUrl(rollingRange)).toEqual(toUrl); - expect(mergeUrlParams).toHaveBeenCalledWith({ duration_seconds: `${seconds}` }, fromUrl); + expect(urlUtils.mergeUrlParams).toHaveBeenCalledWith( + { duration_seconds: `${seconds}` }, + fromUrl, + ); + }); + }); + + describe('expandedPanelPayloadFromUrl', () => { + const { expandedPanelPayloadFromUrl } = monitoringUtils; + const [panelGroup] = metricsDashboardViewModel.panelGroups; + const [panel] = panelGroup.panels; + + const { group } = panelGroup; + const { title, y_label: yLabel } = panel; + + it('returns payload for a panel when query parameters are given', () => { + const search = `?group=${group}&title=${title}&y_label=${yLabel}`; + + expect(expandedPanelPayloadFromUrl(metricsDashboardViewModel, search)).toEqual({ + group: panelGroup.group, + panel, + }); + }); + + it('returns null when no parameters are given', () => { + expect(expandedPanelPayloadFromUrl(metricsDashboardViewModel, '')).toBe(null); + }); + + it('throws an error when no group is provided', () => { + const search = `?title=${panel.title}&y_label=${yLabel}`; + expect(() => expandedPanelPayloadFromUrl(metricsDashboardViewModel, search)).toThrow(); + }); + + it('throws an error when no title is provided', () => { + const search = `?title=${title}&y_label=${yLabel}`; + expect(() => expandedPanelPayloadFromUrl(metricsDashboardViewModel, search)).toThrow(); + }); + + it('throws an error when no y_label group is provided', () => { + const search = `?group=${group}&title=${title}`; + expect(() => expandedPanelPayloadFromUrl(metricsDashboardViewModel, search)).toThrow(); + }); + + test.each` + group | title | yLabel | missingField + ${'NOT_A_GROUP'} | ${title} | ${yLabel} | ${'group'} + ${group} | ${'NOT_A_TITLE'} | ${yLabel} | ${'title'} + ${group} | ${title} | ${'NOT_A_Y_LABEL'} | ${'y_label'} + `('throws an error when $missingField is incorrect', params => { + const search = `?group=${params.group}&title=${params.title}&y_label=${params.yLabel}`; + expect(() => expandedPanelPayloadFromUrl(metricsDashboardViewModel, search)).toThrow(); + }); + }); + + describe('panelToUrl', () => { + const { panelToUrl } = monitoringUtils; + + const dashboard = 'metrics.yml'; + const [panelGroup] = metricsDashboardViewModel.panelGroups; + const [panel] = panelGroup.panels; + + const getUrlParams = url => urlUtils.queryToObject(url.split('?')[1]); + + it('returns URL for a panel when query parameters are given', () => { + const params = getUrlParams(panelToUrl(dashboard, {}, panelGroup.group, panel)); + + expect(params).toEqual( + expect.objectContaining({ + dashboard, + group: panelGroup.group, + title: panel.title, + y_label: panel.y_label, + }), + ); + }); + + it('returns a dashboard only URL if group is missing', () => { + const params = getUrlParams(panelToUrl(dashboard, {}, null, panel)); + expect(params).toEqual(expect.objectContaining({ dashboard: 'metrics.yml' })); + }); + + it('returns a dashboard only URL if panel is missing', () => { + const params = getUrlParams(panelToUrl(dashboard, {}, panelGroup.group, null)); + expect(params).toEqual(expect.objectContaining({ dashboard: 'metrics.yml' })); + }); + + it('returns URL for a panel when query paramters are given including custom variables', () => { + const params = getUrlParams(panelToUrl(dashboard, { pod: 'pod' }, panelGroup.group, null)); + expect(params).toEqual(expect.objectContaining({ dashboard: 'metrics.yml', pod: 'pod' })); }); }); @@ -271,4 +405,108 @@ describe('monitoring/utils', () => { }); }); }); + + describe('removePrefixFromLabel', () => { + it.each` + input | expected + ${undefined} | ${''} + ${null} | ${''} + ${''} | ${''} + ${' '} | ${' '} + ${'pod-1'} | ${'pod-1'} + ${'pod-var-1'} | ${'pod-var-1'} + ${'pod-1-var'} | ${'pod-1-var'} + ${'podvar--1'} | ${'podvar--1'} + ${'povar-d-1'} | ${'povar-d-1'} + ${'var-pod-1'} | ${'pod-1'} + ${'var-var-pod-1'} | ${'var-pod-1'} + ${'varvar-pod-1'} | ${'varvar-pod-1'} + ${'var-pod-1-var-'} | ${'pod-1-var-'} + `('removePrefixFromLabel returns $expected with input $input', ({ input, expected }) => { + expect(monitoringUtils.removePrefixFromLabel(input)).toEqual(expected); + }); + }); + + describe('mergeURLVariables', () => { + beforeEach(() => { + jest.spyOn(urlUtils, 'queryToObject'); + }); + + afterEach(() => { + urlUtils.queryToObject.mockRestore(); + }); + + it('returns empty object if variables are not defined in yml or URL', () => { + urlUtils.queryToObject.mockReturnValueOnce({}); + + expect(monitoringUtils.mergeURLVariables({})).toEqual({}); + }); + + it('returns empty object if variables are defined in URL but not in yml', () => { + urlUtils.queryToObject.mockReturnValueOnce({ + 'var-env': 'one', + 'var-instance': 'localhost', + }); + + expect(monitoringUtils.mergeURLVariables({})).toEqual({}); + }); + + it('returns yml variables if variables defined in yml but not in the URL', () => { + urlUtils.queryToObject.mockReturnValueOnce({}); + + const params = { + env: 'one', + instance: 'localhost', + }; + + expect(monitoringUtils.mergeURLVariables(params)).toEqual(params); + }); + + it('returns yml variables if variables defined in URL do not match with yml variables', () => { + const urlParams = { + 'var-env': 'one', + 'var-instance': 'localhost', + }; + const ymlParams = { + pod: { value: 'one' }, + service: { value: 'database' }, + }; + urlUtils.queryToObject.mockReturnValueOnce(urlParams); + + expect(monitoringUtils.mergeURLVariables(ymlParams)).toEqual(ymlParams); + }); + + it('returns merged yml and URL variables if there is some match', () => { + const urlParams = { + 'var-env': 'one', + 'var-instance': 'localhost:8080', + }; + const ymlParams = { + instance: { value: 'localhost' }, + service: { value: 'database' }, + }; + + const merged = { + instance: { value: 'localhost:8080' }, + service: { value: 'database' }, + }; + + urlUtils.queryToObject.mockReturnValueOnce(urlParams); + + expect(monitoringUtils.mergeURLVariables(ymlParams)).toEqual(merged); + }); + }); + + describe('convertVariablesForURL', () => { + it.each` + input | expected + ${undefined} | ${{}} + ${null} | ${{}} + ${{}} | ${{}} + ${{ env: { value: 'prod' } }} | ${{ 'var-env': 'prod' }} + ${{ 'var-env': { value: 'prod' } }} | ${{ 'var-var-env': 'prod' }} + `('convertVariablesForURL returns $expected with input $input', ({ input, expected }) => { + expect(monitoringUtils.convertVariablesForURL(input)).toEqual(expected); + }); + }); }); |