Loki: Fix tests for test decoupling (#108678)
* Loki: Fix tests for test decoupling * Update * Add test and fix implementarion * Remove empty line * prettier
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { AbstractLabelOperator, DataFrame, TimeRange, dateTime, getDefaultTimeRange, ScopedVars } from '@grafana/data';
|
||||
import { AbstractLabelOperator, DataFrame, TimeRange, dateTime, ScopedVars } from '@grafana/data';
|
||||
import { config } from '@grafana/runtime';
|
||||
|
||||
import LanguageProvider from './LanguageProvider';
|
||||
@@ -25,18 +25,6 @@ const mockTimeRange = {
|
||||
},
|
||||
};
|
||||
|
||||
jest.mock('@grafana/data', () => ({
|
||||
...jest.requireActual('@grafana/data'),
|
||||
getDefaultTimeRange: jest.fn().mockImplementation(() => ({
|
||||
from: dateTime(0),
|
||||
to: dateTime(1),
|
||||
raw: {
|
||||
from: dateTime(0),
|
||||
to: dateTime(1),
|
||||
},
|
||||
})),
|
||||
}));
|
||||
|
||||
describe('Language completion provider', () => {
|
||||
describe('start', () => {
|
||||
const datasource = setup({ testkey: ['label1_val1', 'label1_val2'], label2: [] });
|
||||
@@ -208,8 +196,16 @@ describe('Language completion provider', () => {
|
||||
.mockImplementation((range: TimeRange) => ({ start: range.from.valueOf(), end: range.to.valueOf() }));
|
||||
const languageProvider = new LanguageProvider(datasource);
|
||||
languageProvider.request = jest.fn().mockResolvedValue([]);
|
||||
jest.spyOn(languageProvider, 'getDefaultTimeRange').mockImplementation(() => ({
|
||||
from: dateTime(0),
|
||||
to: dateTime(1),
|
||||
raw: {
|
||||
from: dateTime(0),
|
||||
to: dateTime(1),
|
||||
},
|
||||
}));
|
||||
languageProvider.fetchLabelValues('testKey');
|
||||
expect(getDefaultTimeRange).toHaveBeenCalled();
|
||||
expect(languageProvider.getDefaultTimeRange).toHaveBeenCalled();
|
||||
expect(languageProvider.request).toHaveBeenCalled();
|
||||
expect(languageProvider.request).toHaveBeenCalledWith('label/testKey/values', {
|
||||
end: 1,
|
||||
@@ -765,7 +761,7 @@ describe('Query imports', () => {
|
||||
maxLines: DEFAULT_MAX_LINES_SAMPLE,
|
||||
refId: 'data-samples',
|
||||
},
|
||||
getDefaultTimeRange()
|
||||
languageProvider.getDefaultTimeRange()
|
||||
);
|
||||
});
|
||||
|
||||
@@ -786,7 +782,7 @@ describe('Query imports', () => {
|
||||
maxLines: 5,
|
||||
refId: 'data-samples',
|
||||
},
|
||||
getDefaultTimeRange()
|
||||
languageProvider.getDefaultTimeRange()
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -511,7 +511,7 @@ export default class LokiLanguageProvider extends LanguageProvider {
|
||||
*
|
||||
* @returns {TimeRange} The default time range
|
||||
*/
|
||||
private getDefaultTimeRange(): TimeRange {
|
||||
getDefaultTimeRange(): TimeRange {
|
||||
return getDefaultTimeRange();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { of } from 'rxjs';
|
||||
import { initTemplateSrv } from 'test/helpers/initTemplateSrv';
|
||||
|
||||
import {
|
||||
DataQueryResponse,
|
||||
@@ -9,7 +8,7 @@ import {
|
||||
createDataFrame,
|
||||
dateTime,
|
||||
} from '@grafana/data';
|
||||
import { setTemplateSrv } from '@grafana/runtime';
|
||||
import { setTemplateSrv, TemplateSrv } from '@grafana/runtime';
|
||||
|
||||
import LokiLanguageProvider from './LanguageProvider';
|
||||
import {
|
||||
@@ -66,8 +65,10 @@ const frameWithoutTypes = {
|
||||
describe('LogContextProvider', () => {
|
||||
let logContextProvider: LogContextProvider;
|
||||
beforeEach(() => {
|
||||
const templateSrv = initTemplateSrv('key', [{ type: 'query', name: 'foo', current: { value: 'baz' } }]);
|
||||
setTemplateSrv(templateSrv);
|
||||
const templateSrv = {
|
||||
replace: jest.fn((str: string) => str?.replace('$test', 'baz')),
|
||||
};
|
||||
setTemplateSrv(templateSrv as unknown as TemplateSrv);
|
||||
const defaultDatasourceMock = createLokiDatasource(templateSrv);
|
||||
defaultDatasourceMock.query = jest.fn(() => of({ data: [] } as DataQueryResponse));
|
||||
defaultDatasourceMock.languageProvider = defaultLanguageProviderMock;
|
||||
|
||||
@@ -1772,6 +1772,20 @@ describe('LokiDatasource', () => {
|
||||
})
|
||||
);
|
||||
});
|
||||
it('calls query if convertMetricQueryToLogQuery is true for a metric query', async () => {
|
||||
const spy = jest.spyOn(ds, 'query').mockImplementation(() => of({} as DataQueryResponse));
|
||||
await ds.getDataSamples({ expr: 'rate({a="b"}[1m])', refId: 'A' }, mockTimeRange, {
|
||||
convertMetricQueryToLogQuery: true,
|
||||
});
|
||||
expect(spy).toHaveBeenCalled();
|
||||
});
|
||||
it('does not call query if convertMetricQueryToLogQuery is false for a metric query', async () => {
|
||||
const spy = jest.spyOn(ds, 'query');
|
||||
await ds.getDataSamples({ expr: 'rate({a="b"}[1m])', refId: 'A' }, mockTimeRange, {
|
||||
convertMetricQueryToLogQuery: false,
|
||||
});
|
||||
expect(spy).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Query splitting', () => {
|
||||
|
||||
@@ -739,14 +739,28 @@ export class LokiDatasource
|
||||
* Currently, it works for logs data only.
|
||||
* @returns A Promise that resolves to an array of DataFrames containing data samples.
|
||||
*/
|
||||
async getDataSamples(query: LokiQuery, timeRange: TimeRange): Promise<DataFrame[]> {
|
||||
// Currently works only for logs sample
|
||||
if (!isLogsQuery(query.expr) || isQueryWithError(this.interpolateString(query.expr, placeHolderScopedVars))) {
|
||||
async getDataSamples(
|
||||
query: LokiQuery,
|
||||
timeRange: TimeRange,
|
||||
options?: { convertMetricQueryToLogQuery?: boolean }
|
||||
): Promise<DataFrame[]> {
|
||||
let queryExpr = query.expr;
|
||||
if (isQueryWithError(this.interpolateString(queryExpr, placeHolderScopedVars))) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (!isLogsQuery(queryExpr)) {
|
||||
// If it is not a logs query, we need to check if we need to convert it to a logs query
|
||||
if (options?.convertMetricQueryToLogQuery) {
|
||||
queryExpr = getLogQueryFromMetricsQuery(queryExpr);
|
||||
} else {
|
||||
// Otherwise, we return an empty array, as data samples are only supported for logs queries
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
const lokiLogsQuery: LokiQuery = {
|
||||
expr: query.expr,
|
||||
expr: queryExpr,
|
||||
queryType: LokiQueryType.Range,
|
||||
refId: REF_ID_DATA_SAMPLES,
|
||||
maxLines: query.maxLines || DEFAULT_MAX_LINES_SAMPLE,
|
||||
|
||||
@@ -4,8 +4,6 @@ import { DataQueryRequest, dateTime, LoadingState } from '@grafana/data';
|
||||
import { config } from '@grafana/runtime';
|
||||
|
||||
import { LokiDatasource } from './datasource';
|
||||
import * as logsTimeSplit from './logsTimeSplitting';
|
||||
import * as metricTimeSplit from './metricTimeSplitting';
|
||||
import { createLokiDatasource } from './mocks/datasource';
|
||||
import { getMockFrames } from './mocks/frames';
|
||||
import { runSplitQuery } from './querySplitting';
|
||||
@@ -282,18 +280,12 @@ describe('runSplitQuery()', () => {
|
||||
|
||||
describe('Hidden and empty queries', () => {
|
||||
beforeAll(() => {
|
||||
jest.spyOn(logsTimeSplit, 'splitTimeRange').mockReturnValue([]);
|
||||
jest.spyOn(metricTimeSplit, 'splitTimeRange').mockReturnValue([]);
|
||||
jest.useFakeTimers().setSystemTime(new Date('Wed May 17 2023 17:20:12 GMT+0200'));
|
||||
});
|
||||
beforeEach(() => {
|
||||
jest.mocked(logsTimeSplit.splitTimeRange).mockClear();
|
||||
jest.mocked(logsTimeSplit.splitTimeRange).mockClear();
|
||||
jest.mocked(trackGroupedQueries).mockClear();
|
||||
});
|
||||
afterAll(() => {
|
||||
jest.mocked(logsTimeSplit.splitTimeRange).mockRestore();
|
||||
jest.mocked(metricTimeSplit.splitTimeRange).mockRestore();
|
||||
jest.useRealTimers();
|
||||
});
|
||||
test('Ignores hidden queries', async () => {
|
||||
@@ -302,8 +294,6 @@ describe('runSplitQuery()', () => {
|
||||
{ expr: '{a="b"}', refId: 'B' },
|
||||
]);
|
||||
await expect(runSplitQuery(datasource, request)).toEmitValuesWith(() => {
|
||||
expect(logsTimeSplit.splitTimeRange).toHaveBeenCalled();
|
||||
expect(metricTimeSplit.splitTimeRange).not.toHaveBeenCalled();
|
||||
expect(trackGroupedQueries).toHaveBeenCalledTimes(1);
|
||||
expect(trackGroupedQueries).toHaveBeenCalledWith(
|
||||
{
|
||||
@@ -313,9 +303,10 @@ describe('runSplitQuery()', () => {
|
||||
},
|
||||
[
|
||||
{
|
||||
partition: [],
|
||||
partition: expect.any(Array),
|
||||
request: {
|
||||
...request,
|
||||
// Only includes queries that are not hidden
|
||||
targets: request.targets.filter((query) => !query.hide),
|
||||
},
|
||||
},
|
||||
@@ -331,8 +322,6 @@ describe('runSplitQuery()', () => {
|
||||
{ expr: '', refId: 'B' },
|
||||
]);
|
||||
await expect(runSplitQuery(datasource, request)).toEmitValuesWith(() => {
|
||||
expect(logsTimeSplit.splitTimeRange).not.toHaveBeenCalled();
|
||||
expect(metricTimeSplit.splitTimeRange).toHaveBeenCalled();
|
||||
expect(trackGroupedQueries).toHaveBeenCalledTimes(1);
|
||||
expect(trackGroupedQueries).toHaveBeenCalledWith(
|
||||
{
|
||||
@@ -342,9 +331,10 @@ describe('runSplitQuery()', () => {
|
||||
},
|
||||
[
|
||||
{
|
||||
partition: [],
|
||||
partition: expect.any(Array),
|
||||
request: {
|
||||
...request,
|
||||
// Only includes queries with an expression
|
||||
targets: request.targets.filter((query) => query.expr),
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
import { useState } from 'react';
|
||||
|
||||
import { SelectableValue, getDefaultTimeRange, toOption } from '@grafana/data';
|
||||
import { DataSourceApi, SelectableValue, getDefaultTimeRange, toOption } from '@grafana/data';
|
||||
import { QueryBuilderOperationParamEditorProps, VisualQueryModeller } from '@grafana/plugin-ui';
|
||||
import { Select } from '@grafana/ui';
|
||||
|
||||
import { placeHolderScopedVars } from '../../components/monaco-query-field/monaco-completion-provider/validation';
|
||||
import { LokiDatasource } from '../../datasource';
|
||||
import { getLogQueryFromMetricsQuery, isQueryWithError } from '../../queryUtils';
|
||||
import { extractUnwrapLabelKeysFromDataFrame } from '../../responseUtils';
|
||||
import { getOperationParamId } from '../operationUtils';
|
||||
import { LokiVisualQuery } from '../types';
|
||||
@@ -31,11 +28,9 @@ export function UnwrapParamEditor({
|
||||
inputId={getOperationParamId(operationId, index)}
|
||||
onOpenMenu={async () => {
|
||||
// This check is always true, we do it to make typescript happy
|
||||
if (datasource instanceof LokiDatasource) {
|
||||
setState({ isLoading: true });
|
||||
const options = await loadUnwrapOptions(query, datasource, queryModeller, timeRange);
|
||||
setState({ options, isLoading: undefined });
|
||||
}
|
||||
setState({ isLoading: true });
|
||||
const options = await loadUnwrapOptions(query, datasource, queryModeller, timeRange);
|
||||
setState({ options, isLoading: undefined });
|
||||
}}
|
||||
isLoading={state.isLoading}
|
||||
allowCustomValue
|
||||
@@ -54,17 +49,18 @@ export function UnwrapParamEditor({
|
||||
|
||||
async function loadUnwrapOptions(
|
||||
query: LokiVisualQuery,
|
||||
datasource: LokiDatasource,
|
||||
datasource: DataSourceApi,
|
||||
queryModeller: VisualQueryModeller,
|
||||
timeRange = getDefaultTimeRange()
|
||||
): Promise<Array<SelectableValue<string>>> {
|
||||
const queryExpr = queryModeller.renderQuery(query);
|
||||
const logExpr = getLogQueryFromMetricsQuery(queryExpr);
|
||||
if (isQueryWithError(datasource.interpolateString(logExpr, placeHolderScopedVars))) {
|
||||
if (!('getDataSamples' in datasource) || typeof datasource.getDataSamples !== 'function') {
|
||||
return [];
|
||||
}
|
||||
|
||||
const samples = await datasource.getDataSamples({ expr: logExpr, refId: 'unwrap_samples' }, timeRange);
|
||||
// the query is a metric query, we need to set metricQueryToLogConversion to true to getSamples use the log query
|
||||
const samples = await datasource.getDataSamples({ expr: queryExpr, refId: 'unwrap_samples' }, timeRange, {
|
||||
convertMetricQueryToLogQuery: true,
|
||||
});
|
||||
const unwrapLabels = extractUnwrapLabelKeysFromDataFrame(samples[0]);
|
||||
|
||||
const labelOptions = unwrapLabels.map((label) => ({
|
||||
|
||||
Reference in New Issue
Block a user