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 { getByTestId, render, screen, waitFor } from '@testing-library/react';
|
|
|
|
// @ts-ignore
|
|
|
|
import userEvent from '@testing-library/user-event';
|
|
|
|
import React from 'react';
|
|
|
|
|
|
|
|
import { CoreApp, DataFrame, LoadingState, PanelData } from '@grafana/data';
|
|
|
|
|
|
|
|
import { PrometheusDatasource } from '../datasource';
|
|
|
|
import PromQlLanguageProvider from '../language_provider';
|
|
|
|
|
2024-02-17 02:55:39 +08:00
|
|
|
import { PromQueryField } from './PromQueryField';
|
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 { Props } from './monaco-query-field/MonacoQueryFieldProps';
|
|
|
|
|
|
|
|
// the monaco-based editor uses lazy-loading and that does not work
|
|
|
|
// well with this test, and we do not need the monaco-related
|
|
|
|
// functionality in this test anyway, so we mock it out.
|
|
|
|
jest.mock('./monaco-query-field/MonacoQueryFieldLazy', () => {
|
|
|
|
const fakeQueryField = (props: Props) => {
|
|
|
|
return <input onBlur={(e) => props.onBlur(e.currentTarget.value)} data-testid={'dummy-code-input'} type={'text'} />;
|
|
|
|
};
|
|
|
|
return {
|
|
|
|
MonacoQueryFieldLazy: fakeQueryField,
|
|
|
|
};
|
|
|
|
});
|
|
|
|
|
|
|
|
const defaultProps = {
|
|
|
|
datasource: {
|
|
|
|
languageProvider: {
|
|
|
|
start: () => Promise.resolve([]),
|
|
|
|
syntax: () => {},
|
|
|
|
getLabelKeys: () => [],
|
|
|
|
metrics: [],
|
|
|
|
},
|
|
|
|
getInitHints: () => [],
|
|
|
|
} as unknown as PrometheusDatasource,
|
|
|
|
query: {
|
|
|
|
expr: '',
|
|
|
|
refId: '',
|
|
|
|
},
|
|
|
|
onRunQuery: () => {},
|
|
|
|
onChange: () => {},
|
|
|
|
history: [],
|
|
|
|
};
|
|
|
|
|
|
|
|
describe('PromQueryField', () => {
|
|
|
|
beforeAll(() => {
|
|
|
|
// @ts-ignore
|
|
|
|
window.getSelection = () => {};
|
|
|
|
});
|
|
|
|
|
|
|
|
it('renders metrics chooser regularly if lookups are not disabled in the datasource settings', async () => {
|
|
|
|
const queryField = render(<PromQueryField {...defaultProps} />);
|
|
|
|
|
|
|
|
// wait for component to render
|
|
|
|
await screen.findByRole('button');
|
|
|
|
|
|
|
|
expect(queryField.getAllByRole('button')).toHaveLength(1);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('renders a disabled metrics chooser if lookups are disabled in datasource settings', async () => {
|
|
|
|
const props = defaultProps;
|
|
|
|
props.datasource.lookupsDisabled = true;
|
|
|
|
const queryField = render(<PromQueryField {...props} />);
|
|
|
|
|
|
|
|
// wait for component to render
|
|
|
|
await screen.findByRole('button');
|
|
|
|
|
|
|
|
const bcButton = queryField.getByRole('button');
|
|
|
|
expect(bcButton).toBeDisabled();
|
|
|
|
});
|
|
|
|
|
|
|
|
it('renders an initial hint if no data and initial hint provided', async () => {
|
|
|
|
const props = defaultProps;
|
|
|
|
props.datasource.lookupsDisabled = true;
|
|
|
|
props.datasource.getInitHints = () => [{ label: 'Initial hint', type: 'INFO' }];
|
|
|
|
render(<PromQueryField {...props} />);
|
|
|
|
|
|
|
|
// wait for component to render
|
|
|
|
await screen.findByRole('button');
|
|
|
|
|
|
|
|
expect(screen.getByText('Initial hint')).toBeInTheDocument();
|
|
|
|
});
|
|
|
|
|
|
|
|
it('renders query hint if data, query hint and initial hint provided', async () => {
|
|
|
|
const props = defaultProps;
|
|
|
|
props.datasource.lookupsDisabled = true;
|
|
|
|
props.datasource.getInitHints = () => [{ label: 'Initial hint', type: 'INFO' }];
|
|
|
|
props.datasource.getQueryHints = () => [{ label: 'Query hint', type: 'INFO' }];
|
|
|
|
render(
|
|
|
|
<PromQueryField
|
|
|
|
{...props}
|
|
|
|
data={
|
|
|
|
{
|
|
|
|
series: [{ name: 'test name' }] as DataFrame[],
|
|
|
|
state: LoadingState.Done,
|
|
|
|
} as PanelData
|
|
|
|
}
|
|
|
|
/>
|
|
|
|
);
|
|
|
|
|
|
|
|
// wait for component to render
|
|
|
|
await screen.findByRole('button');
|
|
|
|
|
|
|
|
expect(screen.getByText('Query hint')).toBeInTheDocument();
|
|
|
|
expect(screen.queryByText('Initial hint')).not.toBeInTheDocument();
|
|
|
|
});
|
|
|
|
|
|
|
|
it('refreshes metrics when the data source changes', async () => {
|
|
|
|
const defaultProps = {
|
|
|
|
query: { expr: '', refId: '' },
|
|
|
|
onRunQuery: () => {},
|
|
|
|
onChange: () => {},
|
|
|
|
history: [],
|
|
|
|
};
|
|
|
|
const metrics = ['foo', 'bar'];
|
|
|
|
const queryField = render(
|
|
|
|
<PromQueryField
|
|
|
|
datasource={
|
|
|
|
{
|
|
|
|
languageProvider: makeLanguageProvider({ metrics: [metrics] }),
|
|
|
|
getInitHints: () => [],
|
|
|
|
} as unknown as PrometheusDatasource
|
|
|
|
}
|
|
|
|
{...defaultProps}
|
|
|
|
/>
|
|
|
|
);
|
|
|
|
|
|
|
|
// wait for component to render
|
|
|
|
await screen.findByRole('button');
|
|
|
|
|
|
|
|
const changedMetrics = ['baz', 'moo'];
|
|
|
|
queryField.rerender(
|
|
|
|
<PromQueryField
|
|
|
|
// @ts-ignore
|
|
|
|
datasource={{
|
|
|
|
languageProvider: makeLanguageProvider({ metrics: [changedMetrics] }),
|
|
|
|
}}
|
|
|
|
{...defaultProps}
|
|
|
|
/>
|
|
|
|
);
|
|
|
|
|
|
|
|
// If we check the label browser right away it should be in loading state
|
|
|
|
let labelBrowser = screen.getByRole('button');
|
|
|
|
expect(labelBrowser).toHaveTextContent('Loading');
|
|
|
|
|
|
|
|
// wait for component to rerender
|
|
|
|
labelBrowser = await screen.findByRole('button');
|
|
|
|
await waitFor(() => {
|
|
|
|
expect(labelBrowser).toHaveTextContent('Metrics browser');
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should not run query onBlur', async () => {
|
|
|
|
const onRunQuery = jest.fn();
|
|
|
|
const { container } = render(<PromQueryField {...defaultProps} app={CoreApp.Explore} onRunQuery={onRunQuery} />);
|
|
|
|
|
|
|
|
// wait for component to rerender
|
|
|
|
await screen.findByRole('button');
|
|
|
|
|
|
|
|
const input = getByTestId(container, 'dummy-code-input');
|
|
|
|
expect(input).toBeInTheDocument();
|
|
|
|
await userEvent.type(input, 'metric');
|
|
|
|
|
|
|
|
// blur element
|
|
|
|
await userEvent.click(document.body);
|
|
|
|
expect(onRunQuery).not.toHaveBeenCalled();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
function makeLanguageProvider(options: { metrics: string[][] }) {
|
|
|
|
const metricsStack = [...options.metrics];
|
|
|
|
return {
|
|
|
|
histogramMetrics: [],
|
|
|
|
metrics: [],
|
|
|
|
metricsMetadata: {},
|
|
|
|
lookupsDisabled: false,
|
|
|
|
getLabelKeys: () => [],
|
|
|
|
start() {
|
|
|
|
this.metrics = metricsStack.shift();
|
|
|
|
return Promise.resolve([]);
|
|
|
|
},
|
|
|
|
} as any as PromQlLanguageProvider;
|
|
|
|
}
|