Prometheus: Create Prometheus library (#81641)
* Move to the library
* copy from library
* move them in src
* have additional files
* add unmigrated/dulicated code and files
* migrate from brendan's pr
module.ts, query_hints.ts, tracking.ts, and remove plugin.json
* migrate from brendan's pr
metric_find_query.test.ts
* migrate from brendan's pr
language_utils.test.ts
* migrate from brendan's pr
index.ts in root and in configuration
* migrate from brendan's pr
datasource.test.ts
* migrate from brendan's pr
typings folder
* migrate from brendan's pr
querycache folder
* migrate from brendan's pr
monaco-query-field folder
* migrate from brendan's pr
components folder without monaco-query-field folder
* migrate from brendan's pr
configuration/overhaul folder
* migrate from brendan's pr
AlertingSettingsOverhaul.tsx
* Remove azure related code
* migrate from brendan's pr
ConfigEditor.tsx, DataSourceHttpSettingsOverhaul.tsx, ExemplarSetting.tsx, configuration/mocks.ts, PromSettings.test.tsx, PromSettings.tsx
* migrate from brendan's pr
useFlag.ts
* migrate from brendan's pr
metrics-modal folder
* migrate from brendan's pr
files inside components folder
* migrate from brendan's pr
LabelFilters* files because they are now under components folder
* migrate from brendan's pr
files under querybuilder/shared folder
* migrate from brendan's pr
aggregations.ts, QueryPattern.tsx, QueryPatternsModal.tsx, state.ts, testUtils.ts under querybuilder folder
* Apply Ivana's PR https://github.com/grafana/grafana/pull/81656
* Apply jack's suggestions in this PR https://github.com/grafana/grafana/pull/77762
* Apply Ivana's PR https://github.com/grafana/grafana/pull/81656
* Fix type import
* add monaco-promql to transformIgnorePatterns to run prometheus frontend library tests
* remove Loki specific tests because we removed Loki code to decouple Loki
* add prometheus specific references
* We are moving these betterer issues from core Prometheus to the Library and we promise to remove all issues in the future, thank you
* include prometheus library in package.json
* add yarn lock with prometheus frontend library
* decouple final core import from metric_find_query.test.ts
* run prettier
* fix core imports in promqail
* fix lint errors
* run prettier
* add grafana-ui to devdeps to fix lint errors
* update yarn.lock
* grafana-ui fix
* trying to fix grafana-ui type errors with lerna drone check
* trying to fix grafana-ui type errors with lerna drone check
* trying to fix grafana-ui type errors with lerna drone check
* trying to fix grafana-ui type errors with lerna drone check
* try to pass typecheck
---------
Co-authored-by: Brendan O'Handley <brendan.ohandley@grafana.com>
2024-02-02 22:30:14 +08:00
|
|
|
import { render, screen, waitFor } from '@testing-library/react';
|
|
|
|
import userEvent from '@testing-library/user-event';
|
|
|
|
import React from 'react';
|
|
|
|
|
|
|
|
import { DataSourceInstanceSettings, MetricFindValue } from '@grafana/data';
|
|
|
|
|
|
|
|
import { PrometheusDatasource } from '../../datasource';
|
|
|
|
import { PromOptions } from '../../types';
|
|
|
|
|
|
|
|
import {
|
|
|
|
formatPrometheusLabelFilters,
|
|
|
|
formatPrometheusLabelFiltersToString,
|
|
|
|
MetricSelect,
|
2024-02-06 22:27:09 +08:00
|
|
|
MetricSelectProps,
|
Prometheus: Create Prometheus library (#81641)
* Move to the library
* copy from library
* move them in src
* have additional files
* add unmigrated/dulicated code and files
* migrate from brendan's pr
module.ts, query_hints.ts, tracking.ts, and remove plugin.json
* migrate from brendan's pr
metric_find_query.test.ts
* migrate from brendan's pr
language_utils.test.ts
* migrate from brendan's pr
index.ts in root and in configuration
* migrate from brendan's pr
datasource.test.ts
* migrate from brendan's pr
typings folder
* migrate from brendan's pr
querycache folder
* migrate from brendan's pr
monaco-query-field folder
* migrate from brendan's pr
components folder without monaco-query-field folder
* migrate from brendan's pr
configuration/overhaul folder
* migrate from brendan's pr
AlertingSettingsOverhaul.tsx
* Remove azure related code
* migrate from brendan's pr
ConfigEditor.tsx, DataSourceHttpSettingsOverhaul.tsx, ExemplarSetting.tsx, configuration/mocks.ts, PromSettings.test.tsx, PromSettings.tsx
* migrate from brendan's pr
useFlag.ts
* migrate from brendan's pr
metrics-modal folder
* migrate from brendan's pr
files inside components folder
* migrate from brendan's pr
LabelFilters* files because they are now under components folder
* migrate from brendan's pr
files under querybuilder/shared folder
* migrate from brendan's pr
aggregations.ts, QueryPattern.tsx, QueryPatternsModal.tsx, state.ts, testUtils.ts under querybuilder folder
* Apply Ivana's PR https://github.com/grafana/grafana/pull/81656
* Apply jack's suggestions in this PR https://github.com/grafana/grafana/pull/77762
* Apply Ivana's PR https://github.com/grafana/grafana/pull/81656
* Fix type import
* add monaco-promql to transformIgnorePatterns to run prometheus frontend library tests
* remove Loki specific tests because we removed Loki code to decouple Loki
* add prometheus specific references
* We are moving these betterer issues from core Prometheus to the Library and we promise to remove all issues in the future, thank you
* include prometheus library in package.json
* add yarn lock with prometheus frontend library
* decouple final core import from metric_find_query.test.ts
* run prettier
* fix core imports in promqail
* fix lint errors
* run prettier
* add grafana-ui to devdeps to fix lint errors
* update yarn.lock
* grafana-ui fix
* trying to fix grafana-ui type errors with lerna drone check
* trying to fix grafana-ui type errors with lerna drone check
* trying to fix grafana-ui type errors with lerna drone check
* trying to fix grafana-ui type errors with lerna drone check
* try to pass typecheck
---------
Co-authored-by: Brendan O'Handley <brendan.ohandley@grafana.com>
2024-02-02 22:30:14 +08:00
|
|
|
} from './MetricSelect';
|
|
|
|
|
|
|
|
const instanceSettings = {
|
|
|
|
url: 'proxied',
|
|
|
|
id: 1,
|
|
|
|
user: 'test',
|
|
|
|
password: 'mupp',
|
|
|
|
jsonData: { httpMethod: 'GET' },
|
|
|
|
} as unknown as DataSourceInstanceSettings<PromOptions>;
|
|
|
|
|
|
|
|
const dataSourceMock = new PrometheusDatasource(instanceSettings);
|
|
|
|
const mockValues = [{ label: 'random_metric' }, { label: 'unique_metric' }, { label: 'more_unique_metric' }];
|
|
|
|
|
|
|
|
// Mock metricFindQuery which will call backend API
|
|
|
|
//@ts-ignore
|
|
|
|
dataSourceMock.metricFindQuery = jest.fn((query: string) => {
|
|
|
|
// Use the label values regex to get the values inside the label_values function call
|
|
|
|
const labelValuesRegex = /^label_values\((?:(.+),\s*)?([a-zA-Z_][a-zA-Z0-9_]*)\)\s*$/;
|
|
|
|
const queryValueArray = query.match(labelValuesRegex) as RegExpMatchArray;
|
|
|
|
const queryValueRaw = queryValueArray[1] as string;
|
|
|
|
|
|
|
|
// Remove the wrapping regex
|
|
|
|
const queryValue = queryValueRaw.substring(queryValueRaw.indexOf('".*') + 3, queryValueRaw.indexOf('.*"'));
|
|
|
|
|
|
|
|
// Run the regex that we'd pass into prometheus API against the strings in the test
|
|
|
|
return Promise.resolve(
|
|
|
|
mockValues
|
|
|
|
.filter((value) => value.label.match(queryValue))
|
|
|
|
.map((result) => {
|
|
|
|
return {
|
|
|
|
text: result.label,
|
|
|
|
};
|
|
|
|
}) as MetricFindValue[]
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
2024-02-06 22:27:09 +08:00
|
|
|
const props: MetricSelectProps = {
|
Prometheus: Create Prometheus library (#81641)
* Move to the library
* copy from library
* move them in src
* have additional files
* add unmigrated/dulicated code and files
* migrate from brendan's pr
module.ts, query_hints.ts, tracking.ts, and remove plugin.json
* migrate from brendan's pr
metric_find_query.test.ts
* migrate from brendan's pr
language_utils.test.ts
* migrate from brendan's pr
index.ts in root and in configuration
* migrate from brendan's pr
datasource.test.ts
* migrate from brendan's pr
typings folder
* migrate from brendan's pr
querycache folder
* migrate from brendan's pr
monaco-query-field folder
* migrate from brendan's pr
components folder without monaco-query-field folder
* migrate from brendan's pr
configuration/overhaul folder
* migrate from brendan's pr
AlertingSettingsOverhaul.tsx
* Remove azure related code
* migrate from brendan's pr
ConfigEditor.tsx, DataSourceHttpSettingsOverhaul.tsx, ExemplarSetting.tsx, configuration/mocks.ts, PromSettings.test.tsx, PromSettings.tsx
* migrate from brendan's pr
useFlag.ts
* migrate from brendan's pr
metrics-modal folder
* migrate from brendan's pr
files inside components folder
* migrate from brendan's pr
LabelFilters* files because they are now under components folder
* migrate from brendan's pr
files under querybuilder/shared folder
* migrate from brendan's pr
aggregations.ts, QueryPattern.tsx, QueryPatternsModal.tsx, state.ts, testUtils.ts under querybuilder folder
* Apply Ivana's PR https://github.com/grafana/grafana/pull/81656
* Apply jack's suggestions in this PR https://github.com/grafana/grafana/pull/77762
* Apply Ivana's PR https://github.com/grafana/grafana/pull/81656
* Fix type import
* add monaco-promql to transformIgnorePatterns to run prometheus frontend library tests
* remove Loki specific tests because we removed Loki code to decouple Loki
* add prometheus specific references
* We are moving these betterer issues from core Prometheus to the Library and we promise to remove all issues in the future, thank you
* include prometheus library in package.json
* add yarn lock with prometheus frontend library
* decouple final core import from metric_find_query.test.ts
* run prettier
* fix core imports in promqail
* fix lint errors
* run prettier
* add grafana-ui to devdeps to fix lint errors
* update yarn.lock
* grafana-ui fix
* trying to fix grafana-ui type errors with lerna drone check
* trying to fix grafana-ui type errors with lerna drone check
* trying to fix grafana-ui type errors with lerna drone check
* trying to fix grafana-ui type errors with lerna drone check
* try to pass typecheck
---------
Co-authored-by: Brendan O'Handley <brendan.ohandley@grafana.com>
2024-02-02 22:30:14 +08:00
|
|
|
labelsFilters: [],
|
|
|
|
datasource: dataSourceMock,
|
|
|
|
query: {
|
|
|
|
metric: '',
|
|
|
|
labels: [],
|
|
|
|
operations: [],
|
|
|
|
},
|
|
|
|
onChange: jest.fn(),
|
|
|
|
onGetMetrics: jest.fn().mockResolvedValue(mockValues),
|
|
|
|
metricLookupDisabled: false,
|
|
|
|
};
|
|
|
|
|
|
|
|
describe('MetricSelect', () => {
|
|
|
|
it('shows all metric options', async () => {
|
|
|
|
render(<MetricSelect {...props} />);
|
|
|
|
await openMetricSelect();
|
|
|
|
await waitFor(() => expect(screen.getByText('random_metric')).toBeInTheDocument());
|
|
|
|
await waitFor(() => expect(screen.getByText('unique_metric')).toBeInTheDocument());
|
|
|
|
await waitFor(() => expect(screen.getByText('more_unique_metric')).toBeInTheDocument());
|
|
|
|
await waitFor(() => expect(screen.getAllByLabelText('Select option')).toHaveLength(3));
|
|
|
|
});
|
|
|
|
|
|
|
|
it('truncates list of metrics to 1000', async () => {
|
|
|
|
const manyMockValues = [...Array(1001).keys()].map((idx: number) => {
|
|
|
|
return { label: 'random_metric' + idx };
|
|
|
|
});
|
|
|
|
|
|
|
|
props.onGetMetrics = jest.fn().mockResolvedValue(manyMockValues);
|
|
|
|
|
|
|
|
render(<MetricSelect {...props} />);
|
|
|
|
await openMetricSelect();
|
|
|
|
await waitFor(() => expect(screen.getAllByLabelText('Select option')).toHaveLength(1000));
|
|
|
|
});
|
|
|
|
|
|
|
|
it('shows option to set custom value when typing', async () => {
|
|
|
|
render(<MetricSelect {...props} />);
|
|
|
|
await openMetricSelect();
|
|
|
|
const input = screen.getByRole('combobox');
|
|
|
|
await userEvent.type(input, 'custom value');
|
|
|
|
await waitFor(() => expect(screen.getByText('custom value')).toBeInTheDocument());
|
|
|
|
});
|
|
|
|
|
|
|
|
it('shows searched options when typing', async () => {
|
|
|
|
render(<MetricSelect {...props} />);
|
|
|
|
await openMetricSelect();
|
|
|
|
const input = screen.getByRole('combobox');
|
|
|
|
await userEvent.type(input, 'unique');
|
|
|
|
await waitFor(() => expect(screen.getAllByLabelText('Select option')).toHaveLength(3));
|
|
|
|
});
|
|
|
|
|
|
|
|
it('searches on split words', async () => {
|
|
|
|
render(<MetricSelect {...props} />);
|
|
|
|
await openMetricSelect();
|
|
|
|
const input = screen.getByRole('combobox');
|
|
|
|
await userEvent.type(input, 'more unique');
|
|
|
|
await waitFor(() => expect(screen.getAllByLabelText('Select option')).toHaveLength(2));
|
|
|
|
});
|
|
|
|
|
|
|
|
it('searches on multiple split words', async () => {
|
|
|
|
render(<MetricSelect {...props} />);
|
|
|
|
await openMetricSelect();
|
|
|
|
const input = screen.getByRole('combobox');
|
|
|
|
await userEvent.type(input, 'more unique metric');
|
|
|
|
await waitFor(() => expect(screen.getAllByLabelText('Select option')).toHaveLength(2));
|
|
|
|
});
|
|
|
|
|
|
|
|
it('highlights matching string', async () => {
|
|
|
|
render(<MetricSelect {...props} />);
|
|
|
|
await openMetricSelect();
|
|
|
|
const input = screen.getByRole('combobox');
|
|
|
|
await userEvent.type(input, 'more');
|
|
|
|
await waitFor(() => expect(document.querySelectorAll('mark')).toHaveLength(1));
|
|
|
|
});
|
|
|
|
|
|
|
|
it('highlights multiple matching strings in 1 input row', async () => {
|
|
|
|
render(<MetricSelect {...props} />);
|
|
|
|
await openMetricSelect();
|
|
|
|
const input = screen.getByRole('combobox');
|
|
|
|
await userEvent.type(input, 'more metric');
|
|
|
|
await waitFor(() => expect(document.querySelectorAll('mark')).toHaveLength(2));
|
|
|
|
});
|
|
|
|
|
|
|
|
it('highlights multiple matching strings in multiple input rows', async () => {
|
|
|
|
render(<MetricSelect {...props} />);
|
|
|
|
await openMetricSelect();
|
|
|
|
const input = screen.getByRole('combobox');
|
|
|
|
await userEvent.type(input, 'unique metric');
|
|
|
|
await waitFor(() => expect(document.querySelectorAll('mark')).toHaveLength(4));
|
|
|
|
});
|
|
|
|
|
|
|
|
it('does not highlight matching string in create option', async () => {
|
|
|
|
render(<MetricSelect {...props} />);
|
|
|
|
await openMetricSelect();
|
|
|
|
const input = screen.getByRole('combobox');
|
|
|
|
await userEvent.type(input, 'new');
|
|
|
|
await waitFor(() => expect(document.querySelector('mark')).not.toBeInTheDocument());
|
|
|
|
});
|
|
|
|
|
|
|
|
it('label filters properly join', () => {
|
|
|
|
const query = formatPrometheusLabelFilters([
|
|
|
|
{
|
|
|
|
value: 'value',
|
|
|
|
label: 'label',
|
|
|
|
op: '=',
|
|
|
|
},
|
|
|
|
{
|
|
|
|
value: 'value2',
|
|
|
|
label: 'label2',
|
|
|
|
op: '=',
|
|
|
|
},
|
|
|
|
]);
|
|
|
|
query.forEach((label) => {
|
|
|
|
expect(label.includes(',', 0));
|
|
|
|
});
|
|
|
|
});
|
|
|
|
it('label filter creation', () => {
|
|
|
|
const labels = [
|
|
|
|
{
|
|
|
|
value: 'value',
|
|
|
|
label: 'label',
|
|
|
|
op: '=',
|
|
|
|
},
|
|
|
|
{
|
|
|
|
value: 'value2',
|
|
|
|
label: 'label2',
|
|
|
|
op: '=',
|
|
|
|
},
|
|
|
|
];
|
|
|
|
|
|
|
|
const queryString = formatPrometheusLabelFiltersToString('query', labels);
|
|
|
|
queryString.split(',').forEach((queryChunk) => {
|
|
|
|
expect(queryChunk.length).toBeGreaterThan(1); // must be longer then ','
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
async function openMetricSelect() {
|
|
|
|
const select = screen.getByText('Select metric').parentElement!;
|
|
|
|
await userEvent.click(select);
|
|
|
|
}
|