diff --git a/public/app/plugins/datasource/cloudwatch/datasource.test.ts b/public/app/plugins/datasource/cloudwatch/datasource.test.ts index 00eb29f9bb7..5a06bce1476 100644 --- a/public/app/plugins/datasource/cloudwatch/datasource.test.ts +++ b/public/app/plugins/datasource/cloudwatch/datasource.test.ts @@ -10,8 +10,13 @@ import { namespaceVariable, setupMockedDataSource, } from './__mocks__/CloudWatchDataSource'; -import { CloudWatchDatasource } from './datasource'; -import { CloudWatchLogsQueryStatus, CloudWatchMetricsQuery, MetricEditorMode, MetricQueryType } from './types'; +import { + CloudWatchLogsQuery, + CloudWatchLogsQueryStatus, + CloudWatchMetricsQuery, + MetricEditorMode, + MetricQueryType, +} from './types'; describe('datasource', () => { describe('query', () => { @@ -144,111 +149,124 @@ describe('datasource', () => { }); }); - describe('filterMetricQuery', () => { - let baseQuery: CloudWatchMetricsQuery; - let datasource: CloudWatchDatasource; - - beforeEach(() => { - datasource = setupMockedDataSource().datasource; - baseQuery = { + describe('filterQuery', () => { + const datasource = setupMockedDataSource().datasource; + describe('CloudWatchLogsQuery', () => { + const baseQuery: CloudWatchLogsQuery = { + queryMode: 'Logs', id: '', - region: 'us-east-2', - namespace: '', - period: '', - alias: '', - metricName: '', - dimensions: {}, - matchExact: true, - statistic: '', - expression: '', + region: '', refId: '', + logGroupNames: ['foo', 'bar'], }; + it('should return false if empty logGroupNames', () => { + expect(datasource.filterQuery({ ...baseQuery, logGroupNames: undefined })).toBeFalsy(); + }); + it('should return true if has logGroupNames', () => { + expect(datasource.filterQuery(baseQuery)).toBeTruthy(); + }); }); - - it('should error if invalid mode', async () => { - expect(() => datasource.filterMetricQuery(baseQuery)).toThrowError('invalid metric editor mode'); - }); - - describe('metric search queries', () => { + describe('CloudWatchMetricsQuery', () => { + let baseQuery: CloudWatchMetricsQuery; beforeEach(() => { - datasource = setupMockedDataSource().datasource; baseQuery = { - ...baseQuery, - namespace: 'AWS/EC2', - metricName: 'CPUUtilization', - statistic: 'Average', - metricQueryType: MetricQueryType.Search, - metricEditorMode: MetricEditorMode.Builder, + id: '', + region: 'us-east-2', + namespace: '', + period: '', + alias: '', + metricName: '', + dimensions: {}, + matchExact: true, + statistic: '', + expression: '', + refId: '', }; }); - it('should not allow builder queries that dont have namespace, metric or statistic', async () => { - expect(datasource.filterMetricQuery({ ...baseQuery, statistic: undefined })).toBeFalsy(); - expect(datasource.filterMetricQuery({ ...baseQuery, metricName: undefined })).toBeFalsy(); - expect(datasource.filterMetricQuery({ ...baseQuery, namespace: '' })).toBeFalsy(); + it('should error if invalid mode', async () => { + expect(() => datasource.filterQuery(baseQuery)).toThrowError('invalid metric editor mode'); }); - it('should allow builder queries that have namespace, metric or statistic', async () => { - expect(datasource.filterMetricQuery(baseQuery)).toBeTruthy(); + describe('metric search queries', () => { + beforeEach(() => { + baseQuery = { + ...baseQuery, + namespace: 'AWS/EC2', + metricName: 'CPUUtilization', + statistic: 'Average', + metricQueryType: MetricQueryType.Search, + metricEditorMode: MetricEditorMode.Builder, + }; + }); + + it('should not allow builder queries that dont have namespace, metric or statistic', async () => { + expect(datasource.filterQuery({ ...baseQuery, statistic: undefined })).toBeFalsy(); + expect(datasource.filterQuery({ ...baseQuery, metricName: undefined })).toBeFalsy(); + expect(datasource.filterQuery({ ...baseQuery, namespace: '' })).toBeFalsy(); + }); + + it('should allow builder queries that have namespace, metric or statistic', async () => { + expect(datasource.filterQuery(baseQuery)).toBeTruthy(); + }); + + it('should not allow code queries that dont have an expression', async () => { + expect( + datasource.filterQuery({ ...baseQuery, expression: undefined, metricEditorMode: MetricEditorMode.Code }) + ).toBeFalsy(); + }); + + it('should allow code queries that have an expression', async () => { + expect( + datasource.filterQuery({ ...baseQuery, expression: 'x * 2', metricEditorMode: MetricEditorMode.Code }) + ).toBeTruthy(); + }); }); - it('should not allow code queries that dont have an expression', async () => { - expect( - datasource.filterMetricQuery({ ...baseQuery, expression: undefined, metricEditorMode: MetricEditorMode.Code }) - ).toBeFalsy(); + describe('metric search expression queries', () => { + beforeEach(() => { + baseQuery = { + ...baseQuery, + metricQueryType: MetricQueryType.Search, + metricEditorMode: MetricEditorMode.Code, + }; + }); + + it('should not allow queries that dont have an expression', async () => { + const valid = datasource.filterQuery(baseQuery); + expect(valid).toBeFalsy(); + }); + + it('should allow queries that have an expression', async () => { + baseQuery.expression = 'SUM([a,x])'; + const valid = datasource.filterQuery(baseQuery); + expect(valid).toBeTruthy(); + }); }); - it('should allow code queries that have an expression', async () => { - expect( - datasource.filterMetricQuery({ ...baseQuery, expression: 'x * 2', metricEditorMode: MetricEditorMode.Code }) - ).toBeTruthy(); - }); - }); + describe('metric query queries', () => { + beforeEach(() => { + baseQuery = { + ...baseQuery, + metricQueryType: MetricQueryType.Query, + metricEditorMode: MetricEditorMode.Code, + }; + }); - describe('metric search expression queries', () => { - beforeEach(() => { - datasource = setupMockedDataSource().datasource; - baseQuery = { - ...baseQuery, - metricQueryType: MetricQueryType.Search, - metricEditorMode: MetricEditorMode.Code, - }; - }); + it('should not allow queries that dont have a sql expresssion', async () => { + const valid = datasource.filterQuery(baseQuery); + expect(valid).toBeFalsy(); + }); - it('should not allow queries that dont have an expresssion', async () => { - const valid = datasource.filterMetricQuery(baseQuery); - expect(valid).toBeFalsy(); - }); - - it('should allow queries that have an expresssion', async () => { - baseQuery.expression = 'SUM([a,x])'; - const valid = datasource.filterMetricQuery(baseQuery); - expect(valid).toBeTruthy(); - }); - }); - - describe('metric query queries', () => { - beforeEach(() => { - datasource = setupMockedDataSource().datasource; - baseQuery = { - ...baseQuery, - metricQueryType: MetricQueryType.Query, - metricEditorMode: MetricEditorMode.Code, - }; - }); - - it('should not allow queries that dont have a sql expresssion', async () => { - const valid = datasource.filterMetricQuery(baseQuery); - expect(valid).toBeFalsy(); - }); - - it('should allow queries that have a sql expresssion', async () => { - baseQuery.sqlExpression = 'select SUM(CPUUtilization) from "AWS/EC2"'; - const valid = datasource.filterMetricQuery(baseQuery); - expect(valid).toBeTruthy(); + it('should allow queries that have a sql expresssion', async () => { + baseQuery.sqlExpression = 'select SUM(CPUUtilization) from "AWS/EC2"'; + const valid = datasource.filterQuery(baseQuery); + expect(valid).toBeTruthy(); + }); }); }); }); + describe('resource requests', () => { it('should map resource response to metric response', async () => { const datasource = setupMockedDataSource().datasource; diff --git a/public/app/plugins/datasource/cloudwatch/datasource.ts b/public/app/plugins/datasource/cloudwatch/datasource.ts index 7a98c88710d..97f59886a0f 100644 --- a/public/app/plugins/datasource/cloudwatch/datasource.ts +++ b/public/app/plugins/datasource/cloudwatch/datasource.ts @@ -234,22 +234,15 @@ export class CloudWatchDatasource ); }; - filterMetricQuery({ - region, - metricQueryType, - metricEditorMode, - expression, - metricName, - namespace, - sqlExpression, - statistic, - dimensions, - ...rest - }: CloudWatchMetricsQuery): boolean { + filterQuery(query: CloudWatchQuery): boolean { + if (query.queryMode === 'Logs') { + return !!query.logGroupNames?.length; + } + const { region, metricQueryType, metricEditorMode, expression, metricName, namespace, sqlExpression, statistic } = + query; if (!region) { return false; } - if (metricQueryType === MetricQueryType.Search && metricEditorMode === MetricEditorMode.Builder) { return !!namespace && !!metricName && !!statistic; } else if (metricQueryType === MetricQueryType.Search && metricEditorMode === MetricEditorMode.Code) { @@ -266,27 +259,25 @@ export class CloudWatchDatasource metricQueries: CloudWatchMetricsQuery[], options: DataQueryRequest ): Observable => { - const validMetricsQueries = metricQueries - .filter(this.filterMetricQuery) - .map((item: CloudWatchMetricsQuery): MetricQuery => { - item.region = this.templateSrv.replace(this.getActualRegion(item.region), options.scopedVars); - item.namespace = this.replace(item.namespace, options.scopedVars, true, 'namespace'); - item.metricName = this.replace(item.metricName, options.scopedVars, true, 'metric name'); - item.dimensions = this.convertDimensionFormat(item.dimensions ?? {}, options.scopedVars); - item.statistic = this.templateSrv.replace(item.statistic, options.scopedVars); - item.period = String(this.getPeriod(item, options)); // use string format for period in graph query, and alerting - item.id = this.templateSrv.replace(item.id, options.scopedVars); - item.expression = this.templateSrv.replace(item.expression, options.scopedVars); - item.sqlExpression = this.templateSrv.replace(item.sqlExpression, options.scopedVars, 'raw'); + const validMetricsQueries = metricQueries.map((item: CloudWatchMetricsQuery): MetricQuery => { + item.region = this.templateSrv.replace(this.getActualRegion(item.region), options.scopedVars); + item.namespace = this.replace(item.namespace, options.scopedVars, true, 'namespace'); + item.metricName = this.replace(item.metricName, options.scopedVars, true, 'metric name'); + item.dimensions = this.convertDimensionFormat(item.dimensions ?? {}, options.scopedVars); + item.statistic = this.templateSrv.replace(item.statistic, options.scopedVars); + item.period = String(this.getPeriod(item, options)); // use string format for period in graph query, and alerting + item.id = this.templateSrv.replace(item.id, options.scopedVars); + item.expression = this.templateSrv.replace(item.expression, options.scopedVars); + item.sqlExpression = this.templateSrv.replace(item.sqlExpression, options.scopedVars, 'raw'); - return { - intervalMs: options.intervalMs, - maxDataPoints: options.maxDataPoints, - ...item, - type: 'timeSeriesQuery', - datasource: this.getRef(), - }; - }); + return { + intervalMs: options.intervalMs, + maxDataPoints: options.maxDataPoints, + ...item, + type: 'timeSeriesQuery', + datasource: this.getRef(), + }; + }); // No valid targets, return the empty result to save a round trip. if (isEmpty(validMetricsQueries)) {