mirror of
https://github.com/grafana/grafana.git
synced 2026-07-29 15:59:50 -05:00
Loki: refactor mock instance creation and clean up datasource test (#54176)
* refactor(loki-test): move mock creation to mock module * refactor(loki-test): allow to pass custom settings to the mock constructor * refactor(loki-test): refactor mock factory in datasource test * refactor(loki-test): revert change in undefined test case for dsMaxLines * refactor(loki-test): move type assertion to mock definition * refactor(loki-test): fix more type issues * refactor(loki-explore-query-editor): refactor test to use createLokiDatasource() and fix type issues * refactor(loki-test): replace makeMockLokiDatasource with metadataRequest factory * fix: remove any * fix(loki-test): fix remaining usages of any * Fix: add missing exported type
This commit is contained in:
+1
-24
@@ -83,7 +83,7 @@ exports[`no enzyme tests`] = {
|
|||||||
"public/app/plugins/datasource/influxdb/components/ConfigEditor.test.tsx:57753101": [
|
"public/app/plugins/datasource/influxdb/components/ConfigEditor.test.tsx:57753101": [
|
||||||
[0, 19, 13, "RegExp match", "2409514259"]
|
[0, 19, 13, "RegExp match", "2409514259"]
|
||||||
],
|
],
|
||||||
"public/app/plugins/datasource/loki/components/LokiExploreQueryEditor.test.tsx:1488067923": [
|
"public/app/plugins/datasource/loki/components/LokiExploreQueryEditor.test.tsx:2984948507": [
|
||||||
[0, 26, 13, "RegExp match", "2409514259"]
|
[0, 26, 13, "RegExp match", "2409514259"]
|
||||||
],
|
],
|
||||||
"public/app/plugins/datasource/loki/components/LokiQueryEditor.test.tsx:146069464": [
|
"public/app/plugins/datasource/loki/components/LokiQueryEditor.test.tsx:146069464": [
|
||||||
@@ -7126,11 +7126,6 @@ exports[`better eslint`] = {
|
|||||||
"public/app/plugins/datasource/jaeger/util.ts:5381": [
|
"public/app/plugins/datasource/jaeger/util.ts:5381": [
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
||||||
],
|
],
|
||||||
"public/app/plugins/datasource/loki/components/LokiExploreQueryEditor.test.tsx:5381": [
|
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
|
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "1"],
|
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "2"]
|
|
||||||
],
|
|
||||||
"public/app/plugins/datasource/loki/components/LokiLabelBrowser.tsx:5381": [
|
"public/app/plugins/datasource/loki/components/LokiLabelBrowser.tsx:5381": [
|
||||||
[0, 0, 0, "Do not use any type assertions.", "0"],
|
[0, 0, 0, "Do not use any type assertions.", "0"],
|
||||||
[0, 0, 0, "Do not use any type assertions.", "1"]
|
[0, 0, 0, "Do not use any type assertions.", "1"]
|
||||||
@@ -7163,15 +7158,6 @@ exports[`better eslint`] = {
|
|||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "6"],
|
[0, 0, 0, "Unexpected any. Specify a different type.", "6"],
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "7"]
|
[0, 0, 0, "Unexpected any. Specify a different type.", "7"]
|
||||||
],
|
],
|
||||||
"public/app/plugins/datasource/loki/datasource.test.ts:5381": [
|
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
|
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "1"],
|
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "2"],
|
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "3"],
|
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "4"],
|
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "5"],
|
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "6"]
|
|
||||||
],
|
|
||||||
"public/app/plugins/datasource/loki/datasource.ts:5381": [
|
"public/app/plugins/datasource/loki/datasource.ts:5381": [
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
|
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "1"],
|
[0, 0, 0, "Unexpected any. Specify a different type.", "1"],
|
||||||
@@ -7185,11 +7171,6 @@ exports[`better eslint`] = {
|
|||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
|
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
|
||||||
[0, 0, 0, "Do not use any type assertions.", "1"]
|
[0, 0, 0, "Do not use any type assertions.", "1"]
|
||||||
],
|
],
|
||||||
"public/app/plugins/datasource/loki/language_provider.test.ts:5381": [
|
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
|
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "1"],
|
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "2"]
|
|
||||||
],
|
|
||||||
"public/app/plugins/datasource/loki/language_provider.ts:5381": [
|
"public/app/plugins/datasource/loki/language_provider.ts:5381": [
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
|
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "1"],
|
[0, 0, 0, "Unexpected any. Specify a different type.", "1"],
|
||||||
@@ -7210,10 +7191,6 @@ exports[`better eslint`] = {
|
|||||||
"public/app/plugins/datasource/loki/live_streams_result_transformer.ts:5381": [
|
"public/app/plugins/datasource/loki/live_streams_result_transformer.ts:5381": [
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
||||||
],
|
],
|
||||||
"public/app/plugins/datasource/loki/mocks.ts:5381": [
|
|
||||||
[0, 0, 0, "Do not use any type assertions.", "0"],
|
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "1"]
|
|
||||||
],
|
|
||||||
"public/app/plugins/datasource/loki/querybuilder/binaryScalarOperations.ts:5381": [
|
"public/app/plugins/datasource/loki/querybuilder/binaryScalarOperations.ts:5381": [
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -2,19 +2,22 @@ import { mount, shallow } from 'enzyme';
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { act } from 'react-dom/test-utils';
|
import { act } from 'react-dom/test-utils';
|
||||||
|
|
||||||
import { ExploreMode, LoadingState, PanelData, toUtc, TimeRange } from '@grafana/data';
|
import { LoadingState, PanelData, toUtc, TimeRange, HistoryItem } from '@grafana/data';
|
||||||
|
import { TemplateSrv } from '@grafana/runtime';
|
||||||
|
|
||||||
import { LokiDatasource } from '../datasource';
|
import { LokiDatasource } from '../datasource';
|
||||||
import LokiLanguageProvider from '../language_provider';
|
import LokiLanguageProvider from '../language_provider';
|
||||||
import { makeMockLokiDatasource } from '../mocks';
|
import { createLokiDatasource } from '../mocks';
|
||||||
import { LokiQuery } from '../types';
|
import { LokiQuery } from '../types';
|
||||||
|
|
||||||
import { LokiExploreQueryEditor } from './LokiExploreQueryEditor';
|
import { LokiExploreQueryEditor, Props } from './LokiExploreQueryEditor';
|
||||||
import { LokiOptionFields } from './LokiOptionFields';
|
import { LokiOptionFields } from './LokiOptionFields';
|
||||||
|
|
||||||
const setup = (renderMethod: any, propOverrides?: object) => {
|
const setup = (renderMethod: (c: JSX.Element) => ReturnType<typeof shallow> | ReturnType<typeof mount>) => {
|
||||||
const datasource: LokiDatasource = makeMockLokiDatasource({});
|
const datasource: LokiDatasource = createLokiDatasource({} as unknown as TemplateSrv);
|
||||||
datasource.languageProvider = new LokiLanguageProvider(datasource);
|
datasource.languageProvider = new LokiLanguageProvider(datasource);
|
||||||
|
jest.spyOn(datasource, 'metadataRequest').mockResolvedValue([]);
|
||||||
|
|
||||||
const onRunQuery = jest.fn();
|
const onRunQuery = jest.fn();
|
||||||
const onChange = jest.fn();
|
const onChange = jest.fn();
|
||||||
const query: LokiQuery = { expr: '', refId: 'A', maxLines: 0 };
|
const query: LokiQuery = { expr: '', refId: 'A', maxLines: 0 };
|
||||||
@@ -58,21 +61,18 @@ const setup = (renderMethod: any, propOverrides?: object) => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
const history: any[] = [];
|
const history: Array<HistoryItem<LokiQuery>> = [];
|
||||||
const exploreMode: ExploreMode = ExploreMode.Logs;
|
|
||||||
|
|
||||||
const props: any = {
|
const props: Props = {
|
||||||
query,
|
query,
|
||||||
data,
|
data,
|
||||||
range,
|
range,
|
||||||
datasource,
|
datasource,
|
||||||
exploreMode,
|
|
||||||
history,
|
history,
|
||||||
onChange,
|
onChange,
|
||||||
onRunQuery,
|
onRunQuery,
|
||||||
};
|
};
|
||||||
|
|
||||||
Object.assign(props, { ...props, ...propOverrides });
|
|
||||||
return renderMethod(<LokiExploreQueryEditor {...props} />);
|
return renderMethod(<LokiExploreQueryEditor {...props} />);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { LokiQuery, LokiOptions } from '../types';
|
|||||||
import { LokiOptionFields } from './LokiOptionFields';
|
import { LokiOptionFields } from './LokiOptionFields';
|
||||||
import { LokiQueryField } from './LokiQueryField';
|
import { LokiQueryField } from './LokiQueryField';
|
||||||
|
|
||||||
type Props = QueryEditorProps<LokiDatasource, LokiQuery, LokiOptions>;
|
export type Props = QueryEditorProps<LokiDatasource, LokiQuery, LokiOptions>;
|
||||||
|
|
||||||
export const LokiExploreQueryEditor = memo((props: Props) => {
|
export const LokiExploreQueryEditor = memo((props: Props) => {
|
||||||
const { query, data, datasource, history, onChange, onRunQuery, range } = props;
|
const { query, data, datasource, history, onChange, onRunQuery, range } = props;
|
||||||
|
|||||||
+78
-4
@@ -53,9 +53,48 @@ exports[`LokiExploreQueryEditor should render component 1`] = `
|
|||||||
}
|
}
|
||||||
data-testid="loki-editor-explore"
|
data-testid="loki-editor-explore"
|
||||||
datasource={
|
datasource={
|
||||||
Object {
|
LokiDatasource {
|
||||||
"getTimeRangeParams": [Function],
|
"annotations": Object {
|
||||||
"interpolateString": [Function],
|
"QueryEditor": Object {
|
||||||
|
"$$typeof": Symbol(react.memo),
|
||||||
|
"compare": null,
|
||||||
|
"type": [Function],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"getLogRowContext": [Function],
|
||||||
|
"id": 0,
|
||||||
|
"instanceSettings": Object {
|
||||||
|
"access": "direct",
|
||||||
|
"id": 0,
|
||||||
|
"jsonData": Object {
|
||||||
|
"maxLines": "20",
|
||||||
|
},
|
||||||
|
"meta": Object {
|
||||||
|
"baseUrl": "",
|
||||||
|
"id": "id",
|
||||||
|
"info": Object {
|
||||||
|
"author": Object {
|
||||||
|
"name": "Test",
|
||||||
|
},
|
||||||
|
"description": "",
|
||||||
|
"links": Array [],
|
||||||
|
"logos": Object {
|
||||||
|
"large": "",
|
||||||
|
"small": "",
|
||||||
|
},
|
||||||
|
"screenshots": Array [],
|
||||||
|
"updated": "",
|
||||||
|
"version": "",
|
||||||
|
},
|
||||||
|
"module": "",
|
||||||
|
"name": "name",
|
||||||
|
"type": "datasource",
|
||||||
|
},
|
||||||
|
"name": "",
|
||||||
|
"type": "",
|
||||||
|
"uid": "",
|
||||||
|
"url": "myloggingurl",
|
||||||
|
},
|
||||||
"languageProvider": LokiLanguageProvider {
|
"languageProvider": LokiLanguageProvider {
|
||||||
"cleanText": [Function],
|
"cleanText": [Function],
|
||||||
"datasource": [Circular],
|
"datasource": [Circular],
|
||||||
@@ -245,7 +284,42 @@ exports[`LokiExploreQueryEditor should render component 1`] = `
|
|||||||
"start": [Function],
|
"start": [Function],
|
||||||
"started": false,
|
"started": false,
|
||||||
},
|
},
|
||||||
"metadataRequest": [Function],
|
"maxLines": 20,
|
||||||
|
"meta": Object {
|
||||||
|
"baseUrl": "",
|
||||||
|
"id": "id",
|
||||||
|
"info": Object {
|
||||||
|
"author": Object {
|
||||||
|
"name": "Test",
|
||||||
|
},
|
||||||
|
"description": "",
|
||||||
|
"links": Array [],
|
||||||
|
"logos": Object {
|
||||||
|
"large": "",
|
||||||
|
"small": "",
|
||||||
|
},
|
||||||
|
"screenshots": Array [],
|
||||||
|
"updated": "",
|
||||||
|
"version": "",
|
||||||
|
},
|
||||||
|
"module": "",
|
||||||
|
"name": "name",
|
||||||
|
"type": "datasource",
|
||||||
|
},
|
||||||
|
"metadataRequest": [MockFunction],
|
||||||
|
"name": "",
|
||||||
|
"prepareLogRowContextQueryTarget": [Function],
|
||||||
|
"runLiveQuery": [Function],
|
||||||
|
"streamOptionsProvider": [Function],
|
||||||
|
"streams": LiveStreams {
|
||||||
|
"streams": Object {},
|
||||||
|
},
|
||||||
|
"templateSrv": Object {},
|
||||||
|
"timeSrv": Object {
|
||||||
|
"timeRange": [Function],
|
||||||
|
},
|
||||||
|
"type": "",
|
||||||
|
"uid": "",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
history={Array []}
|
history={Array []}
|
||||||
|
|||||||
@@ -14,36 +14,21 @@ import {
|
|||||||
FieldType,
|
FieldType,
|
||||||
LogRowModel,
|
LogRowModel,
|
||||||
MutableDataFrame,
|
MutableDataFrame,
|
||||||
toUtc,
|
|
||||||
} from '@grafana/data';
|
} from '@grafana/data';
|
||||||
import { BackendSrvRequest, FetchResponse, setBackendSrv, getBackendSrv, BackendSrv } from '@grafana/runtime';
|
import { BackendSrvRequest, FetchResponse, setBackendSrv, getBackendSrv, BackendSrv } from '@grafana/runtime';
|
||||||
import { TimeSrv } from 'app/features/dashboard/services/TimeSrv';
|
|
||||||
import { TemplateSrv } from 'app/features/templating/template_srv';
|
import { TemplateSrv } from 'app/features/templating/template_srv';
|
||||||
|
|
||||||
import { initialCustomVariableModelState } from '../../../features/variables/custom/reducer';
|
import { initialCustomVariableModelState } from '../../../features/variables/custom/reducer';
|
||||||
import { CustomVariableModel } from '../../../features/variables/types';
|
import { CustomVariableModel } from '../../../features/variables/types';
|
||||||
|
|
||||||
import { LokiDatasource } from './datasource';
|
import { LokiDatasource } from './datasource';
|
||||||
import { makeMockLokiDatasource } from './mocks';
|
import { createMetadataRequest, createLokiDatasource } from './mocks';
|
||||||
import { LokiOptions, LokiQuery, LokiQueryType } from './types';
|
import { LokiOptions, LokiQuery, LokiQueryType } from './types';
|
||||||
|
|
||||||
const rawRange = {
|
|
||||||
from: toUtc('2018-04-25 10:00'),
|
|
||||||
to: toUtc('2018-04-25 11:00'),
|
|
||||||
};
|
|
||||||
|
|
||||||
const timeSrvStub = {
|
|
||||||
timeRange: () => ({
|
|
||||||
from: rawRange.from,
|
|
||||||
to: rawRange.to,
|
|
||||||
raw: rawRange,
|
|
||||||
}),
|
|
||||||
} as unknown as TimeSrv;
|
|
||||||
|
|
||||||
const templateSrvStub = {
|
const templateSrvStub = {
|
||||||
getAdhocFilters: jest.fn(() => [] as any[]),
|
getAdhocFilters: jest.fn(() => [] as unknown[]),
|
||||||
replace: jest.fn((a: string, ...rest: any) => a),
|
replace: jest.fn((a: string, ...rest: unknown[]) => a),
|
||||||
};
|
} as unknown as TemplateSrv;
|
||||||
|
|
||||||
const testFrame: DataFrame = {
|
const testFrame: DataFrame = {
|
||||||
refId: 'A',
|
refId: 'A',
|
||||||
@@ -131,22 +116,16 @@ describe('LokiDatasource', () => {
|
|||||||
describe('when doing logs queries with limits', () => {
|
describe('when doing logs queries with limits', () => {
|
||||||
const runTest = async (
|
const runTest = async (
|
||||||
queryMaxLines: number | undefined,
|
queryMaxLines: number | undefined,
|
||||||
dsMaxLines: number | undefined,
|
dsMaxLines: string | undefined,
|
||||||
expectedMaxLines: number
|
expectedMaxLines: number
|
||||||
) => {
|
) => {
|
||||||
let settings = {
|
const settings = {
|
||||||
url: 'myloggingurl',
|
|
||||||
jsonData: {
|
jsonData: {
|
||||||
maxLines: dsMaxLines,
|
maxLines: dsMaxLines,
|
||||||
},
|
},
|
||||||
} as DataSourceInstanceSettings<LokiOptions>;
|
} as DataSourceInstanceSettings<LokiOptions>;
|
||||||
|
|
||||||
const templateSrvMock = {
|
const ds = createLokiDatasource(templateSrvStub, settings);
|
||||||
getAdhocFilters: (): any[] => [],
|
|
||||||
replace: (a: string) => a,
|
|
||||||
} as unknown as TemplateSrv;
|
|
||||||
|
|
||||||
const ds = new LokiDatasource(settings, templateSrvMock, timeSrvStub);
|
|
||||||
|
|
||||||
// we need to check the final query before it is sent out,
|
// we need to check the final query before it is sent out,
|
||||||
// and applyTemplateVariables is a convenient place to do that.
|
// and applyTemplateVariables is a convenient place to do that.
|
||||||
@@ -166,7 +145,7 @@ describe('LokiDatasource', () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
it('should use datasource max lines when no query max lines', async () => {
|
it('should use datasource max lines when no query max lines', async () => {
|
||||||
await runTest(undefined, 40, 40);
|
await runTest(undefined, '40', 40);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should use query max lines, if exists', async () => {
|
it('should use query max lines, if exists', async () => {
|
||||||
@@ -174,30 +153,22 @@ describe('LokiDatasource', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should use query max lines, if both exist, even if it is higher than ds max lines', async () => {
|
it('should use query max lines, if both exist, even if it is higher than ds max lines', async () => {
|
||||||
await runTest(80, 40, 80);
|
await runTest(80, '40', 80);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('When using adhoc filters', () => {
|
describe('When using adhoc filters', () => {
|
||||||
const DEFAULT_EXPR = 'rate({bar="baz", job="foo"} |= "bar" [5m])';
|
const DEFAULT_EXPR = 'rate({bar="baz", job="foo"} |= "bar" [5m])';
|
||||||
const query: LokiQuery = { expr: DEFAULT_EXPR, refId: 'A' };
|
const query: LokiQuery = { expr: DEFAULT_EXPR, refId: 'A' };
|
||||||
const originalAdhocFiltersMock = templateSrvStub.getAdhocFilters();
|
const mockedGetAdhocFilters = templateSrvStub.getAdhocFilters as jest.Mock;
|
||||||
const ds = new LokiDatasource(
|
const ds = createLokiDatasource(templateSrvStub);
|
||||||
{} as DataSourceInstanceSettings,
|
|
||||||
templateSrvStub as unknown as TemplateSrv,
|
|
||||||
timeSrvStub
|
|
||||||
);
|
|
||||||
|
|
||||||
afterAll(() => {
|
|
||||||
templateSrvStub.getAdhocFilters.mockReturnValue(originalAdhocFiltersMock);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not modify expression with no filters', async () => {
|
it('should not modify expression with no filters', async () => {
|
||||||
expect(ds.applyTemplateVariables(query, {}).expr).toBe(DEFAULT_EXPR);
|
expect(ds.applyTemplateVariables(query, {}).expr).toBe(DEFAULT_EXPR);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should add filters to expression', async () => {
|
it('should add filters to expression', async () => {
|
||||||
templateSrvStub.getAdhocFilters.mockReturnValue([
|
mockedGetAdhocFilters.mockReturnValue([
|
||||||
{
|
{
|
||||||
key: 'k1',
|
key: 'k1',
|
||||||
operator: '=',
|
operator: '=',
|
||||||
@@ -216,7 +187,7 @@ describe('LokiDatasource', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should add escaping if needed to regex filter expressions', async () => {
|
it('should add escaping if needed to regex filter expressions', async () => {
|
||||||
templateSrvStub.getAdhocFilters.mockReturnValue([
|
mockedGetAdhocFilters.mockReturnValue([
|
||||||
{
|
{
|
||||||
key: 'k1',
|
key: 'k1',
|
||||||
operator: '=~',
|
operator: '=~',
|
||||||
@@ -239,7 +210,7 @@ describe('LokiDatasource', () => {
|
|||||||
let variable: CustomVariableModel;
|
let variable: CustomVariableModel;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
ds = createLokiDSForTests();
|
ds = createLokiDatasource(templateSrvStub);
|
||||||
variable = { ...initialCustomVariableModelState };
|
variable = { ...initialCustomVariableModelState };
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -281,8 +252,12 @@ describe('LokiDatasource', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('when performing testDataSource', () => {
|
describe('when performing testDataSource', () => {
|
||||||
|
let ds: LokiDatasource;
|
||||||
|
beforeEach(() => {
|
||||||
|
ds = createLokiDatasource(templateSrvStub);
|
||||||
|
});
|
||||||
|
|
||||||
it('should return successfully when call succeeds with labels', async () => {
|
it('should return successfully when call succeeds with labels', async () => {
|
||||||
const ds = createLokiDSForTests({} as TemplateSrv);
|
|
||||||
ds.metadataRequest = () => Promise.resolve(['avalue']);
|
ds.metadataRequest = () => Promise.resolve(['avalue']);
|
||||||
|
|
||||||
const result = await ds.testDatasource();
|
const result = await ds.testDatasource();
|
||||||
@@ -294,7 +269,6 @@ describe('LokiDatasource', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should return error when call succeeds without labels', async () => {
|
it('should return error when call succeeds without labels', async () => {
|
||||||
const ds = createLokiDSForTests({} as TemplateSrv);
|
|
||||||
ds.metadataRequest = () => Promise.resolve([]);
|
ds.metadataRequest = () => Promise.resolve([]);
|
||||||
|
|
||||||
const result = await ds.testDatasource();
|
const result = await ds.testDatasource();
|
||||||
@@ -306,7 +280,6 @@ describe('LokiDatasource', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should return error status with no details when call fails with no details', async () => {
|
it('should return error status with no details when call fails with no details', async () => {
|
||||||
const ds = createLokiDSForTests({} as TemplateSrv);
|
|
||||||
ds.metadataRequest = () => Promise.reject({});
|
ds.metadataRequest = () => Promise.reject({});
|
||||||
|
|
||||||
const result = await ds.testDatasource();
|
const result = await ds.testDatasource();
|
||||||
@@ -318,7 +291,6 @@ describe('LokiDatasource', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should return error status with details when call fails with details', async () => {
|
it('should return error status with details when call fails with details', async () => {
|
||||||
const ds = createLokiDSForTests({} as TemplateSrv);
|
|
||||||
ds.metadataRequest = () =>
|
ds.metadataRequest = () =>
|
||||||
Promise.reject({
|
Promise.reject({
|
||||||
data: {
|
data: {
|
||||||
@@ -336,10 +308,10 @@ describe('LokiDatasource', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('when calling annotationQuery', () => {
|
describe('when calling annotationQuery', () => {
|
||||||
const getTestContext = (frame: DataFrame, options: any = []) => {
|
const getTestContext = (frame: DataFrame, options = {}) => {
|
||||||
const query = makeAnnotationQueryRequest(options);
|
const query = makeAnnotationQueryRequest(options);
|
||||||
|
|
||||||
const ds = createLokiDSForTests();
|
const ds = createLokiDatasource(templateSrvStub);
|
||||||
const response: DataQueryResponse = {
|
const response: DataQueryResponse = {
|
||||||
data: [frame],
|
data: [frame],
|
||||||
};
|
};
|
||||||
@@ -477,20 +449,22 @@ describe('LokiDatasource', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('metricFindQuery', () => {
|
describe('metricFindQuery', () => {
|
||||||
const getTestContext = (mock: LokiDatasource) => {
|
const getTestContext = () => {
|
||||||
const ds = createLokiDSForTests();
|
const ds = createLokiDatasource(templateSrvStub);
|
||||||
ds.metadataRequest = mock.metadataRequest;
|
jest
|
||||||
|
.spyOn(ds, 'metadataRequest')
|
||||||
|
.mockImplementation(
|
||||||
|
createMetadataRequest(
|
||||||
|
{ label1: ['value1', 'value2'], label2: ['value3', 'value4'] },
|
||||||
|
{ '{label1="value1", label2="value2"}': [{ label5: 'value5' }] }
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
return { ds };
|
return { ds };
|
||||||
};
|
};
|
||||||
|
|
||||||
const mock = makeMockLokiDatasource(
|
|
||||||
{ label1: ['value1', 'value2'], label2: ['value3', 'value4'] },
|
|
||||||
{ '{label1="value1", label2="value2"}': [{ label5: 'value5' }] }
|
|
||||||
);
|
|
||||||
|
|
||||||
it(`should return label names for Loki`, async () => {
|
it(`should return label names for Loki`, async () => {
|
||||||
const { ds } = getTestContext(mock);
|
const { ds } = getTestContext();
|
||||||
|
|
||||||
const res = await ds.metricFindQuery('label_names()');
|
const res = await ds.metricFindQuery('label_names()');
|
||||||
|
|
||||||
@@ -498,7 +472,7 @@ describe('LokiDatasource', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it(`should return label values for Loki when no matcher`, async () => {
|
it(`should return label values for Loki when no matcher`, async () => {
|
||||||
const { ds } = getTestContext(mock);
|
const { ds } = getTestContext();
|
||||||
|
|
||||||
const res = await ds.metricFindQuery('label_values(label1)');
|
const res = await ds.metricFindQuery('label_values(label1)');
|
||||||
|
|
||||||
@@ -506,7 +480,7 @@ describe('LokiDatasource', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it(`should return label values for Loki with matcher`, async () => {
|
it(`should return label values for Loki with matcher`, async () => {
|
||||||
const { ds } = getTestContext(mock);
|
const { ds } = getTestContext();
|
||||||
|
|
||||||
const res = await ds.metricFindQuery('label_values({label1="value1", label2="value2"},label5)');
|
const res = await ds.metricFindQuery('label_values({label1="value1", label2="value2"},label5)');
|
||||||
|
|
||||||
@@ -514,7 +488,7 @@ describe('LokiDatasource', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it(`should return empty array when incorrect query for Loki`, async () => {
|
it(`should return empty array when incorrect query for Loki`, async () => {
|
||||||
const { ds } = getTestContext(mock);
|
const { ds } = getTestContext();
|
||||||
|
|
||||||
const res = await ds.metricFindQuery('incorrect_query');
|
const res = await ds.metricFindQuery('incorrect_query');
|
||||||
|
|
||||||
@@ -524,11 +498,15 @@ describe('LokiDatasource', () => {
|
|||||||
|
|
||||||
describe('modifyQuery', () => {
|
describe('modifyQuery', () => {
|
||||||
describe('when called with ADD_FILTER', () => {
|
describe('when called with ADD_FILTER', () => {
|
||||||
|
let ds: LokiDatasource;
|
||||||
|
beforeEach(() => {
|
||||||
|
ds = createLokiDatasource(templateSrvStub);
|
||||||
|
});
|
||||||
|
|
||||||
describe('and query has no parser', () => {
|
describe('and query has no parser', () => {
|
||||||
it('then the correct label should be added for logs query', () => {
|
it('then the correct label should be added for logs query', () => {
|
||||||
const query: LokiQuery = { refId: 'A', expr: '{bar="baz"}' };
|
const query: LokiQuery = { refId: 'A', expr: '{bar="baz"}' };
|
||||||
const action = { options: { key: 'job', value: 'grafana' }, type: 'ADD_FILTER' };
|
const action = { options: { key: 'job', value: 'grafana' }, type: 'ADD_FILTER' };
|
||||||
const ds = createLokiDSForTests();
|
|
||||||
const result = ds.modifyQuery(query, action);
|
const result = ds.modifyQuery(query, action);
|
||||||
|
|
||||||
expect(result.refId).toEqual('A');
|
expect(result.refId).toEqual('A');
|
||||||
@@ -538,7 +516,6 @@ describe('LokiDatasource', () => {
|
|||||||
it('then the correctly escaped label should be added for logs query', () => {
|
it('then the correctly escaped label should be added for logs query', () => {
|
||||||
const query: LokiQuery = { refId: 'A', expr: '{bar="baz"}' };
|
const query: LokiQuery = { refId: 'A', expr: '{bar="baz"}' };
|
||||||
const action = { options: { key: 'job', value: '\\test' }, type: 'ADD_FILTER' };
|
const action = { options: { key: 'job', value: '\\test' }, type: 'ADD_FILTER' };
|
||||||
const ds = createLokiDSForTests();
|
|
||||||
const result = ds.modifyQuery(query, action);
|
const result = ds.modifyQuery(query, action);
|
||||||
|
|
||||||
expect(result.refId).toEqual('A');
|
expect(result.refId).toEqual('A');
|
||||||
@@ -548,7 +525,6 @@ describe('LokiDatasource', () => {
|
|||||||
it('then the correct label should be added for metrics query', () => {
|
it('then the correct label should be added for metrics query', () => {
|
||||||
const query: LokiQuery = { refId: 'A', expr: 'rate({bar="baz"}[5m])' };
|
const query: LokiQuery = { refId: 'A', expr: 'rate({bar="baz"}[5m])' };
|
||||||
const action = { options: { key: 'job', value: 'grafana' }, type: 'ADD_FILTER' };
|
const action = { options: { key: 'job', value: 'grafana' }, type: 'ADD_FILTER' };
|
||||||
const ds = createLokiDSForTests();
|
|
||||||
const result = ds.modifyQuery(query, action);
|
const result = ds.modifyQuery(query, action);
|
||||||
|
|
||||||
expect(result.refId).toEqual('A');
|
expect(result.refId).toEqual('A');
|
||||||
@@ -558,7 +534,6 @@ describe('LokiDatasource', () => {
|
|||||||
it('then the correct label should be added for logs query', () => {
|
it('then the correct label should be added for logs query', () => {
|
||||||
const query: LokiQuery = { refId: 'A', expr: '{bar="baz"} | logfmt' };
|
const query: LokiQuery = { refId: 'A', expr: '{bar="baz"} | logfmt' };
|
||||||
const action = { options: { key: 'job', value: 'grafana' }, type: 'ADD_FILTER' };
|
const action = { options: { key: 'job', value: 'grafana' }, type: 'ADD_FILTER' };
|
||||||
const ds = createLokiDSForTests();
|
|
||||||
const result = ds.modifyQuery(query, action);
|
const result = ds.modifyQuery(query, action);
|
||||||
|
|
||||||
expect(result.refId).toEqual('A');
|
expect(result.refId).toEqual('A');
|
||||||
@@ -567,7 +542,6 @@ describe('LokiDatasource', () => {
|
|||||||
it('then the correct label should be added for metrics query', () => {
|
it('then the correct label should be added for metrics query', () => {
|
||||||
const query: LokiQuery = { refId: 'A', expr: 'rate({bar="baz"} | logfmt [5m])' };
|
const query: LokiQuery = { refId: 'A', expr: 'rate({bar="baz"} | logfmt [5m])' };
|
||||||
const action = { options: { key: 'job', value: 'grafana' }, type: 'ADD_FILTER' };
|
const action = { options: { key: 'job', value: 'grafana' }, type: 'ADD_FILTER' };
|
||||||
const ds = createLokiDSForTests();
|
|
||||||
const result = ds.modifyQuery(query, action);
|
const result = ds.modifyQuery(query, action);
|
||||||
|
|
||||||
expect(result.refId).toEqual('A');
|
expect(result.refId).toEqual('A');
|
||||||
@@ -579,10 +553,14 @@ describe('LokiDatasource', () => {
|
|||||||
|
|
||||||
describe('when called with ADD_FILTER_OUT', () => {
|
describe('when called with ADD_FILTER_OUT', () => {
|
||||||
describe('and query has no parser', () => {
|
describe('and query has no parser', () => {
|
||||||
|
let ds: LokiDatasource;
|
||||||
|
beforeEach(() => {
|
||||||
|
ds = createLokiDatasource(templateSrvStub);
|
||||||
|
});
|
||||||
|
|
||||||
it('then the correct label should be added for logs query', () => {
|
it('then the correct label should be added for logs query', () => {
|
||||||
const query: LokiQuery = { refId: 'A', expr: '{bar="baz"}' };
|
const query: LokiQuery = { refId: 'A', expr: '{bar="baz"}' };
|
||||||
const action = { options: { key: 'job', value: 'grafana' }, type: 'ADD_FILTER_OUT' };
|
const action = { options: { key: 'job', value: 'grafana' }, type: 'ADD_FILTER_OUT' };
|
||||||
const ds = createLokiDSForTests();
|
|
||||||
const result = ds.modifyQuery(query, action);
|
const result = ds.modifyQuery(query, action);
|
||||||
|
|
||||||
expect(result.refId).toEqual('A');
|
expect(result.refId).toEqual('A');
|
||||||
@@ -592,7 +570,6 @@ describe('LokiDatasource', () => {
|
|||||||
it('then the correctly escaped label should be added for logs query', () => {
|
it('then the correctly escaped label should be added for logs query', () => {
|
||||||
const query: LokiQuery = { refId: 'A', expr: '{bar="baz"}' };
|
const query: LokiQuery = { refId: 'A', expr: '{bar="baz"}' };
|
||||||
const action = { options: { key: 'job', value: '"test' }, type: 'ADD_FILTER_OUT' };
|
const action = { options: { key: 'job', value: '"test' }, type: 'ADD_FILTER_OUT' };
|
||||||
const ds = createLokiDSForTests();
|
|
||||||
const result = ds.modifyQuery(query, action);
|
const result = ds.modifyQuery(query, action);
|
||||||
|
|
||||||
expect(result.refId).toEqual('A');
|
expect(result.refId).toEqual('A');
|
||||||
@@ -602,17 +579,20 @@ describe('LokiDatasource', () => {
|
|||||||
it('then the correct label should be added for metrics query', () => {
|
it('then the correct label should be added for metrics query', () => {
|
||||||
const query: LokiQuery = { refId: 'A', expr: 'rate({bar="baz"}[5m])' };
|
const query: LokiQuery = { refId: 'A', expr: 'rate({bar="baz"}[5m])' };
|
||||||
const action = { options: { key: 'job', value: 'grafana' }, type: 'ADD_FILTER_OUT' };
|
const action = { options: { key: 'job', value: 'grafana' }, type: 'ADD_FILTER_OUT' };
|
||||||
const ds = createLokiDSForTests();
|
|
||||||
const result = ds.modifyQuery(query, action);
|
const result = ds.modifyQuery(query, action);
|
||||||
|
|
||||||
expect(result.refId).toEqual('A');
|
expect(result.refId).toEqual('A');
|
||||||
expect(result.expr).toEqual('rate({bar="baz", job!="grafana"}[5m])');
|
expect(result.expr).toEqual('rate({bar="baz", job!="grafana"}[5m])');
|
||||||
});
|
});
|
||||||
describe('and query has parser', () => {
|
describe('and query has parser', () => {
|
||||||
|
let ds: LokiDatasource;
|
||||||
|
beforeEach(() => {
|
||||||
|
ds = createLokiDatasource(templateSrvStub);
|
||||||
|
});
|
||||||
|
|
||||||
it('then the correct label should be added for logs query', () => {
|
it('then the correct label should be added for logs query', () => {
|
||||||
const query: LokiQuery = { refId: 'A', expr: '{bar="baz"} | logfmt' };
|
const query: LokiQuery = { refId: 'A', expr: '{bar="baz"} | logfmt' };
|
||||||
const action = { options: { key: 'job', value: 'grafana' }, type: 'ADD_FILTER_OUT' };
|
const action = { options: { key: 'job', value: 'grafana' }, type: 'ADD_FILTER_OUT' };
|
||||||
const ds = createLokiDSForTests();
|
|
||||||
const result = ds.modifyQuery(query, action);
|
const result = ds.modifyQuery(query, action);
|
||||||
|
|
||||||
expect(result.refId).toEqual('A');
|
expect(result.refId).toEqual('A');
|
||||||
@@ -621,7 +601,6 @@ describe('LokiDatasource', () => {
|
|||||||
it('then the correct label should be added for metrics query', () => {
|
it('then the correct label should be added for metrics query', () => {
|
||||||
const query: LokiQuery = { refId: 'A', expr: 'rate({bar="baz"} | logfmt [5m])' };
|
const query: LokiQuery = { refId: 'A', expr: 'rate({bar="baz"} | logfmt [5m])' };
|
||||||
const action = { options: { key: 'job', value: 'grafana' }, type: 'ADD_FILTER_OUT' };
|
const action = { options: { key: 'job', value: 'grafana' }, type: 'ADD_FILTER_OUT' };
|
||||||
const ds = createLokiDSForTests();
|
|
||||||
const result = ds.modifyQuery(query, action);
|
const result = ds.modifyQuery(query, action);
|
||||||
|
|
||||||
expect(result.refId).toEqual('A');
|
expect(result.refId).toEqual('A');
|
||||||
@@ -649,7 +628,7 @@ describe('LokiDatasource', () => {
|
|||||||
getAdhocFilters: (): AdHocFilter[] => adHocFilters,
|
getAdhocFilters: (): AdHocFilter[] => adHocFilters,
|
||||||
replace: (a: string) => a,
|
replace: (a: string) => a,
|
||||||
} as unknown as TemplateSrv;
|
} as unknown as TemplateSrv;
|
||||||
ds = createLokiDSForTests(templateSrvMock);
|
ds = createLokiDatasource(templateSrvMock);
|
||||||
});
|
});
|
||||||
describe('and query has no parser', () => {
|
describe('and query has no parser', () => {
|
||||||
it('then the correct label should be added for logs query', () => {
|
it('then the correct label should be added for logs query', () => {
|
||||||
@@ -684,7 +663,7 @@ describe('LokiDatasource', () => {
|
|||||||
getAdhocFilters: (): AdHocFilter[] => adHocFilters,
|
getAdhocFilters: (): AdHocFilter[] => adHocFilters,
|
||||||
replace: (a: string) => a,
|
replace: (a: string) => a,
|
||||||
} as unknown as TemplateSrv;
|
} as unknown as TemplateSrv;
|
||||||
ds = createLokiDSForTests(templateSrvMock);
|
ds = createLokiDatasource(templateSrvMock);
|
||||||
});
|
});
|
||||||
describe('and query has no parser', () => {
|
describe('and query has no parser', () => {
|
||||||
it('then the correct label should be added for logs query', () => {
|
it('then the correct label should be added for logs query', () => {
|
||||||
@@ -707,7 +686,7 @@ describe('LokiDatasource', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('prepareLogRowContextQueryTarget', () => {
|
describe('prepareLogRowContextQueryTarget', () => {
|
||||||
const ds = createLokiDSForTests();
|
const ds = createLokiDatasource(templateSrvStub);
|
||||||
it('creates query with only labels from /labels API', async () => {
|
it('creates query with only labels from /labels API', async () => {
|
||||||
const row: LogRowModel = {
|
const row: LogRowModel = {
|
||||||
rowIndex: 0,
|
rowIndex: 0,
|
||||||
@@ -758,8 +737,12 @@ describe('LokiDatasource', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('logs volume data provider', () => {
|
describe('logs volume data provider', () => {
|
||||||
|
let ds: LokiDatasource;
|
||||||
|
beforeEach(() => {
|
||||||
|
ds = createLokiDatasource(templateSrvStub);
|
||||||
|
});
|
||||||
|
|
||||||
it('creates provider for logs query', () => {
|
it('creates provider for logs query', () => {
|
||||||
const ds = createLokiDSForTests();
|
|
||||||
const options = getQueryOptions<LokiQuery>({
|
const options = getQueryOptions<LokiQuery>({
|
||||||
targets: [{ expr: '{label=value}', refId: 'A' }],
|
targets: [{ expr: '{label=value}', refId: 'A' }],
|
||||||
});
|
});
|
||||||
@@ -768,7 +751,6 @@ describe('LokiDatasource', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('does not create provider for metrics query', () => {
|
it('does not create provider for metrics query', () => {
|
||||||
const ds = createLokiDSForTests();
|
|
||||||
const options = getQueryOptions<LokiQuery>({
|
const options = getQueryOptions<LokiQuery>({
|
||||||
targets: [{ expr: 'rate({label=value}[1m])', refId: 'A' }],
|
targets: [{ expr: 'rate({label=value}[1m])', refId: 'A' }],
|
||||||
});
|
});
|
||||||
@@ -777,7 +759,6 @@ describe('LokiDatasource', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('creates provider if at least one query is a logs query', () => {
|
it('creates provider if at least one query is a logs query', () => {
|
||||||
const ds = createLokiDSForTests();
|
|
||||||
const options = getQueryOptions<LokiQuery>({
|
const options = getQueryOptions<LokiQuery>({
|
||||||
targets: [
|
targets: [
|
||||||
{ expr: 'rate({label=value}[1m])', refId: 'A' },
|
{ expr: 'rate({label=value}[1m])', refId: 'A' },
|
||||||
@@ -789,7 +770,6 @@ describe('LokiDatasource', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('does not create provider if there is only an instant logs query', () => {
|
it('does not create provider if there is only an instant logs query', () => {
|
||||||
const ds = createLokiDSForTests();
|
|
||||||
const options = getQueryOptions<LokiQuery>({
|
const options = getQueryOptions<LokiQuery>({
|
||||||
targets: [{ expr: '{label=value', refId: 'A', queryType: LokiQueryType.Instant }],
|
targets: [{ expr: '{label=value', refId: 'A', queryType: LokiQueryType.Instant }],
|
||||||
});
|
});
|
||||||
@@ -799,8 +779,12 @@ describe('LokiDatasource', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('importing queries', () => {
|
describe('importing queries', () => {
|
||||||
|
let ds: LokiDatasource;
|
||||||
|
beforeEach(() => {
|
||||||
|
ds = createLokiDatasource(templateSrvStub);
|
||||||
|
});
|
||||||
|
|
||||||
it('keeps all labels when no labels are loaded', async () => {
|
it('keeps all labels when no labels are loaded', async () => {
|
||||||
const ds = createLokiDSForTests();
|
|
||||||
ds.getResource = () => Promise.resolve({ data: [] });
|
ds.getResource = () => Promise.resolve({ data: [] });
|
||||||
const queries = await ds.importFromAbstractQueries([
|
const queries = await ds.importFromAbstractQueries([
|
||||||
{
|
{
|
||||||
@@ -815,7 +799,6 @@ describe('LokiDatasource', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('filters out non existing labels', async () => {
|
it('filters out non existing labels', async () => {
|
||||||
const ds = createLokiDSForTests();
|
|
||||||
ds.getResource = () => Promise.resolve({ data: ['foo'] });
|
ds.getResource = () => Promise.resolve({ data: ['foo'] });
|
||||||
const queries = await ds.importFromAbstractQueries([
|
const queries = await ds.importFromAbstractQueries([
|
||||||
{
|
{
|
||||||
@@ -833,7 +816,7 @@ describe('LokiDatasource', () => {
|
|||||||
|
|
||||||
describe('applyTemplateVariables', () => {
|
describe('applyTemplateVariables', () => {
|
||||||
it('should add the adhoc filter to the query', () => {
|
it('should add the adhoc filter to the query', () => {
|
||||||
const ds = createLokiDSForTests();
|
const ds = createLokiDatasource(templateSrvStub);
|
||||||
const spy = jest.spyOn(ds, 'addAdHocFilters');
|
const spy = jest.spyOn(ds, 'addAdHocFilters');
|
||||||
ds.applyTemplateVariables({ expr: '{test}', refId: 'A' }, {});
|
ds.applyTemplateVariables({ expr: '{test}', refId: 'A' }, {});
|
||||||
expect(spy).toHaveBeenCalledWith('{test}');
|
expect(spy).toHaveBeenCalledWith('{test}');
|
||||||
@@ -847,23 +830,7 @@ function assertAdHocFilters(query: string, expectedResults: string, ds: LokiData
|
|||||||
expect(result).toEqual(expectedResults);
|
expect(result).toEqual(expectedResults);
|
||||||
}
|
}
|
||||||
|
|
||||||
function createLokiDSForTests(
|
function makeAnnotationQueryRequest(options = {}): AnnotationQueryRequest<LokiQuery> {
|
||||||
templateSrvMock = {
|
|
||||||
getAdhocFilters: (): any[] => [],
|
|
||||||
replace: (a: string) => a,
|
|
||||||
} as unknown as TemplateSrv
|
|
||||||
): LokiDatasource {
|
|
||||||
const instanceSettings = {
|
|
||||||
url: 'myloggingurl',
|
|
||||||
} as DataSourceInstanceSettings;
|
|
||||||
|
|
||||||
const customData = { ...(instanceSettings.jsonData || {}), maxLines: 20 };
|
|
||||||
const customSettings: DataSourceInstanceSettings = { ...instanceSettings, jsonData: customData };
|
|
||||||
|
|
||||||
return new LokiDatasource(customSettings, templateSrvMock, timeSrvStub as TimeSrv);
|
|
||||||
}
|
|
||||||
|
|
||||||
function makeAnnotationQueryRequest(options: any): AnnotationQueryRequest<LokiQuery> {
|
|
||||||
const timeRange = {
|
const timeRange = {
|
||||||
from: dateTime(),
|
from: dateTime(),
|
||||||
to: dateTime(),
|
to: dateTime(),
|
||||||
@@ -872,7 +839,9 @@ function makeAnnotationQueryRequest(options: any): AnnotationQueryRequest<LokiQu
|
|||||||
annotation: {
|
annotation: {
|
||||||
expr: '{test=test}',
|
expr: '{test=test}',
|
||||||
refId: '',
|
refId: '',
|
||||||
datasource: 'loki',
|
datasource: {
|
||||||
|
type: 'loki',
|
||||||
|
},
|
||||||
enable: true,
|
enable: true,
|
||||||
name: 'test-annotation',
|
name: 'test-annotation',
|
||||||
iconColor: 'red',
|
iconColor: 'red',
|
||||||
@@ -880,7 +849,7 @@ function makeAnnotationQueryRequest(options: any): AnnotationQueryRequest<LokiQu
|
|||||||
},
|
},
|
||||||
dashboard: {
|
dashboard: {
|
||||||
id: 1,
|
id: 1,
|
||||||
} as any,
|
},
|
||||||
range: {
|
range: {
|
||||||
...timeRange,
|
...timeRange,
|
||||||
raw: timeRange,
|
raw: timeRange,
|
||||||
|
|||||||
@@ -2,10 +2,11 @@ import Plain from 'slate-plain-serializer';
|
|||||||
|
|
||||||
import { AbstractLabelOperator } from '@grafana/data';
|
import { AbstractLabelOperator } from '@grafana/data';
|
||||||
import { TypeaheadInput } from '@grafana/ui';
|
import { TypeaheadInput } from '@grafana/ui';
|
||||||
|
import { TemplateSrv } from 'app/features/templating/template_srv';
|
||||||
|
|
||||||
import { LokiDatasource } from './datasource';
|
import { LokiDatasource } from './datasource';
|
||||||
import LanguageProvider, { LokiHistoryItem } from './language_provider';
|
import LanguageProvider, { LokiHistoryItem } from './language_provider';
|
||||||
import { makeMockLokiDatasource } from './mocks';
|
import { createLokiDatasource, createMetadataRequest } from './mocks';
|
||||||
import { LokiQueryType } from './types';
|
import { LokiQueryType } from './types';
|
||||||
|
|
||||||
jest.mock('app/store/store', () => ({
|
jest.mock('app/store/store', () => ({
|
||||||
@@ -21,7 +22,7 @@ jest.mock('app/store/store', () => ({
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
describe('Language completion provider', () => {
|
describe('Language completion provider', () => {
|
||||||
const datasource = makeMockLokiDatasource({});
|
const datasource = setup({});
|
||||||
|
|
||||||
describe('query suggestions', () => {
|
describe('query suggestions', () => {
|
||||||
it('returns no suggestions on empty context', async () => {
|
it('returns no suggestions on empty context', async () => {
|
||||||
@@ -90,7 +91,7 @@ describe('Language completion provider', () => {
|
|||||||
|
|
||||||
describe('fetchSeries', () => {
|
describe('fetchSeries', () => {
|
||||||
it('should use match[] parameter', () => {
|
it('should use match[] parameter', () => {
|
||||||
const datasource = makeMockLokiDatasource({}, { '{foo="bar"}': [{ label1: 'label_val1' }] });
|
const datasource = setup({}, { '{foo="bar"}': [{ label1: 'label_val1' }] });
|
||||||
const languageProvider = new LanguageProvider(datasource);
|
const languageProvider = new LanguageProvider(datasource);
|
||||||
const fetchSeries = languageProvider.fetchSeries;
|
const fetchSeries = languageProvider.fetchSeries;
|
||||||
const requestSpy = jest.spyOn(languageProvider, 'request');
|
const requestSpy = jest.spyOn(languageProvider, 'request');
|
||||||
@@ -105,11 +106,11 @@ describe('Language completion provider', () => {
|
|||||||
|
|
||||||
describe('fetchSeriesLabels', () => {
|
describe('fetchSeriesLabels', () => {
|
||||||
it('should interpolate variable in series', () => {
|
it('should interpolate variable in series', () => {
|
||||||
const datasource: LokiDatasource = {
|
const datasource = setup({});
|
||||||
metadataRequest: () => ({ data: { data: [] as any[] } }),
|
jest.spyOn(datasource, 'getTimeRangeParams').mockReturnValue({ start: 0, end: 1 });
|
||||||
getTimeRangeParams: () => ({ start: 0, end: 1 }),
|
jest
|
||||||
interpolateString: (string: string) => string.replace(/\$/, 'interpolated-'),
|
.spyOn(datasource, 'interpolateString')
|
||||||
} as any as LokiDatasource;
|
.mockImplementation((string: string) => string.replace(/\$/, 'interpolated-'));
|
||||||
|
|
||||||
const languageProvider = new LanguageProvider(datasource);
|
const languageProvider = new LanguageProvider(datasource);
|
||||||
const fetchSeriesLabels = languageProvider.fetchSeriesLabels;
|
const fetchSeriesLabels = languageProvider.fetchSeriesLabels;
|
||||||
@@ -126,7 +127,7 @@ describe('Language completion provider', () => {
|
|||||||
|
|
||||||
describe('label key suggestions', () => {
|
describe('label key suggestions', () => {
|
||||||
it('returns all label suggestions on empty selector', async () => {
|
it('returns all label suggestions on empty selector', async () => {
|
||||||
const datasource = makeMockLokiDatasource({ label1: [], label2: [] });
|
const datasource = setup({ label1: [], label2: [] });
|
||||||
const provider = await getLanguageProvider(datasource);
|
const provider = await getLanguageProvider(datasource);
|
||||||
const input = createTypeaheadInput('{}', '', '', 1);
|
const input = createTypeaheadInput('{}', '', '', 1);
|
||||||
const result = await provider.provideCompletionItems(input);
|
const result = await provider.provideCompletionItems(input);
|
||||||
@@ -143,7 +144,7 @@ describe('Language completion provider', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('returns all label suggestions on selector when starting to type', async () => {
|
it('returns all label suggestions on selector when starting to type', async () => {
|
||||||
const datasource = makeMockLokiDatasource({ label1: [], label2: [] });
|
const datasource = setup({ label1: [], label2: [] });
|
||||||
const provider = await getLanguageProvider(datasource);
|
const provider = await getLanguageProvider(datasource);
|
||||||
const input = createTypeaheadInput('{l}', '', '', 2);
|
const input = createTypeaheadInput('{l}', '', '', 2);
|
||||||
const result = await provider.provideCompletionItems(input);
|
const result = await provider.provideCompletionItems(input);
|
||||||
@@ -162,10 +163,7 @@ describe('Language completion provider', () => {
|
|||||||
|
|
||||||
describe('label suggestions facetted', () => {
|
describe('label suggestions facetted', () => {
|
||||||
it('returns facetted label suggestions based on selector', async () => {
|
it('returns facetted label suggestions based on selector', async () => {
|
||||||
const datasource = makeMockLokiDatasource(
|
const datasource = setup({ label1: [], label2: [] }, { '{foo="bar"}': [{ label1: 'label_val1' }] });
|
||||||
{ label1: [], label2: [] },
|
|
||||||
{ '{foo="bar"}': [{ label1: 'label_val1' }] }
|
|
||||||
);
|
|
||||||
const provider = await getLanguageProvider(datasource);
|
const provider = await getLanguageProvider(datasource);
|
||||||
const input = createTypeaheadInput('{foo="bar",}', '', '', 11);
|
const input = createTypeaheadInput('{foo="bar",}', '', '', 11);
|
||||||
const result = await provider.provideCompletionItems(input);
|
const result = await provider.provideCompletionItems(input);
|
||||||
@@ -174,10 +172,7 @@ describe('Language completion provider', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('returns facetted label suggestions for multipule selectors', async () => {
|
it('returns facetted label suggestions for multipule selectors', async () => {
|
||||||
const datasource = makeMockLokiDatasource(
|
const datasource = setup({ label1: [], label2: [] }, { '{baz="42",foo="bar"}': [{ label2: 'label_val2' }] });
|
||||||
{ label1: [], label2: [] },
|
|
||||||
{ '{baz="42",foo="bar"}': [{ label2: 'label_val2' }] }
|
|
||||||
);
|
|
||||||
const provider = await getLanguageProvider(datasource);
|
const provider = await getLanguageProvider(datasource);
|
||||||
const input = createTypeaheadInput('{baz="42",foo="bar",}', '', '', 20);
|
const input = createTypeaheadInput('{baz="42",foo="bar",}', '', '', 20);
|
||||||
const result = await provider.provideCompletionItems(input);
|
const result = await provider.provideCompletionItems(input);
|
||||||
@@ -188,7 +183,7 @@ describe('Language completion provider', () => {
|
|||||||
|
|
||||||
describe('label suggestions', () => {
|
describe('label suggestions', () => {
|
||||||
it('returns label values suggestions from Loki', async () => {
|
it('returns label values suggestions from Loki', async () => {
|
||||||
const datasource = makeMockLokiDatasource({ label1: ['label1_val1', 'label1_val2'], label2: [] });
|
const datasource = setup({ label1: ['label1_val1', 'label1_val2'], label2: [] });
|
||||||
const provider = await getLanguageProvider(datasource);
|
const provider = await getLanguageProvider(datasource);
|
||||||
const input = createTypeaheadInput('{label1=}', '=', 'label1');
|
const input = createTypeaheadInput('{label1=}', '=', 'label1');
|
||||||
let result = await provider.provideCompletionItems(input);
|
let result = await provider.provideCompletionItems(input);
|
||||||
@@ -206,7 +201,7 @@ describe('Language completion provider', () => {
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
it('returns label values suggestions from Loki when re-editing', async () => {
|
it('returns label values suggestions from Loki when re-editing', async () => {
|
||||||
const datasource = makeMockLokiDatasource({ label1: ['label1_val1', 'label1_val2'], label2: [] });
|
const datasource = setup({ label1: ['label1_val1', 'label1_val2'], label2: [] });
|
||||||
const provider = await getLanguageProvider(datasource);
|
const provider = await getLanguageProvider(datasource);
|
||||||
const input = createTypeaheadInput('{label1="label1_v"}', 'label1_v', 'label1', 17, [
|
const input = createTypeaheadInput('{label1="label1_v"}', 'label1_v', 'label1', 17, [
|
||||||
'attr-value',
|
'attr-value',
|
||||||
@@ -228,7 +223,7 @@ describe('Language completion provider', () => {
|
|||||||
|
|
||||||
describe('label values', () => {
|
describe('label values', () => {
|
||||||
it('should fetch label values if not cached', async () => {
|
it('should fetch label values if not cached', async () => {
|
||||||
const datasource = makeMockLokiDatasource({ testkey: ['label1_val1', 'label1_val2'], label2: [] });
|
const datasource = setup({ testkey: ['label1_val1', 'label1_val2'], label2: [] });
|
||||||
const provider = await getLanguageProvider(datasource);
|
const provider = await getLanguageProvider(datasource);
|
||||||
const requestSpy = jest.spyOn(provider, 'request');
|
const requestSpy = jest.spyOn(provider, 'request');
|
||||||
const labelValues = await provider.fetchLabelValues('testkey');
|
const labelValues = await provider.fetchLabelValues('testkey');
|
||||||
@@ -237,7 +232,7 @@ describe('Language completion provider', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should return cached values', async () => {
|
it('should return cached values', async () => {
|
||||||
const datasource = makeMockLokiDatasource({ testkey: ['label1_val1', 'label1_val2'], label2: [] });
|
const datasource = setup({ testkey: ['label1_val1', 'label1_val2'], label2: [] });
|
||||||
const provider = await getLanguageProvider(datasource);
|
const provider = await getLanguageProvider(datasource);
|
||||||
const requestSpy = jest.spyOn(provider, 'request');
|
const requestSpy = jest.spyOn(provider, 'request');
|
||||||
const labelValues = await provider.fetchLabelValues('testkey');
|
const labelValues = await provider.fetchLabelValues('testkey');
|
||||||
@@ -250,7 +245,7 @@ describe('Language completion provider', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should encode special characters', async () => {
|
it('should encode special characters', async () => {
|
||||||
const datasource = makeMockLokiDatasource({ '`\\"testkey': ['label1_val1', 'label1_val2'], label2: [] });
|
const datasource = setup({ '`\\"testkey': ['label1_val1', 'label1_val2'], label2: [] });
|
||||||
const provider = await getLanguageProvider(datasource);
|
const provider = await getLanguageProvider(datasource);
|
||||||
const requestSpy = jest.spyOn(provider, 'request');
|
const requestSpy = jest.spyOn(provider, 'request');
|
||||||
await provider.fetchLabelValues('`\\"testkey');
|
await provider.fetchLabelValues('`\\"testkey');
|
||||||
@@ -262,9 +257,9 @@ describe('Language completion provider', () => {
|
|||||||
|
|
||||||
describe('Request URL', () => {
|
describe('Request URL', () => {
|
||||||
it('should contain range params', async () => {
|
it('should contain range params', async () => {
|
||||||
const datasourceWithLabels = makeMockLokiDatasource({ other: [] });
|
const datasourceWithLabels = setup({ other: [] });
|
||||||
const rangeParams = datasourceWithLabels.getTimeRangeParams();
|
const rangeParams = datasourceWithLabels.getTimeRangeParams();
|
||||||
const datasourceSpy = jest.spyOn(datasourceWithLabels as any, 'metadataRequest');
|
const datasourceSpy = jest.spyOn(datasourceWithLabels, 'metadataRequest');
|
||||||
|
|
||||||
const instance = new LanguageProvider(datasourceWithLabels);
|
const instance = new LanguageProvider(datasourceWithLabels);
|
||||||
instance.fetchLabels();
|
instance.fetchLabels();
|
||||||
@@ -274,7 +269,7 @@ describe('Request URL', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('Query imports', () => {
|
describe('Query imports', () => {
|
||||||
const datasource = makeMockLokiDatasource({});
|
const datasource = setup({});
|
||||||
|
|
||||||
it('returns empty queries', async () => {
|
it('returns empty queries', async () => {
|
||||||
const instance = new LanguageProvider(datasource);
|
const instance = new LanguageProvider(datasource);
|
||||||
@@ -334,3 +329,21 @@ function createTypeaheadInput(
|
|||||||
labelKey,
|
labelKey,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setup(
|
||||||
|
labelsAndValues: Record<string, string[]>,
|
||||||
|
series?: Record<string, Array<Record<string, string>>>
|
||||||
|
): LokiDatasource {
|
||||||
|
const datasource = createLokiDatasource({} as unknown as TemplateSrv);
|
||||||
|
|
||||||
|
const rangeMock = {
|
||||||
|
start: 1560153109000,
|
||||||
|
end: 1560163909000,
|
||||||
|
};
|
||||||
|
|
||||||
|
jest.spyOn(datasource, 'getTimeRangeParams').mockReturnValue(rangeMock);
|
||||||
|
jest.spyOn(datasource, 'metadataRequest').mockImplementation(createMetadataRequest(labelsAndValues, series));
|
||||||
|
jest.spyOn(datasource, 'interpolateString').mockImplementation((string: string) => string);
|
||||||
|
|
||||||
|
return datasource;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,37 +1,84 @@
|
|||||||
import { DataSourceSettings } from '@grafana/data';
|
import { DataSourceInstanceSettings, DataSourceSettings, PluginType, toUtc } from '@grafana/data';
|
||||||
|
import { TemplateSrv } from '@grafana/runtime';
|
||||||
|
|
||||||
import { getMockDataSource } from '../../../features/datasources/__mocks__';
|
import { getMockDataSource } from '../../../features/datasources/__mocks__';
|
||||||
|
|
||||||
import { LokiDatasource } from './datasource';
|
import { LokiDatasource } from './datasource';
|
||||||
import { LokiOptions } from './types';
|
import { LokiOptions } from './types';
|
||||||
|
|
||||||
interface Labels {
|
export function createDefaultConfigOptions(): DataSourceSettings<LokiOptions> {
|
||||||
[label: string]: string[];
|
return getMockDataSource<LokiOptions>({
|
||||||
|
jsonData: { maxLines: '531' },
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Series {
|
const rawRange = {
|
||||||
[label: string]: string;
|
from: toUtc('2018-04-25 10:00'),
|
||||||
|
to: toUtc('2018-04-25 11:00'),
|
||||||
|
};
|
||||||
|
|
||||||
|
const defaultTimeSrvMock = {
|
||||||
|
timeRange: () => ({
|
||||||
|
from: rawRange.from,
|
||||||
|
to: rawRange.to,
|
||||||
|
raw: rawRange,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
export function createLokiDatasource(
|
||||||
|
templateSrvMock: TemplateSrv,
|
||||||
|
settings: Partial<DataSourceInstanceSettings<LokiOptions>> = {},
|
||||||
|
timeSrvStub = defaultTimeSrvMock
|
||||||
|
): LokiDatasource {
|
||||||
|
const customSettings: DataSourceInstanceSettings<LokiOptions> = {
|
||||||
|
url: 'myloggingurl',
|
||||||
|
id: 0,
|
||||||
|
uid: '',
|
||||||
|
type: '',
|
||||||
|
name: '',
|
||||||
|
meta: {
|
||||||
|
id: 'id',
|
||||||
|
name: 'name',
|
||||||
|
type: PluginType.datasource,
|
||||||
|
module: '',
|
||||||
|
baseUrl: '',
|
||||||
|
info: {
|
||||||
|
author: {
|
||||||
|
name: 'Test',
|
||||||
|
},
|
||||||
|
description: '',
|
||||||
|
links: [],
|
||||||
|
logos: {
|
||||||
|
large: '',
|
||||||
|
small: '',
|
||||||
|
},
|
||||||
|
screenshots: [],
|
||||||
|
updated: '',
|
||||||
|
version: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
jsonData: {
|
||||||
|
maxLines: '20',
|
||||||
|
},
|
||||||
|
access: 'direct',
|
||||||
|
...settings,
|
||||||
|
};
|
||||||
|
|
||||||
|
// @ts-expect-error
|
||||||
|
return new LokiDatasource(customSettings, templateSrvMock, timeSrvStub);
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SeriesForSelector {
|
export function createMetadataRequest(
|
||||||
[selector: string]: Series[];
|
labelsAndValues: Record<string, string[]>,
|
||||||
}
|
series?: Record<string, Array<Record<string, string>>>
|
||||||
|
) {
|
||||||
export function makeMockLokiDatasource(labelsAndValues: Labels, series?: SeriesForSelector): LokiDatasource {
|
|
||||||
// added % to allow urlencoded labelKeys. Note, that this is not confirm with Loki, as loki does not allow specialcharacters in labelKeys, but needed for tests.
|
// added % to allow urlencoded labelKeys. Note, that this is not confirm with Loki, as loki does not allow specialcharacters in labelKeys, but needed for tests.
|
||||||
const lokiLabelsAndValuesEndpointRegex = /^label\/([%\w]*)\/values/;
|
const lokiLabelsAndValuesEndpointRegex = /^label\/([%\w]*)\/values/;
|
||||||
const lokiSeriesEndpointRegex = /^series/;
|
const lokiSeriesEndpointRegex = /^series/;
|
||||||
|
|
||||||
const lokiLabelsEndpoint = 'labels';
|
const lokiLabelsEndpoint = 'labels';
|
||||||
const rangeMock = {
|
|
||||||
start: 1560153109000,
|
|
||||||
end: 1560163909000,
|
|
||||||
};
|
|
||||||
|
|
||||||
const labels = Object.keys(labelsAndValues);
|
const labels = Object.keys(labelsAndValues);
|
||||||
return {
|
|
||||||
getTimeRangeParams: () => rangeMock,
|
return async function metadataRequestMock(url: string, params?: Record<string, string | number>) {
|
||||||
metadataRequest: (url: string, params?: { [key: string]: string }) => {
|
|
||||||
if (url === lokiLabelsEndpoint) {
|
if (url === lokiLabelsEndpoint) {
|
||||||
return labels;
|
return labels;
|
||||||
} else {
|
} else {
|
||||||
@@ -45,13 +92,5 @@ export function makeMockLokiDatasource(labelsAndValues: Labels, series?: SeriesF
|
|||||||
throw new Error(`Unexpected url error, ${url}`);
|
throw new Error(`Unexpected url error, ${url}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
};
|
||||||
interpolateString: (string: string) => string,
|
|
||||||
} as any;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function createDefaultConfigOptions(): DataSourceSettings<LokiOptions> {
|
|
||||||
return getMockDataSource<LokiOptions>({
|
|
||||||
jsonData: { maxLines: '531' },
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user