Cloudwatch : Fixed reseting metric name when changing namespace in Metric Query (#44612)

* Added logic to reset metric name when changing namespace in Metric Query

* Added tests for reseting or not metricName onChange namespace

* Added tests for reseting or not metricName onChange namespace

* Removed comment

* Cleaned up tests

* Refactored namespace to be updated in utils

* Removed unecessary overrides for query and onQueryChange

* Renamed tests + used some instead of find
This commit is contained in:
Yaelle Chaudy 2022-02-01 09:13:25 +01:00 committed by GitHub
parent fd14112dbd
commit 33a7269b4f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 165 additions and 2 deletions

View File

@ -0,0 +1,137 @@
import React from 'react';
import { selectOptionInTest } from '@grafana/ui';
import { act, render, screen } from '@testing-library/react';
import { CloudWatchMetricsQuery, MetricEditorMode, MetricQueryType, SQLExpression } from '../../types';
import { setupMockedDataSource } from '../../__mocks__/CloudWatchDataSource';
import { QueryEditorExpressionType, QueryEditorPropertyType } from '../../expressions';
import SQLBuilderSelectRow from './SQLBuilderSelectRow';
const { datasource } = setupMockedDataSource();
const makeSQLQuery = (sql?: SQLExpression): CloudWatchMetricsQuery => ({
queryMode: 'Metrics',
refId: '',
id: '',
region: 'us-east-1',
namespace: 'ec2',
dimensions: { somekey: 'somevalue' },
metricQueryType: MetricQueryType.Query,
metricEditorMode: MetricEditorMode.Builder,
sql: sql,
});
const query = makeSQLQuery({
select: {
type: QueryEditorExpressionType.Function,
name: 'AVERAGE',
parameters: [
{
type: QueryEditorExpressionType.FunctionParameter,
name: 'm1',
},
],
},
from: {
type: QueryEditorExpressionType.Property,
property: {
type: QueryEditorPropertyType.String,
name: 'n1',
},
},
});
const onQueryChange = jest.fn();
const baseProps = {
query,
datasource,
onQueryChange,
};
const namespaces = [
{ value: 'n1', label: 'n1', text: 'n1' },
{ value: 'n2', label: 'n2', text: 'n2' },
];
const metrics = [
{ value: 'm1', label: 'm1', text: 'm1' },
{ value: 'm2', label: 'm2', text: 'm2' },
];
describe('Cloudwatch SQLBuilderSelectRow', () => {
beforeEach(() => {
datasource.getNamespaces = jest.fn().mockResolvedValue(namespaces);
datasource.getMetrics = jest.fn().mockResolvedValue([]);
datasource.getDimensionKeys = jest.fn().mockResolvedValue([]);
datasource.getDimensionValues = jest.fn().mockResolvedValue([]);
onQueryChange.mockReset();
});
it('Should not reset metricName when selecting a namespace if metric exist in new namespace', async () => {
datasource.getMetrics = jest.fn().mockResolvedValue(metrics);
await act(async () => {
render(<SQLBuilderSelectRow {...baseProps} />);
});
expect(screen.getByText('n1')).toBeInTheDocument();
expect(screen.getByText('m1')).toBeInTheDocument();
const namespaceSelect = screen.getByLabelText('Namespace');
await selectOptionInTest(namespaceSelect, 'n2');
const expectedQuery = makeSQLQuery({
select: {
type: QueryEditorExpressionType.Function,
name: 'AVERAGE',
parameters: [
{
type: QueryEditorExpressionType.FunctionParameter,
name: 'm1',
},
],
},
from: {
type: QueryEditorExpressionType.Property,
property: {
type: QueryEditorPropertyType.String,
name: 'n2',
},
},
});
expect(onQueryChange).toHaveBeenCalledTimes(1);
expect(onQueryChange.mock.calls).toEqual([[{ ...expectedQuery, namespace: 'n2' }]]);
});
it('Should reset metricName when selecting a namespace if metric does not exist in new namespace', async () => {
datasource.getMetrics = jest.fn().mockImplementation((namespace: string, region: string) => {
let mockMetrics =
namespace === 'n1' && region === baseProps.query.region
? metrics
: [{ value: 'newNamespaceMetric', label: 'newNamespaceMetric', text: 'newNamespaceMetric' }];
return Promise.resolve(mockMetrics);
});
await act(async () => {
render(<SQLBuilderSelectRow {...baseProps} />);
});
expect(screen.getByText('n1')).toBeInTheDocument();
expect(screen.getByText('m1')).toBeInTheDocument();
const namespaceSelect = screen.getByLabelText('Namespace');
await selectOptionInTest(namespaceSelect, 'n2');
const expectedQuery = makeSQLQuery({
select: {
type: QueryEditorExpressionType.Function,
name: 'AVERAGE',
},
from: {
type: QueryEditorExpressionType.Property,
property: {
type: QueryEditorPropertyType.String,
name: 'n2',
},
},
});
expect(onQueryChange).toHaveBeenCalledTimes(1);
expect(onQueryChange.mock.calls).toEqual([[{ ...expectedQuery, namespace: 'n2' }]]);
});
});

View File

@ -1,5 +1,5 @@
import React, { useEffect, useMemo } from 'react';
import { toOption } from '@grafana/data';
import { SelectableValue, toOption } from '@grafana/data';
import { EditorField, EditorFieldGroup } from '@grafana/experimental';
import { Select, Switch } from '@grafana/ui';
import { STATISTICS } from '../../cloudwatch-sql/language';
@ -12,6 +12,7 @@ import {
getNamespaceFromExpression,
getSchemaLabelKeys as getSchemaLabels,
isUsingWithSchema,
removeMetricName,
setAggregation,
setMetricName,
setNamespace,
@ -52,16 +53,32 @@ const SQLBuilderSelectRow: React.FC<SQLBuilderSelectRowProps> = ({ datasource, q
[unusedDimensionKeys, schemaLabels]
);
const onNamespaceChange = async (query: CloudWatchMetricsQuery) => {
const validatedQuery = await validateMetricName(query);
onQueryChange(validatedQuery);
};
const validateMetricName = async (query: CloudWatchMetricsQuery) => {
let { region, sql } = query;
await datasource.getMetrics(query.namespace, region).then((result: Array<SelectableValue<string>>) => {
if (!result.some((metric) => metric.value === metricName)) {
sql = removeMetricName(query).sql;
}
});
return { ...query, sql };
};
return (
<>
<EditorFieldGroup>
<EditorField label="Namespace" width={16}>
<Select
aria-label="Namespace"
value={namespace ? toOption(namespace) : null}
inputId={`${query.refId}-cloudwatch-sql-namespace`}
options={namespaceOptions}
allowCustomValue
onChange={({ value }) => value && onQueryChange(setNamespace(query, value))}
onChange={({ value }) => value && onNamespaceChange(setNamespace(query, value))}
menuShouldPortal
/>
</EditorField>

View File

@ -146,6 +146,8 @@ export function setSql(query: CloudWatchMetricsQuery, sql: SQLExpression): Cloud
export function setNamespace(query: CloudWatchMetricsQuery, namespace: string | undefined): CloudWatchMetricsQuery {
const sql = query.sql ?? {};
//updating `namespace` props for CloudWatchMetricsQuery
query.namespace = namespace ? namespace : '';
if (namespace === undefined) {
return setSql(query, {
@ -230,6 +232,13 @@ export function setMetricName(query: CloudWatchMetricsQuery, metricName: string)
});
}
export function removeMetricName(query: CloudWatchMetricsQuery): CloudWatchMetricsQuery {
const queryWithNoParams = { ...query };
delete queryWithNoParams.sql?.select?.parameters;
return queryWithNoParams;
}
export function setAggregation(query: CloudWatchMetricsQuery, aggregation: string): CloudWatchMetricsQuery {
return setSql(query, {
select: {