CloudWatch: Remove error message when using multi-valued template vars in region field (#45886)

* don't show error message when using multi-valued template variables in region field

* add unit tests

* remove commented code
pull/45636/head^2
Erik Sundell 3 years ago committed by GitHub
parent 1b2c4dca61
commit 1df040eb23
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 7
      public/app/plugins/datasource/cloudwatch/__mocks__/CloudWatchDataSource.ts
  2. 9
      public/app/plugins/datasource/cloudwatch/components/QueryHeader.tsx
  3. 65
      public/app/plugins/datasource/cloudwatch/datasource.test.ts
  4. 42
      public/app/plugins/datasource/cloudwatch/datasource.ts

@ -1,11 +1,12 @@
import { dateTime } from '@grafana/data'; import { dateTime } from '@grafana/data';
import { setBackendSrv } from '@grafana/runtime'; import { setBackendSrv } from '@grafana/runtime';
import { TemplateSrvMock } from '../../../../features/templating/template_srv.mock'; import { TemplateSrv } from 'app/features/templating/template_srv';
import { initialCustomVariableModelState } from 'app/features/variables/custom/reducer'; import { initialCustomVariableModelState } from 'app/features/variables/custom/reducer';
import { CustomVariableModel } from 'app/features/variables/types'; import { CustomVariableModel } from 'app/features/variables/types';
import { of } from 'rxjs'; import { of } from 'rxjs';
import { TemplateSrvMock } from '../../../../features/templating/template_srv.mock';
import { CloudWatchDatasource } from '../datasource'; import { CloudWatchDatasource } from '../datasource';
import { TemplateSrv } from 'app/features/templating/template_srv';
export function setupMockedDataSource({ data = [], variables }: { data?: any; variables?: any } = {}) { export function setupMockedDataSource({ data = [], variables }: { data?: any; variables?: any } = {}) {
let templateService = new TemplateSrvMock({ let templateService = new TemplateSrvMock({
@ -16,6 +17,8 @@ export function setupMockedDataSource({ data = [], variables }: { data?: any; va
if (variables) { if (variables) {
templateService = new TemplateSrv(); templateService = new TemplateSrv();
templateService.init(variables); templateService.init(variables);
templateService.getVariables = jest.fn().mockReturnValue(variables);
templateService.getVariableName = (name: string) => name;
} }
const datasource = new CloudWatchDatasource( const datasource = new CloudWatchDatasource(

@ -1,12 +1,11 @@
import React from 'react';
import { pick } from 'lodash';
import { ExploreMode, SelectableValue } from '@grafana/data'; import { ExploreMode, SelectableValue } from '@grafana/data';
import { EditorHeader, InlineSelect } from '@grafana/experimental'; import { EditorHeader, InlineSelect } from '@grafana/experimental';
import { pick } from 'lodash';
import React from 'react';
import { CloudWatchDatasource } from '../datasource'; import { CloudWatchDatasource } from '../datasource';
import { CloudWatchQuery, CloudWatchQueryMode } from '../types';
import { useRegions } from '../hooks'; import { useRegions } from '../hooks';
import { CloudWatchQuery, CloudWatchQueryMode } from '../types';
import MetricsQueryHeader from './MetricsQueryHeader'; import MetricsQueryHeader from './MetricsQueryHeader';
interface QueryHeaderProps { interface QueryHeaderProps {
@ -59,7 +58,7 @@ const QueryHeader: React.FC<QueryHeaderProps> = ({
<EditorHeader> <EditorHeader>
<InlineSelect <InlineSelect
label="Region" label="Region"
value={regions.find((v) => v.value === region)} value={region}
placeholder="Select region" placeholder="Select region"
allowCustomValue allowCustomValue
onChange={({ value: region }) => region && onRegion({ value: region })} onChange={({ value: region }) => region && onRegion({ value: region })}

@ -1,17 +1,17 @@
import { lastValueFrom, of } from 'rxjs';
import { setDataSourceSrv } from '@grafana/runtime';
import { ArrayVector, DataFrame, dataFrameToJSON, dateTime, Field, MutableDataFrame } from '@grafana/data'; import { ArrayVector, DataFrame, dataFrameToJSON, dateTime, Field, MutableDataFrame } from '@grafana/data';
import { setDataSourceSrv } from '@grafana/runtime';
import { lastValueFrom, of } from 'rxjs';
import { toArray } from 'rxjs/operators'; import { toArray } from 'rxjs/operators';
import { CloudWatchMetricsQuery, MetricEditorMode, MetricQueryType, CloudWatchLogsQueryStatus } from './types';
import { import {
setupMockedDataSource,
namespaceVariable,
metricVariable,
labelsVariable, labelsVariable,
limitVariable, limitVariable,
metricVariable,
namespaceVariable,
setupMockedDataSource,
} from './__mocks__/CloudWatchDataSource'; } from './__mocks__/CloudWatchDataSource';
import { CloudWatchDatasource } from './datasource'; import { CloudWatchDatasource } from './datasource';
import { CloudWatchLogsQueryStatus, CloudWatchMetricsQuery, MetricEditorMode, MetricQueryType } from './types';
describe('datasource', () => { describe('datasource', () => {
describe('query', () => { describe('query', () => {
@ -91,6 +91,57 @@ describe('datasource', () => {
}, },
]); ]);
}); });
describe('debouncedCustomAlert', () => {
const debouncedAlert = jest.fn();
beforeEach(() => {
const { datasource } = setupMockedDataSource({
variables: [
{ ...namespaceVariable, multi: true },
{ ...metricVariable, multi: true },
],
});
datasource.debouncedCustomAlert = debouncedAlert;
datasource.performTimeSeriesQuery = jest.fn().mockResolvedValue([]);
datasource.query({
targets: [
{
queryMode: 'Metrics',
id: '',
region: 'us-east-2',
namespace: namespaceVariable.id,
metricName: metricVariable.id,
period: '',
alias: '',
dimensions: {},
matchExact: true,
statistic: '',
refId: '',
expression: 'x * 2',
metricQueryType: MetricQueryType.Search,
metricEditorMode: MetricEditorMode.Code,
},
],
} as any);
});
it('should show debounced alert for namespace and metric name', async () => {
expect(debouncedAlert).toHaveBeenCalledWith(
'CloudWatch templating error',
'Multi template variables are not supported for namespace'
);
expect(debouncedAlert).toHaveBeenCalledWith(
'CloudWatch templating error',
'Multi template variables are not supported for metric name'
);
});
it('should not show debounced alert for region', async () => {
expect(debouncedAlert).not.toHaveBeenCalledWith(
'CloudWatch templating error',
'Multi template variables are not supported for region'
);
});
});
}); });
describe('filterMetricQuery', () => { describe('filterMetricQuery', () => {

@ -1,9 +1,3 @@
import React from 'react';
import { cloneDeep, find, findLast, isEmpty, isString, set } from 'lodash';
import { from, lastValueFrom, merge, Observable, of, throwError, zip } from 'rxjs';
import { catchError, concatMap, finalize, map, mergeMap, repeat, scan, share, takeWhile, tap } from 'rxjs/operators';
import { DataSourceWithBackend, FetchError, getBackendSrv, toDataQueryResponse } from '@grafana/runtime';
import { RowContextOptions } from '@grafana/ui/src/components/Logs/LogRowContextProvider';
import { import {
DataFrame, DataFrame,
DataQueryError, DataQueryError,
@ -22,44 +16,50 @@ import {
TimeRange, TimeRange,
toLegacyResponseData, toLegacyResponseData,
} from '@grafana/data'; } from '@grafana/data';
import { DataSourceWithBackend, FetchError, getBackendSrv, toDataQueryResponse } from '@grafana/runtime';
import { toTestingStatus } from '@grafana/runtime/src/utils/queryResponse';
import { RowContextOptions } from '@grafana/ui/src/components/Logs/LogRowContextProvider';
import { notifyApp } from 'app/core/actions'; import { notifyApp } from 'app/core/actions';
import { createErrorNotification } from 'app/core/copy/appNotification'; import { createErrorNotification } from 'app/core/copy/appNotification';
import { AppNotificationTimeout } from 'app/types';
import { store } from 'app/store/store';
import { getTemplateSrv, TemplateSrv } from 'app/features/templating/template_srv';
import { getTimeSrv, TimeSrv } from 'app/features/dashboard/services/TimeSrv'; import { getTimeSrv, TimeSrv } from 'app/features/dashboard/services/TimeSrv';
import { getTemplateSrv, TemplateSrv } from 'app/features/templating/template_srv';
import { VariableWithMultiSupport } from 'app/features/variables/types';
import { store } from 'app/store/store';
import { AppNotificationTimeout } from 'app/types';
import { cloneDeep, find, findLast, isEmpty, isString, set } from 'lodash';
import React from 'react';
import { from, lastValueFrom, merge, Observable, of, throwError, zip } from 'rxjs';
import { catchError, concatMap, finalize, map, mergeMap, repeat, scan, share, takeWhile, tap } from 'rxjs/operators';
import { SQLCompletionItemProvider } from './cloudwatch-sql/completion/CompletionItemProvider';
import { ThrottlingErrorMessage } from './components/ThrottlingErrorMessage'; import { ThrottlingErrorMessage } from './components/ThrottlingErrorMessage';
import { CloudWatchLanguageProvider } from './language_provider';
import memoizedDebounce from './memoizedDebounce'; import memoizedDebounce from './memoizedDebounce';
import { MetricMathCompletionItemProvider } from './metric-math/completion/CompletionItemProvider';
import { import {
MetricEditorMode,
CloudWatchJsonData, CloudWatchJsonData,
CloudWatchLogsQuery, CloudWatchLogsQuery,
CloudWatchLogsQueryStatus, CloudWatchLogsQueryStatus,
CloudWatchLogsRequest,
CloudWatchMetricsQuery, CloudWatchMetricsQuery,
CloudWatchQuery, CloudWatchQuery,
DescribeLogGroupsRequest, DescribeLogGroupsRequest,
Dimensions,
GetLogEventsRequest, GetLogEventsRequest,
GetLogGroupFieldsRequest, GetLogGroupFieldsRequest,
GetLogGroupFieldsResponse, GetLogGroupFieldsResponse,
isCloudWatchLogsQuery, isCloudWatchLogsQuery,
LogAction, LogAction,
MetricQueryType, MetricEditorMode,
MetricQuery, MetricQuery,
MetricQueryType,
MetricRequest, MetricRequest,
StartQueryRequest, StartQueryRequest,
TSDBResponse, TSDBResponse,
Dimensions,
CloudWatchLogsRequest,
} from './types'; } from './types';
import { CloudWatchLanguageProvider } from './language_provider';
import { VariableWithMultiSupport } from 'app/features/variables/types';
import { increasingInterval } from './utils/rxjs/increasingInterval';
import { toTestingStatus } from '@grafana/runtime/src/utils/queryResponse';
import { addDataLinksToLogsResponse } from './utils/datalinks'; import { addDataLinksToLogsResponse } from './utils/datalinks';
import { runWithRetry } from './utils/logsRetry'; import { runWithRetry } from './utils/logsRetry';
import { SQLCompletionItemProvider } from './cloudwatch-sql/completion/CompletionItemProvider'; import { increasingInterval } from './utils/rxjs/increasingInterval';
import { MetricMathCompletionItemProvider } from './metric-math/completion/CompletionItemProvider';
const DS_QUERY_ENDPOINT = '/api/ds/query'; const DS_QUERY_ENDPOINT = '/api/ds/query';
@ -268,7 +268,7 @@ export class CloudWatchDatasource
const validMetricsQueries = metricQueries const validMetricsQueries = metricQueries
.filter(this.filterMetricQuery) .filter(this.filterMetricQuery)
.map((item: CloudWatchMetricsQuery): MetricQuery => { .map((item: CloudWatchMetricsQuery): MetricQuery => {
item.region = this.replace(this.getActualRegion(item.region), options.scopedVars, true, 'region'); item.region = this.templateSrv.replace(this.getActualRegion(item.region), options.scopedVars);
item.namespace = this.replace(item.namespace, options.scopedVars, true, 'namespace'); item.namespace = this.replace(item.namespace, options.scopedVars, true, 'namespace');
item.metricName = this.replace(item.metricName, options.scopedVars, true, 'metric name'); item.metricName = this.replace(item.metricName, options.scopedVars, true, 'metric name');
item.dimensions = this.convertDimensionFormat(item.dimensions ?? {}, options.scopedVars); item.dimensions = this.convertDimensionFormat(item.dimensions ?? {}, options.scopedVars);

Loading…
Cancel
Save