From 987afeee387245052b813626dd6d5e8fb9d1aaba Mon Sep 17 00:00:00 2001 From: Andres Martinez Gotor Date: Thu, 24 Mar 2022 01:47:59 -0700 Subject: [PATCH] Chore: Cover CloudMonitoring function utils with tests (#46878) --- .../cloud-monitoring/functions.test.ts | 197 +++++++++++++++++- .../datasource/cloud-monitoring/functions.ts | 33 +-- .../cloud-monitoring/specs/testData.ts | 38 ++++ 3 files changed, 237 insertions(+), 31 deletions(-) diff --git a/public/app/plugins/datasource/cloud-monitoring/functions.test.ts b/public/app/plugins/datasource/cloud-monitoring/functions.test.ts index 89539459494..118e76f4930 100644 --- a/public/app/plugins/datasource/cloud-monitoring/functions.test.ts +++ b/public/app/plugins/datasource/cloud-monitoring/functions.test.ts @@ -1,9 +1,126 @@ -import { getAlignmentOptionsByMetric } from './functions'; -import { ValueTypes, MetricKind } from './types'; +import { AGGREGATIONS, SYSTEM_LABELS } from './constants'; +import { + extractServicesFromMetricDescriptors, + getAggregationOptionsByMetric, + getAlignmentOptionsByMetric, + getAlignmentPickerData, + getLabelKeys, + getMetricTypes, + getMetricTypesByService, + labelsToGroupedOptions, + stringArrayToFilters, +} from './functions'; +import { newMockDatasource } from './specs/testData'; +import { AlignmentTypes, MetricDescriptor, MetricKind, ValueTypes } from './types'; + +jest.mock('@grafana/runtime', () => ({ + ...(jest.requireActual('@grafana/runtime') as unknown as object), + getTemplateSrv: () => ({ + replace: jest.fn().mockImplementation((s: string) => s), + }), +})); describe('functions', () => { - let result: any; + describe('extractServicesFromMetricDescriptors', () => { + it('should return unique metric descriptors', () => { + const desc: MetricDescriptor = { + valueType: '', + metricKind: MetricKind.CUMULATIVE, + type: '', + unit: '', + service: '1', + serviceShortName: '', + displayName: '', + description: '', + }; + expect(extractServicesFromMetricDescriptors([desc, desc])).toEqual([desc]); + }); + }); + + describe('getMetricTypesByService', () => { + it('filters by metric descriptiors', () => { + const desc1: MetricDescriptor = { + valueType: '', + metricKind: MetricKind.CUMULATIVE, + type: '', + unit: '', + service: '1', + serviceShortName: '', + displayName: '', + description: '', + }; + const desc2: MetricDescriptor = { + valueType: '', + metricKind: MetricKind.CUMULATIVE, + type: '', + unit: '', + service: '2', + serviceShortName: '', + displayName: '', + description: '', + }; + expect(getMetricTypesByService([desc1, desc2], '1')).toEqual([desc1]); + }); + }); + + describe('getMetricTypes', () => { + it('gets metric type that exists in the array', () => { + const desc1: MetricDescriptor = { + valueType: '', + metricKind: MetricKind.CUMULATIVE, + type: '1', + unit: '', + service: 'svc1', + serviceShortName: '', + displayName: 'uno', + description: '', + }; + const desc2: MetricDescriptor = { + valueType: '', + metricKind: MetricKind.CUMULATIVE, + type: '2', + unit: '', + service: 'svc2', + serviceShortName: '', + displayName: 'dos', + description: '', + }; + expect(getMetricTypes([desc1, desc2], '1', '1', 'svc1')).toEqual({ + metricTypes: [{ name: 'uno', value: '1' }], + selectedMetricType: '1', + }); + }); + + it('gets metric type that does not exist in the array', () => { + const desc1: MetricDescriptor = { + valueType: '', + metricKind: MetricKind.CUMULATIVE, + type: '1', + unit: '', + service: 'svc1', + serviceShortName: '', + displayName: 'uno', + description: '', + }; + const desc2: MetricDescriptor = { + valueType: '', + metricKind: MetricKind.CUMULATIVE, + type: '2', + unit: '', + service: 'svc2', + serviceShortName: '', + displayName: 'dos', + description: '', + }; + expect(getMetricTypes([desc1, desc2], '3', '4', 'svc1')).toEqual({ + metricTypes: [{ name: 'uno', value: '1' }], + selectedMetricType: '1', + }); + }); + }); + describe('getAlignmentOptionsByMetric', () => { + let result: any; describe('when double and gauge is passed', () => { beforeEach(() => { result = getAlignmentOptionsByMetric(ValueTypes.DOUBLE, MetricKind.GAUGE); @@ -35,4 +152,78 @@ describe('functions', () => { }); }); }); + + describe('getAggregationOptionsByMetric', () => { + it('gets a result for a type and a metric kind', () => { + expect(getAggregationOptionsByMetric(ValueTypes.BOOL, MetricKind.CUMULATIVE)).toEqual([ + AGGREGATIONS[0], + AGGREGATIONS[6], + ]); + }); + }); + + describe('getLabelKeys', () => { + it('should return labels', async () => { + const ds = newMockDatasource(); + ds.getLabels = jest.fn().mockResolvedValue({ l1: true, l2: true }); + expect(await getLabelKeys(ds, 'type', 'project')).toEqual(['l1', 'l2', ...SYSTEM_LABELS]); + }); + }); + + describe('getAlignmentPickerData', () => { + it('should return default data', () => { + const res = getAlignmentPickerData(); + expect(res.alignOptions).toHaveLength(9); + expect(res.perSeriesAligner).toEqual(AlignmentTypes.ALIGN_MEAN); + }); + + it('should use provided data', () => { + const res = getAlignmentPickerData(ValueTypes.BOOL, MetricKind.CUMULATIVE); + expect(res.alignOptions).toHaveLength(0); + expect(res.perSeriesAligner).toEqual(AlignmentTypes.ALIGN_MEAN); + }); + }); + + describe('labelsToGroupedOptions', () => { + it('should group in the same label', () => { + expect(labelsToGroupedOptions(['foo', 'bar'])).toEqual([ + { + expanded: true, + label: '', + options: [ + { label: 'foo', value: 'foo' }, + { label: 'bar', value: 'bar' }, + ], + }, + ]); + }); + + it('should group in different labels', () => { + expect(labelsToGroupedOptions(['foo.bar', 'foobar'])).toEqual([ + { + expanded: true, + label: 'Foo Bar', + options: [{ label: 'foo.bar', value: 'foo.bar' }], + }, + { + expanded: true, + label: '', + options: [{ label: 'foobar', value: 'foobar' }], + }, + ]); + }); + }); + + describe('stringArrayToFilters', () => { + it('chunks an array', () => { + expect(stringArrayToFilters(['key', 'operator', 'value', 'condition'])).toEqual([ + { + condition: 'condition', + key: 'key', + operator: 'operator', + value: 'value', + }, + ]); + }); + }); }); diff --git a/public/app/plugins/datasource/cloud-monitoring/functions.ts b/public/app/plugins/datasource/cloud-monitoring/functions.ts index f5a6e238a82..6c37c962ec6 100644 --- a/public/app/plugins/datasource/cloud-monitoring/functions.ts +++ b/public/app/plugins/datasource/cloud-monitoring/functions.ts @@ -1,8 +1,9 @@ -import { chunk, flatten, initial, startCase, uniqBy } from 'lodash'; -import { ALIGNMENTS, AGGREGATIONS, SYSTEM_LABELS } from './constants'; +import { getTemplateSrv, TemplateSrv } from '@grafana/runtime'; +import { chunk, initial, startCase, uniqBy } from 'lodash'; + +import { AGGREGATIONS, ALIGNMENTS, SYSTEM_LABELS } from './constants'; import CloudMonitoringDatasource from './datasource'; -import { TemplateSrv, getTemplateSrv } from '@grafana/runtime'; -import { MetricDescriptor, ValueTypes, MetricKind, AlignmentTypes, PreprocessorType, Filter } from './types'; +import { AlignmentTypes, MetricDescriptor, MetricKind, PreprocessorType, ValueTypes } from './types'; const templateSrv: TemplateSrv = getTemplateSrv(); @@ -104,11 +105,6 @@ export const labelsToGroupedOptions = (groupBys: string[]) => { return Object.entries(groups).map(([label, options]) => ({ label, options, expanded: true }), []); }; -export const filtersToStringArray = (filters: Filter[]) => { - const strArr = flatten(filters.map(({ key, operator, value, condition }) => [key, operator, value, condition!])); - return strArr.filter((_, i) => i !== strArr.length - 1); -}; - export const stringArrayToFilters = (filterArray: string[]) => chunk(filterArray, 4).map(([key, operator, value, condition = 'AND']) => ({ key, @@ -116,22 +112,3 @@ export const stringArrayToFilters = (filterArray: string[]) => value, condition, })); - -export const formatCloudMonitoringError = (error: any) => { - let message = error.statusText ?? ''; - if (error.data && error.data.error) { - try { - const res = JSON.parse(error.data.error); - message += res.error.code + '. ' + res.error.message; - } catch (err) { - message += error.data.error; - } - } else if (error.data && error.data.message) { - try { - message = JSON.parse(error.data.message).error.message; - } catch (err) { - error.error = err; - } - } - return message; -}; diff --git a/public/app/plugins/datasource/cloud-monitoring/specs/testData.ts b/public/app/plugins/datasource/cloud-monitoring/specs/testData.ts index b97aad7c6ce..91a3456ecf2 100644 --- a/public/app/plugins/datasource/cloud-monitoring/specs/testData.ts +++ b/public/app/plugins/datasource/cloud-monitoring/specs/testData.ts @@ -1,3 +1,8 @@ +import { PluginType } from '@grafana/data'; +import { GoogleAuthType } from '@grafana/google-sdk'; + +import CloudMonitoringDatasource from '../datasource'; + export const metricDescriptors = [ { name: 'projects/grafana-prod/metricDescriptors/agent.googleapis.com/agent/api_request_count', @@ -40,3 +45,36 @@ export const metricDescriptors = [ }, }, ]; + +export const newMockDatasource = () => + new CloudMonitoringDatasource({ + id: 1, + uid: 'cm-id', + type: 'cloud-monitoring-datasource', + name: 'Cloud Monitoring Data Source', + jsonData: { + authenticationType: GoogleAuthType.JWT, + }, + access: 'proxy', + meta: { + id: 'cloud-monitoring-datasource', + name: 'Cloud Monitoring Data Source', + type: PluginType.datasource, + module: '', + baseUrl: '', + info: { + description: '', + screenshots: [], + updated: '', + version: '', + logos: { + small: '', + large: '', + }, + author: { + name: '', + }, + links: [], + }, + }, + });