Chore: InfluxDB unit testing overhaul (#86586)
* move mocks into the __mocks__ folder * refactor datasource.test.ts * refactor datasource_backend_mode.test.ts * add dbName tests * prettier * betterer
This commit is contained in:
@@ -5154,12 +5154,6 @@ exports[`better eslint`] = {
|
||||
"public/app/plugins/datasource/influxdb/migrations.ts:5381": [
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
||||
],
|
||||
"public/app/plugins/datasource/influxdb/mocks.ts:5381": [
|
||||
[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.", "2"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "3"]
|
||||
],
|
||||
"public/app/plugins/datasource/influxdb/query_part.ts:5381": [
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "1"],
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
import { of } from 'rxjs';
|
||||
|
||||
import { AdHocVariableFilter, DataSourceInstanceSettings, PluginType, ScopedVars } from '@grafana/data';
|
||||
import { FetchResponse, getBackendSrv, setBackendSrv, VariableInterpolation } from '@grafana/runtime';
|
||||
|
||||
import { TemplateSrv } from '../../../../features/templating/template_srv';
|
||||
import InfluxDatasource from '../datasource';
|
||||
import { InfluxOptions, InfluxVersion } from '../types';
|
||||
|
||||
const getAdhocFiltersMock = jest.fn().mockImplementation(() => []);
|
||||
const replaceMock = jest.fn().mockImplementation((a: string, ...rest: unknown[]) => a);
|
||||
|
||||
export const templateSrvStub = {
|
||||
getAdhocFilters: getAdhocFiltersMock,
|
||||
replace: replaceMock,
|
||||
} as unknown as TemplateSrv;
|
||||
|
||||
export function mockTemplateSrv(
|
||||
getAdhocFiltersMock: (datasourceName: string) => AdHocVariableFilter[],
|
||||
replaceMock: (
|
||||
target?: string,
|
||||
scopedVars?: ScopedVars,
|
||||
format?: string | Function | undefined,
|
||||
interpolations?: VariableInterpolation[]
|
||||
) => string
|
||||
): TemplateSrv {
|
||||
return {
|
||||
getAdhocFilters: getAdhocFiltersMock,
|
||||
replace: replaceMock,
|
||||
} as unknown as TemplateSrv;
|
||||
}
|
||||
|
||||
export function mockBackendService(response: FetchResponse) {
|
||||
const fetchMock = jest.fn().mockReturnValue(of(response));
|
||||
const origBackendSrv = getBackendSrv();
|
||||
setBackendSrv({
|
||||
...origBackendSrv,
|
||||
fetch: fetchMock,
|
||||
});
|
||||
return fetchMock;
|
||||
}
|
||||
|
||||
export function getMockInfluxDS(
|
||||
instanceSettings: DataSourceInstanceSettings<InfluxOptions> = getMockDSInstanceSettings(),
|
||||
templateSrv: TemplateSrv = templateSrvStub
|
||||
): InfluxDatasource {
|
||||
return new InfluxDatasource(instanceSettings, templateSrv);
|
||||
}
|
||||
|
||||
export function getMockDSInstanceSettings(
|
||||
overrideJsonData?: Partial<InfluxOptions>
|
||||
): DataSourceInstanceSettings<InfluxOptions> {
|
||||
return {
|
||||
id: 123,
|
||||
url: 'proxied',
|
||||
access: 'proxy',
|
||||
name: 'influxDb',
|
||||
readOnly: false,
|
||||
uid: 'influxdb-test',
|
||||
type: 'influxdb',
|
||||
meta: {
|
||||
id: 'influxdb-meta',
|
||||
type: PluginType.datasource,
|
||||
name: 'influxdb-test',
|
||||
info: {
|
||||
author: {
|
||||
name: 'observability-metrics',
|
||||
},
|
||||
version: 'v0.0.1',
|
||||
description: 'test',
|
||||
links: [],
|
||||
logos: {
|
||||
large: '',
|
||||
small: '',
|
||||
},
|
||||
updated: '',
|
||||
screenshots: [],
|
||||
},
|
||||
module: '',
|
||||
baseUrl: '',
|
||||
},
|
||||
jsonData: {
|
||||
version: InfluxVersion.InfluxQL,
|
||||
httpMode: 'POST',
|
||||
dbName: 'site',
|
||||
...(overrideJsonData ? overrideJsonData : {}),
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import { DataQueryRequest, dateTime } from '@grafana/data';
|
||||
|
||||
import { InfluxQuery } from '../types';
|
||||
|
||||
const now = dateTime('2023-09-16T21:26:00Z');
|
||||
|
||||
export const queryOptions: DataQueryRequest<InfluxQuery> = {
|
||||
app: 'dashboard',
|
||||
interval: '10',
|
||||
intervalMs: 10,
|
||||
requestId: 'A-testing',
|
||||
startTime: 0,
|
||||
range: {
|
||||
from: dateTime(now).subtract(15, 'minutes'),
|
||||
to: now,
|
||||
raw: {
|
||||
from: 'now-15m',
|
||||
to: 'now',
|
||||
},
|
||||
},
|
||||
rangeRaw: {
|
||||
from: 'now-15m',
|
||||
to: 'now',
|
||||
},
|
||||
targets: [],
|
||||
timezone: 'UTC',
|
||||
scopedVars: {
|
||||
interval: { text: '1m', value: '1m' },
|
||||
__interval: { text: '1m', value: '1m' },
|
||||
__interval_ms: { text: 60000, value: 60000 },
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,99 @@
|
||||
import { AdHocVariableFilter, DataQueryRequest, dateTime } from '@grafana/data';
|
||||
import { SQLQuery } from '@grafana/sql';
|
||||
|
||||
import { InfluxQuery } from '../types';
|
||||
|
||||
type QueryType = InfluxQuery & SQLQuery;
|
||||
|
||||
export const mockInfluxQueryRequest = (targets?: QueryType[]): DataQueryRequest<QueryType> => {
|
||||
return {
|
||||
app: 'explore',
|
||||
interval: '1m',
|
||||
intervalMs: 60000,
|
||||
range: {
|
||||
from: dateTime(0),
|
||||
to: dateTime(10),
|
||||
raw: { from: dateTime(0), to: dateTime(10) },
|
||||
},
|
||||
rangeRaw: {
|
||||
from: dateTime(0),
|
||||
to: dateTime(10),
|
||||
},
|
||||
requestId: '',
|
||||
scopedVars: {},
|
||||
startTime: 0,
|
||||
targets: targets ?? mockTargets(),
|
||||
timezone: '',
|
||||
};
|
||||
};
|
||||
|
||||
export const mockTargets = (): QueryType[] => {
|
||||
return [
|
||||
{
|
||||
refId: 'A',
|
||||
datasource: {
|
||||
type: 'influxdb',
|
||||
uid: 'vA4bkHenk',
|
||||
},
|
||||
policy: 'default',
|
||||
resultFormat: 'time_series',
|
||||
orderByTime: 'ASC',
|
||||
tags: [],
|
||||
groupBy: [
|
||||
{
|
||||
type: 'time',
|
||||
params: ['$__interval'],
|
||||
},
|
||||
{
|
||||
type: 'fill',
|
||||
params: ['null'],
|
||||
},
|
||||
],
|
||||
select: [
|
||||
[
|
||||
{
|
||||
type: 'field',
|
||||
params: ['value'],
|
||||
},
|
||||
{
|
||||
type: 'mean',
|
||||
params: [],
|
||||
},
|
||||
],
|
||||
],
|
||||
measurement: 'cpu',
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
export const mockInfluxQueryWithTemplateVars = (adhocFilters: AdHocVariableFilter[]): InfluxQuery => ({
|
||||
refId: 'x',
|
||||
alias: '$var1',
|
||||
measurement: '$var1',
|
||||
policy: '$var1',
|
||||
limit: '$var1',
|
||||
slimit: '$var1',
|
||||
tz: '$var1',
|
||||
tags: [
|
||||
{
|
||||
key: 'drive',
|
||||
operator: '=~',
|
||||
value: '/^$path$/',
|
||||
},
|
||||
],
|
||||
groupBy: [
|
||||
{
|
||||
params: ['$var1'],
|
||||
type: 'tag',
|
||||
},
|
||||
],
|
||||
select: [
|
||||
[
|
||||
{
|
||||
params: ['$var1'],
|
||||
type: 'field',
|
||||
},
|
||||
],
|
||||
],
|
||||
adhocFilters,
|
||||
});
|
||||
+78
-200
@@ -1,108 +1,5 @@
|
||||
import { of } from 'rxjs';
|
||||
|
||||
import {
|
||||
AdHocVariableFilter,
|
||||
DataQueryRequest,
|
||||
DataSourceInstanceSettings,
|
||||
dateTime,
|
||||
FieldType,
|
||||
PluginType,
|
||||
ScopedVars,
|
||||
} from '@grafana/data';
|
||||
import {
|
||||
BackendDataSourceResponse,
|
||||
FetchResponse,
|
||||
getBackendSrv,
|
||||
setBackendSrv,
|
||||
VariableInterpolation,
|
||||
} from '@grafana/runtime';
|
||||
import { SQLQuery } from '@grafana/sql';
|
||||
|
||||
import { TemplateSrv } from '../../../features/templating/template_srv';
|
||||
|
||||
import InfluxDatasource from './datasource';
|
||||
import { InfluxOptions, InfluxQuery, InfluxVersion } from './types';
|
||||
|
||||
const getAdhocFiltersMock = jest.fn().mockImplementation(() => []);
|
||||
const replaceMock = jest.fn().mockImplementation((a: string, ...rest: unknown[]) => a);
|
||||
|
||||
export const templateSrvStub = {
|
||||
getAdhocFilters: getAdhocFiltersMock,
|
||||
replace: replaceMock,
|
||||
} as unknown as TemplateSrv;
|
||||
|
||||
export function mockTemplateSrv(
|
||||
getAdhocFiltersMock: (datasourceName: string) => AdHocVariableFilter[],
|
||||
replaceMock: (
|
||||
target?: string,
|
||||
scopedVars?: ScopedVars,
|
||||
format?: string | Function | undefined,
|
||||
interpolations?: VariableInterpolation[]
|
||||
) => string
|
||||
): TemplateSrv {
|
||||
return {
|
||||
getAdhocFilters: getAdhocFiltersMock,
|
||||
replace: replaceMock,
|
||||
} as unknown as TemplateSrv;
|
||||
}
|
||||
|
||||
export function mockBackendService(response: FetchResponse) {
|
||||
const fetchMock = jest.fn().mockReturnValue(of(response));
|
||||
const origBackendSrv = getBackendSrv();
|
||||
setBackendSrv({
|
||||
...origBackendSrv,
|
||||
fetch: fetchMock,
|
||||
});
|
||||
return fetchMock;
|
||||
}
|
||||
|
||||
export function getMockInfluxDS(
|
||||
instanceSettings: DataSourceInstanceSettings<InfluxOptions> = getMockDSInstanceSettings(),
|
||||
templateSrv: TemplateSrv = templateSrvStub
|
||||
): InfluxDatasource {
|
||||
return new InfluxDatasource(instanceSettings, templateSrv);
|
||||
}
|
||||
|
||||
export function getMockDSInstanceSettings(
|
||||
overrideJsonData?: Partial<InfluxOptions>
|
||||
): DataSourceInstanceSettings<InfluxOptions> {
|
||||
return {
|
||||
id: 123,
|
||||
url: 'proxied',
|
||||
access: 'proxy',
|
||||
name: 'influxDb',
|
||||
readOnly: false,
|
||||
uid: 'influxdb-test',
|
||||
type: 'influxdb',
|
||||
meta: {
|
||||
id: 'influxdb-meta',
|
||||
type: PluginType.datasource,
|
||||
name: 'influxdb-test',
|
||||
info: {
|
||||
author: {
|
||||
name: 'observability-metrics',
|
||||
},
|
||||
version: 'v0.0.1',
|
||||
description: 'test',
|
||||
links: [],
|
||||
logos: {
|
||||
large: '',
|
||||
small: '',
|
||||
},
|
||||
updated: '',
|
||||
screenshots: [],
|
||||
},
|
||||
module: '',
|
||||
baseUrl: '',
|
||||
},
|
||||
jsonData: {
|
||||
version: InfluxVersion.InfluxQL,
|
||||
httpMode: 'POST',
|
||||
dbName: 'site',
|
||||
...(overrideJsonData ? overrideJsonData : {}),
|
||||
},
|
||||
};
|
||||
}
|
||||
import { FieldType } from '@grafana/data';
|
||||
import { BackendDataSourceResponse, FetchResponse } from '@grafana/runtime';
|
||||
|
||||
export const mockInfluxFetchResponse = (
|
||||
overrides?: Partial<FetchResponse<BackendDataSourceResponse>>
|
||||
@@ -133,6 +30,7 @@ export const mockInfluxFetchResponse = (
|
||||
...overrides,
|
||||
};
|
||||
};
|
||||
|
||||
export const mockInfluxTSDBQueryResponse = [
|
||||
{
|
||||
schema: {
|
||||
@@ -220,6 +118,33 @@ export const mockInfluxTSDBQueryResponse = [
|
||||
},
|
||||
];
|
||||
|
||||
export const metricFindQueryResponse = {
|
||||
config: {
|
||||
url: 'mock-response-url',
|
||||
},
|
||||
headers: new Headers(),
|
||||
ok: false,
|
||||
redirected: false,
|
||||
status: 0,
|
||||
statusText: '',
|
||||
type: 'basic',
|
||||
url: '',
|
||||
data: {
|
||||
status: 'success',
|
||||
results: [
|
||||
{
|
||||
series: [
|
||||
{
|
||||
name: 'measurement',
|
||||
columns: ['name'],
|
||||
values: [['cpu']],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
export const mockInfluxRetentionPolicyResponse = [
|
||||
{
|
||||
schema: {
|
||||
@@ -230,101 +155,6 @@ export const mockInfluxRetentionPolicyResponse = [
|
||||
},
|
||||
];
|
||||
|
||||
type QueryType = InfluxQuery & SQLQuery;
|
||||
|
||||
export const mockInfluxQueryRequest = (targets?: QueryType[]): DataQueryRequest<QueryType> => {
|
||||
return {
|
||||
app: 'explore',
|
||||
interval: '1m',
|
||||
intervalMs: 60000,
|
||||
range: {
|
||||
from: dateTime(0),
|
||||
to: dateTime(10),
|
||||
raw: { from: dateTime(0), to: dateTime(10) },
|
||||
},
|
||||
rangeRaw: {
|
||||
from: dateTime(0),
|
||||
to: dateTime(10),
|
||||
},
|
||||
requestId: '',
|
||||
scopedVars: {},
|
||||
startTime: 0,
|
||||
targets: targets ?? mockTargets(),
|
||||
timezone: '',
|
||||
};
|
||||
};
|
||||
|
||||
export const mockTargets = (): QueryType[] => {
|
||||
return [
|
||||
{
|
||||
refId: 'A',
|
||||
datasource: {
|
||||
type: 'influxdb',
|
||||
uid: 'vA4bkHenk',
|
||||
},
|
||||
policy: 'default',
|
||||
resultFormat: 'time_series',
|
||||
orderByTime: 'ASC',
|
||||
tags: [],
|
||||
groupBy: [
|
||||
{
|
||||
type: 'time',
|
||||
params: ['$__interval'],
|
||||
},
|
||||
{
|
||||
type: 'fill',
|
||||
params: ['null'],
|
||||
},
|
||||
],
|
||||
select: [
|
||||
[
|
||||
{
|
||||
type: 'field',
|
||||
params: ['value'],
|
||||
},
|
||||
{
|
||||
type: 'mean',
|
||||
params: [],
|
||||
},
|
||||
],
|
||||
],
|
||||
measurement: 'cpu',
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
export const mockInfluxQueryWithTemplateVars = (adhocFilters: AdHocVariableFilter[]): InfluxQuery => ({
|
||||
refId: 'x',
|
||||
alias: '$interpolationVar',
|
||||
measurement: '$interpolationVar',
|
||||
policy: '$interpolationVar',
|
||||
limit: '$interpolationVar',
|
||||
slimit: '$interpolationVar',
|
||||
tz: '$interpolationVar',
|
||||
tags: [
|
||||
{
|
||||
key: 'cpu',
|
||||
operator: '=~',
|
||||
value: '/^$interpolationVar,$interpolationVar2$/',
|
||||
},
|
||||
],
|
||||
groupBy: [
|
||||
{
|
||||
params: ['$interpolationVar'],
|
||||
type: 'tag',
|
||||
},
|
||||
],
|
||||
select: [
|
||||
[
|
||||
{
|
||||
params: ['$interpolationVar'],
|
||||
type: 'field',
|
||||
},
|
||||
],
|
||||
],
|
||||
adhocFilters,
|
||||
});
|
||||
|
||||
export const mockInfluxSQLFetchResponse: FetchResponse<BackendDataSourceResponse> = {
|
||||
config: {
|
||||
url: 'mock-response-url',
|
||||
@@ -433,3 +263,51 @@ export const mockInfluxSQLVariableFetchResponse: FetchResponse<BackendDataSource
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const mockMetricFindQueryResponse = {
|
||||
data: {
|
||||
results: {
|
||||
metricFindQuery: {
|
||||
status: 200,
|
||||
frames: [
|
||||
{
|
||||
schema: {
|
||||
name: 'NoneNone',
|
||||
refId: 'metricFindQuery',
|
||||
fields: [
|
||||
{
|
||||
name: 'Value',
|
||||
type: 'string',
|
||||
typeInfo: {
|
||||
frame: 'string',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
data: {
|
||||
values: [['test-t2-1', 'test-t2-10']],
|
||||
},
|
||||
},
|
||||
{
|
||||
schema: {
|
||||
name: 'some-other',
|
||||
refId: 'metricFindQuery',
|
||||
fields: [
|
||||
{
|
||||
name: 'Value',
|
||||
type: 'string',
|
||||
typeInfo: {
|
||||
frame: 'string',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
data: {
|
||||
values: [['test-t2-1', 'test-t2-10', 'test-t2-2', 'test-t2-3', 'test-t2-4']],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
+1
-1
@@ -1,8 +1,8 @@
|
||||
import { render, waitFor } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
|
||||
import { getMockInfluxDS, getMockDSInstanceSettings } from '../../../../../__mocks__/datasource';
|
||||
import InfluxDatasource from '../../../../../datasource';
|
||||
import { getMockInfluxDS, getMockDSInstanceSettings } from '../../../../../mocks';
|
||||
import { DEFAULT_POLICY, InfluxQuery } from '../../../../../types';
|
||||
|
||||
import { VisualInfluxQLEditor } from './VisualInfluxQLEditor';
|
||||
|
||||
@@ -1,59 +1,63 @@
|
||||
import { lastValueFrom, of } from 'rxjs';
|
||||
|
||||
import { ScopedVars } from '@grafana/data';
|
||||
import { BackendSrvRequest } from '@grafana/runtime/';
|
||||
import { BackendSrvRequest } from '@grafana/runtime';
|
||||
import config from 'app/core/config';
|
||||
|
||||
import { TemplateSrv } from '../../../features/templating/template_srv';
|
||||
import { queryBuilder } from '../../../features/variables/shared/testing/builders';
|
||||
|
||||
import { getMockDSInstanceSettings, getMockInfluxDS, mockBackendService } from './__mocks__/datasource';
|
||||
import { queryOptions } from './__mocks__/query';
|
||||
import { mockInfluxQueryRequest, mockInfluxQueryWithTemplateVars } from './__mocks__/request';
|
||||
import { mockInfluxFetchResponse, mockMetricFindQueryResponse } from './__mocks__/response';
|
||||
import { BROWSER_MODE_DISABLED_MESSAGE } from './constants';
|
||||
import InfluxDatasource from './datasource';
|
||||
import {
|
||||
getMockDSInstanceSettings,
|
||||
getMockInfluxDS,
|
||||
mockBackendService,
|
||||
mockInfluxFetchResponse,
|
||||
mockInfluxQueryRequest,
|
||||
mockInfluxQueryWithTemplateVars,
|
||||
mockTemplateSrv,
|
||||
} from './mocks';
|
||||
import { InfluxQuery, InfluxVersion } from './types';
|
||||
|
||||
// we want only frontend mode in this file
|
||||
config.featureToggles.influxdbBackendMigration = false;
|
||||
const fetchMock = mockBackendService(mockInfluxFetchResponse());
|
||||
|
||||
describe('InfluxDataSource Frontend Mode', () => {
|
||||
describe('datasource initialization', () => {
|
||||
it('should read the http method from jsonData', () => {
|
||||
let ds = getMockInfluxDS(getMockDSInstanceSettings({ httpMode: 'GET' }));
|
||||
expect(ds.httpMode).toBe('GET');
|
||||
ds = getMockInfluxDS(getMockDSInstanceSettings({ httpMode: 'POST' }));
|
||||
expect(ds.httpMode).toBe('POST');
|
||||
});
|
||||
});
|
||||
|
||||
// Remove this suite when influxdbBackendMigration feature toggle removed
|
||||
describe('InfluxDataSource Frontend Mode [influxdbBackendMigration=false]', () => {
|
||||
beforeEach(() => {
|
||||
// we want only frontend mode in this suite
|
||||
config.featureToggles.influxdbBackendMigration = false;
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should throw an error if there is 200 response with error', async () => {
|
||||
const ds = getMockInfluxDS();
|
||||
fetchMock.mockImplementation(() => {
|
||||
return of({
|
||||
data: {
|
||||
results: [
|
||||
{
|
||||
error: 'Query timeout',
|
||||
},
|
||||
],
|
||||
},
|
||||
describe('general checks', () => {
|
||||
it('should throw an error if there is 200 response with error', async () => {
|
||||
const ds = getMockInfluxDS();
|
||||
fetchMock.mockImplementation(() => {
|
||||
return of({
|
||||
data: {
|
||||
results: [
|
||||
{
|
||||
error: 'Query timeout',
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
try {
|
||||
await lastValueFrom(ds.query(mockInfluxQueryRequest()));
|
||||
} catch (err) {
|
||||
if (err instanceof Error) {
|
||||
expect(err.message).toBe('InfluxDB Error: Query timeout');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
await lastValueFrom(ds.query(mockInfluxQueryRequest()));
|
||||
} catch (err) {
|
||||
if (err instanceof Error) {
|
||||
expect(err.message).toBe('InfluxDB Error: Query timeout');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
describe('outdated browser mode', () => {
|
||||
it('should throw an error when querying data', async () => {
|
||||
it('should throw an error when querying data when deprecated access mode', async () => {
|
||||
expect.assertions(1);
|
||||
const instanceSettings = getMockDSInstanceSettings();
|
||||
instanceSettings.access = 'direct';
|
||||
@@ -68,7 +72,7 @@ describe('InfluxDataSource Frontend Mode', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('metricFindQuery with HTTP GET', () => {
|
||||
describe('metricFindQuery', () => {
|
||||
let ds: InfluxDatasource;
|
||||
const query = 'SELECT max(value) FROM measurement WHERE $timeFilter';
|
||||
const queryOptions = {
|
||||
@@ -77,14 +81,7 @@ describe('InfluxDataSource Frontend Mode', () => {
|
||||
to: '2018-01-02T00:00:00Z',
|
||||
},
|
||||
};
|
||||
|
||||
let requestQuery: string;
|
||||
let requestMethod: string | undefined;
|
||||
let requestData: string | null;
|
||||
const fetchMockImpl = (req: BackendSrvRequest) => {
|
||||
requestMethod = req.method;
|
||||
requestQuery = req.params?.q;
|
||||
requestData = req.data;
|
||||
return of({
|
||||
data: {
|
||||
status: 'success',
|
||||
@@ -108,36 +105,29 @@ describe('InfluxDataSource Frontend Mode', () => {
|
||||
fetchMock.mockImplementation(fetchMockImpl);
|
||||
});
|
||||
|
||||
it('should read the http method from jsonData', async () => {
|
||||
ds = getMockInfluxDS(getMockDSInstanceSettings({ httpMode: 'GET' }));
|
||||
await ds.metricFindQuery(query, queryOptions);
|
||||
expect(requestMethod).toBe('GET');
|
||||
ds = getMockInfluxDS(getMockDSInstanceSettings({ httpMode: 'POST' }));
|
||||
await ds.metricFindQuery(query, queryOptions);
|
||||
expect(requestMethod).toBe('POST');
|
||||
});
|
||||
|
||||
it('should replace $timefilter', async () => {
|
||||
ds = getMockInfluxDS(getMockDSInstanceSettings({ httpMode: 'GET' }));
|
||||
await ds.metricFindQuery(query, queryOptions);
|
||||
expect(requestQuery).toMatch('time >= 1514764800000ms and time <= 1514851200000ms');
|
||||
expect(fetchMock.mock.lastCall[0].params?.q).toMatch('time >= 1514764800000ms and time <= 1514851200000ms');
|
||||
ds = getMockInfluxDS(getMockDSInstanceSettings({ httpMode: 'POST' }));
|
||||
await ds.metricFindQuery(query, queryOptions);
|
||||
expect(requestQuery).toBeFalsy();
|
||||
expect(requestData).toMatch('time%20%3E%3D%201514764800000ms%20and%20time%20%3C%3D%201514851200000ms');
|
||||
expect(fetchMock.mock.lastCall[0].params?.q).toBeFalsy();
|
||||
expect(fetchMock.mock.lastCall[0].data).toMatch(
|
||||
'time%20%3E%3D%201514764800000ms%20and%20time%20%3C%3D%201514851200000ms'
|
||||
);
|
||||
});
|
||||
|
||||
it('should not have any data in request body if http mode is GET', async () => {
|
||||
ds = getMockInfluxDS(getMockDSInstanceSettings({ httpMode: 'GET' }));
|
||||
await ds.metricFindQuery(query, queryOptions);
|
||||
expect(requestData).toBeNull();
|
||||
expect(fetchMock.mock.lastCall[0].data).toBeNull();
|
||||
});
|
||||
|
||||
it('should have data in request body if http mode is POST', async () => {
|
||||
ds = getMockInfluxDS(getMockDSInstanceSettings({ httpMode: 'POST' }));
|
||||
await ds.metricFindQuery(query, queryOptions);
|
||||
expect(requestData).not.toBeNull();
|
||||
expect(requestData).toMatch('q=SELECT');
|
||||
expect(fetchMock.mock.lastCall[0].data).not.toBeNull();
|
||||
expect(fetchMock.mock.lastCall[0].data).toMatch('q=SELECT');
|
||||
});
|
||||
|
||||
it('parse response correctly', async () => {
|
||||
@@ -150,6 +140,7 @@ describe('InfluxDataSource Frontend Mode', () => {
|
||||
});
|
||||
});
|
||||
|
||||
// Update this after starting to use TemplateSrv from @grafana/runtime package
|
||||
describe('adhoc variables', () => {
|
||||
const adhocFilters = [
|
||||
{
|
||||
@@ -163,8 +154,6 @@ describe('InfluxDataSource Frontend Mode', () => {
|
||||
mockTemplateService.getAdhocFilters = jest.fn((_: string) => adhocFilters);
|
||||
let ds = getMockInfluxDS(getMockDSInstanceSettings(), mockTemplateService);
|
||||
|
||||
// const fetchMock = jest.fn().mockReturnValue(fetchResult);
|
||||
|
||||
it('query should contain the ad-hoc variable', () => {
|
||||
ds.query(mockInfluxQueryRequest());
|
||||
const expected = encodeURIComponent(
|
||||
@@ -252,105 +241,75 @@ describe('InfluxDataSource Frontend Mode', () => {
|
||||
ds.getTagValues({ key: 'test', filters: [] });
|
||||
expect(metricFindQueryMock).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should use dbName instead of database', () => {
|
||||
const instanceSettings = getMockDSInstanceSettings();
|
||||
instanceSettings.database = 'should_not_be_used';
|
||||
ds = getMockInfluxDS(instanceSettings);
|
||||
expect(ds.database).toBe('site');
|
||||
});
|
||||
|
||||
it('should fallback to use use database is dbName is not exist', () => {
|
||||
const instanceSettings = getMockDSInstanceSettings();
|
||||
instanceSettings.database = 'fallback';
|
||||
instanceSettings.jsonData.dbName = undefined;
|
||||
ds = getMockInfluxDS(instanceSettings);
|
||||
expect(ds.database).toBe('fallback');
|
||||
});
|
||||
});
|
||||
|
||||
describe('variable interpolation', () => {
|
||||
const text = 'interpolationText';
|
||||
const text2 = 'interpolationText2';
|
||||
const textWithoutFormatRegex = 'interpolationText,interpolationText2';
|
||||
const textWithFormatRegex = 'interpolationText,interpolationText2';
|
||||
const justText = 'interpolationText';
|
||||
const variableMap: Record<string, string> = {
|
||||
$interpolationVar: text,
|
||||
$interpolationVar2: text2,
|
||||
};
|
||||
const adhocFilters = [
|
||||
{
|
||||
key: 'adhoc',
|
||||
operator: '=',
|
||||
value: 'val',
|
||||
condition: '',
|
||||
},
|
||||
const variablesMock = [
|
||||
queryBuilder().withId('var1').withName('var1').withCurrent('var1_value').build(),
|
||||
queryBuilder().withId('path').withName('path').withCurrent('/etc/hosts').build(),
|
||||
];
|
||||
const templateSrv = mockTemplateSrv(
|
||||
jest.fn((_: string) => adhocFilters),
|
||||
jest.fn((target?: string, scopedVars?: ScopedVars, format?: string | Function): string => {
|
||||
if (!format) {
|
||||
return variableMap[target!] || '';
|
||||
}
|
||||
if (format === 'regex') {
|
||||
return textWithFormatRegex;
|
||||
}
|
||||
return textWithoutFormatRegex;
|
||||
})
|
||||
);
|
||||
const ds = new InfluxDatasource(getMockDSInstanceSettings(), templateSrv);
|
||||
|
||||
function influxChecks(query: InfluxQuery) {
|
||||
expect(templateSrv.replace).toBeCalledTimes(12);
|
||||
expect(query.alias).toBe(text);
|
||||
expect(query.measurement).toBe(textWithFormatRegex);
|
||||
expect(query.policy).toBe(justText);
|
||||
expect(query.limit).toBe(justText);
|
||||
expect(query.slimit).toBe(justText);
|
||||
expect(query.tz).toBe(text);
|
||||
expect(query.tags![0].value).toBe(textWithFormatRegex);
|
||||
expect(query.groupBy![0].params![0]).toBe(justText);
|
||||
expect(query.select![0][0].params![0]).toBe(justText);
|
||||
expect(query.adhocFilters?.[0].key).toBe(adhocFilters[0].key);
|
||||
}
|
||||
const mockTemplateService = new TemplateSrv({
|
||||
getVariables: () => variablesMock,
|
||||
getVariableWithName: (name: string) => variablesMock.filter((v) => v.name === name)[0],
|
||||
getFilteredVariables: jest.fn(),
|
||||
});
|
||||
// Remove this after start using TemplateSrv from @grafana/runtime
|
||||
mockTemplateService.getAdhocFilters = jest.fn();
|
||||
|
||||
describe('when interpolating query variables for dashboard->explore', () => {
|
||||
it('should interpolate all variables with Flux mode', () => {
|
||||
ds.version = InfluxVersion.Flux;
|
||||
const ds = getMockInfluxDS(getMockDSInstanceSettings({ version: InfluxVersion.Flux }), mockTemplateService);
|
||||
const fluxQuery = {
|
||||
refId: 'x',
|
||||
query: '$interpolationVar,$interpolationVar2',
|
||||
query: 'some query with $var1 and $path',
|
||||
};
|
||||
const queries = ds.interpolateVariablesInQueries([fluxQuery], {
|
||||
interpolationVar: { text: text, value: text },
|
||||
interpolationVar2: { text: text2, value: text2 },
|
||||
});
|
||||
expect(templateSrv.replace).toBeCalledTimes(1);
|
||||
expect(queries[0].query).toBe(textWithFormatRegex);
|
||||
const queries = ds.interpolateVariablesInQueries([fluxQuery], {});
|
||||
expect(queries[0].query).toBe('some query with var1_value and /etc/hosts');
|
||||
});
|
||||
|
||||
it('should interpolate all variables with InfluxQL mode', () => {
|
||||
ds.version = InfluxVersion.InfluxQL;
|
||||
const queries = ds.interpolateVariablesInQueries([mockInfluxQueryWithTemplateVars(adhocFilters)], {
|
||||
interpolationVar: { text: text, value: text },
|
||||
interpolationVar2: { text: text2, value: text2 },
|
||||
});
|
||||
influxChecks(queries[0]);
|
||||
const ds = getMockInfluxDS(getMockDSInstanceSettings({ version: InfluxVersion.InfluxQL }), mockTemplateService);
|
||||
const [query] = ds.interpolateVariablesInQueries([mockInfluxQueryWithTemplateVars([])], {});
|
||||
expect(query.alias).toBe('var1_value');
|
||||
expect(query.measurement).toBe('var1_value');
|
||||
expect(query.policy).toBe('var1_value');
|
||||
expect(query.limit).toBe('var1_value');
|
||||
expect(query.slimit).toBe('var1_value');
|
||||
expect(query.tz).toBe('var1_value');
|
||||
expect(query.tags![0].value).toBe(`/^\\/etc\\/hosts$/`);
|
||||
expect(query.groupBy![0].params![0]).toBe('var1_value');
|
||||
expect(query.select![0][0].params![0]).toBe('var1_value');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when interpolating template variables', () => {
|
||||
describe('applyTemplateVariables', () => {
|
||||
it('should apply all template variables with Flux mode', () => {
|
||||
ds.version = InfluxVersion.Flux;
|
||||
const ds = getMockInfluxDS(getMockDSInstanceSettings({ version: InfluxVersion.Flux }), mockTemplateService);
|
||||
const fluxQuery = {
|
||||
refId: 'x',
|
||||
query: '$interpolationVar',
|
||||
query: '$var1',
|
||||
};
|
||||
const query = ds.applyTemplateVariables(fluxQuery, {
|
||||
interpolationVar: {
|
||||
text: text,
|
||||
value: text,
|
||||
},
|
||||
});
|
||||
expect(templateSrv.replace).toBeCalledTimes(1);
|
||||
expect(query.query).toBe(text);
|
||||
const query = ds.applyTemplateVariables(fluxQuery, {});
|
||||
expect(query.query).toBe('var1_value');
|
||||
});
|
||||
});
|
||||
|
||||
describe('variable interpolation with chained variables with frontend mode', () => {
|
||||
const variablesMock = [queryBuilder().withId('var1').withName('var1').withCurrent('var1').build()];
|
||||
const mockTemplateService = new TemplateSrv({
|
||||
getVariables: () => variablesMock,
|
||||
getVariableWithName: (name: string) => variablesMock.filter((v) => v.name === name)[0],
|
||||
getFilteredVariables: jest.fn(),
|
||||
});
|
||||
mockTemplateService.getAdhocFilters = jest.fn((_: string) => []);
|
||||
let ds = getMockInfluxDS(getMockDSInstanceSettings(), mockTemplateService);
|
||||
const fetchMockImpl = () =>
|
||||
of({
|
||||
@@ -416,114 +375,298 @@ describe('InfluxDataSource Frontend Mode', () => {
|
||||
expect(qData).toBe(qe);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('interpolateQueryExpr', () => {
|
||||
let ds = getMockInfluxDS(getMockDSInstanceSettings(), new TemplateSrv());
|
||||
it('should return the value as it is', () => {
|
||||
const value = 'normalValue';
|
||||
const variableMock = queryBuilder().withId('tempVar').withName('tempVar').withMulti(false).build();
|
||||
const result = ds.interpolateQueryExpr(value, variableMock, 'my query $tempVar');
|
||||
const expectation = 'normalValue';
|
||||
expect(result).toBe(expectation);
|
||||
});
|
||||
describe('InfluxDataSource Backend Mode [influxdbBackendMigration=true]', () => {
|
||||
beforeEach(() => {
|
||||
// we want only backend mode in this suite
|
||||
config.featureToggles.influxdbBackendMigration = true;
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should return the escaped value if the value wrapped in regex', () => {
|
||||
const value = '/special/path';
|
||||
const variableMock = queryBuilder().withId('tempVar').withName('tempVar').withMulti(false).build();
|
||||
const result = ds.interpolateQueryExpr(value, variableMock, 'select that where path = /$tempVar/');
|
||||
const expectation = `\\/special\\/path`;
|
||||
expect(result).toBe(expectation);
|
||||
});
|
||||
describe('metric find query', () => {
|
||||
let ds = getMockInfluxDS(getMockDSInstanceSettings());
|
||||
it('handles multiple frames', async () => {
|
||||
const fetchMockImpl = () => {
|
||||
return of(mockMetricFindQueryResponse);
|
||||
};
|
||||
|
||||
it('should return the escaped value if the value wrapped in regex 2', () => {
|
||||
const value = '/special/path';
|
||||
const variableMock = queryBuilder().withId('tempVar').withName('tempVar').withMulti(false).build();
|
||||
const result = ds.interpolateQueryExpr(value, variableMock, 'select that where path = /^$tempVar$/');
|
||||
const expectation = `\\/special\\/path`;
|
||||
expect(result).toBe(expectation);
|
||||
});
|
||||
fetchMock.mockImplementation(fetchMockImpl);
|
||||
const values = await ds.getTagValues({ key: 'test_id', filters: [] });
|
||||
expect(fetchMock).toHaveBeenCalled();
|
||||
expect(values.length).toBe(5);
|
||||
expect(values[0].text).toBe('test-t2-1');
|
||||
});
|
||||
});
|
||||
|
||||
it('should return the escaped value if the value wrapped in regex 3', () => {
|
||||
const value = ['env', 'env2', 'env3'];
|
||||
const variableMock = queryBuilder()
|
||||
.withId('tempVar')
|
||||
.withName('tempVar')
|
||||
.withMulti(false)
|
||||
.withIncludeAll(true)
|
||||
.build();
|
||||
const result = ds.interpolateQueryExpr(value, variableMock, 'select from /^($tempVar)$/');
|
||||
const expectation = `(env|env2|env3)`;
|
||||
expect(result).toBe(expectation);
|
||||
});
|
||||
|
||||
it('should **not** return the escaped value if the value **is not** wrapped in regex', () => {
|
||||
const value = '/special/path';
|
||||
const variableMock = queryBuilder().withId('tempVar').withName('tempVar').withMulti(false).build();
|
||||
const result = ds.interpolateQueryExpr(value, variableMock, `select that where path = '$tempVar'`);
|
||||
const expectation = `/special/path`;
|
||||
expect(result).toBe(expectation);
|
||||
});
|
||||
|
||||
it('should **not** return the escaped value if the value **is not** wrapped in regex 2', () => {
|
||||
const value = '12.2';
|
||||
const variableMock = queryBuilder().withId('tempVar').withName('tempVar').withMulti(false).build();
|
||||
const result = ds.interpolateQueryExpr(value, variableMock, `select that where path = '$tempVar'`);
|
||||
const expectation = `12.2`;
|
||||
expect(result).toBe(expectation);
|
||||
});
|
||||
|
||||
it('should escape the value **always** if the variable is a multi-value variable', () => {
|
||||
const value = [`/special/path`, `/some/other/path`];
|
||||
const variableMock = queryBuilder().withId('tempVar').withName('tempVar').withMulti().build();
|
||||
const result = ds.interpolateQueryExpr(value, variableMock, `select that where path = '$tempVar'`);
|
||||
const expectation = `(\\/special\\/path|\\/some\\/other\\/path)`;
|
||||
expect(result).toBe(expectation);
|
||||
});
|
||||
|
||||
it('should escape and join with the pipe even the variable is not multi-value', () => {
|
||||
const variableMock = queryBuilder()
|
||||
.withId('tempVar')
|
||||
.withName('tempVar')
|
||||
.withCurrent('All', '$__all')
|
||||
.withMulti(false)
|
||||
.withAllValue('')
|
||||
.withIncludeAll()
|
||||
.withOptions(
|
||||
describe('variable interpolation with chained variables with backend mode', () => {
|
||||
const variablesMock = [
|
||||
queryBuilder().withId('var1').withName('var1').withCurrent('var1').build(),
|
||||
queryBuilder().withId('path').withName('path').withCurrent('/etc/hosts').build(),
|
||||
queryBuilder()
|
||||
.withId('field_var')
|
||||
.withName('field_var')
|
||||
.withMulti(true)
|
||||
.withOptions(
|
||||
{
|
||||
text: `field_1`,
|
||||
value: `field_1`,
|
||||
},
|
||||
{
|
||||
text: `field_2`,
|
||||
value: `field_2`,
|
||||
},
|
||||
{
|
||||
text: `field_3`,
|
||||
value: `field_3`,
|
||||
}
|
||||
)
|
||||
.withCurrent(['field_1', 'field_3'])
|
||||
.build(),
|
||||
];
|
||||
const mockTemplateService = new TemplateSrv({
|
||||
getVariables: () => variablesMock,
|
||||
getVariableWithName: (name: string) => variablesMock.filter((v) => v.name === name)[0],
|
||||
getFilteredVariables: jest.fn(),
|
||||
});
|
||||
mockTemplateService.getAdhocFilters = jest.fn((_: string) => []);
|
||||
let ds = getMockInfluxDS(getMockDSInstanceSettings(), mockTemplateService);
|
||||
const fetchMockImpl = () =>
|
||||
of({
|
||||
data: {
|
||||
status: 'success',
|
||||
results: [
|
||||
{
|
||||
text: 'All',
|
||||
value: '$__all',
|
||||
series: [
|
||||
{
|
||||
name: 'measurement',
|
||||
columns: ['name'],
|
||||
values: [['cpu']],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
fetchMock.mockImplementation(fetchMockImpl);
|
||||
});
|
||||
|
||||
it('should render chained regex variables with floating point number', () => {
|
||||
ds.metricFindQuery(`SELECT sum("piece_count") FROM "rp"."pdata" WHERE diameter <= $maxSED`, {
|
||||
...queryOptions,
|
||||
scopedVars: { maxSED: { text: '8.1', value: '8.1' } },
|
||||
});
|
||||
const qe = `SELECT sum("piece_count") FROM "rp"."pdata" WHERE diameter <= 8.1`;
|
||||
const qData = fetchMock.mock.calls[0][0].data.queries[0].query;
|
||||
expect(qData).toBe(qe);
|
||||
});
|
||||
|
||||
it('should render chained regex variables with URL', () => {
|
||||
ds.metricFindQuery('SHOW TAG VALUES WITH KEY = "agent_url" WHERE agent_url =~ /^$var1$/', {
|
||||
...queryOptions,
|
||||
scopedVars: {
|
||||
var1: {
|
||||
text: 'https://aaaa-aa-aaa.bbb.ccc.ddd:8443/ggggg',
|
||||
value: 'https://aaaa-aa-aaa.bbb.ccc.ddd:8443/ggggg',
|
||||
},
|
||||
},
|
||||
});
|
||||
const qe = `SHOW TAG VALUES WITH KEY = "agent_url" WHERE agent_url =~ /^https:\\/\\/aaaa-aa-aaa\\.bbb\\.ccc\\.ddd:8443\\/ggggg$/`;
|
||||
expect(fetchMock).toHaveBeenCalled();
|
||||
const qData = fetchMock.mock.calls[0][0].data.queries[0].query;
|
||||
expect(qData).toBe(qe);
|
||||
});
|
||||
|
||||
it('should render chained regex variables with floating point number and url', () => {
|
||||
ds.metricFindQuery(
|
||||
'SELECT sum("piece_count") FROM "rp"."pdata" WHERE diameter <= $maxSED AND agent_url =~ /^$var1$/',
|
||||
{
|
||||
...queryOptions,
|
||||
scopedVars: {
|
||||
var1: {
|
||||
text: 'https://aaaa-aa-aaa.bbb.ccc.ddd:8443/ggggg',
|
||||
value: 'https://aaaa-aa-aaa.bbb.ccc.ddd:8443/ggggg',
|
||||
},
|
||||
maxSED: { text: '8.1', value: '8.1' },
|
||||
},
|
||||
}
|
||||
);
|
||||
const qe = `SELECT sum("piece_count") FROM "rp"."pdata" WHERE diameter <= 8.1 AND agent_url =~ /^https:\\/\\/aaaa-aa-aaa\\.bbb\\.ccc\\.ddd:8443\\/ggggg$/`;
|
||||
const qData = fetchMock.mock.calls[0][0].data.queries[0].query;
|
||||
expect(qData).toBe(qe);
|
||||
});
|
||||
|
||||
it('should interpolate variable inside a regex pattern', () => {
|
||||
const query: InfluxQuery = {
|
||||
refId: 'A',
|
||||
tags: [
|
||||
{
|
||||
key: 'key',
|
||||
operator: '=~',
|
||||
value: '/^.*-$var1$/',
|
||||
},
|
||||
],
|
||||
};
|
||||
const res = ds.applyVariables(query, {});
|
||||
const expected = `/^.*-var1$/`;
|
||||
expect(res.tags?.[0].value).toEqual(expected);
|
||||
});
|
||||
|
||||
it('should remove regex wrappers when operator is not a regex operator', () => {
|
||||
const query: InfluxQuery = {
|
||||
refId: 'A',
|
||||
tags: [
|
||||
{
|
||||
key: 'key',
|
||||
operator: '=',
|
||||
value: '/^$path$/',
|
||||
},
|
||||
],
|
||||
};
|
||||
const res = ds.applyVariables(query, {});
|
||||
const expected = `/etc/hosts`;
|
||||
expect(res.tags?.[0].value).toEqual(expected);
|
||||
});
|
||||
|
||||
it('should interpolate field keys with given scopedVars', () => {
|
||||
const query: InfluxQuery = {
|
||||
refId: 'A',
|
||||
tags: [
|
||||
{
|
||||
key: 'key',
|
||||
operator: '=',
|
||||
value: 'value',
|
||||
},
|
||||
],
|
||||
select: [
|
||||
[
|
||||
{
|
||||
type: 'field',
|
||||
params: ['$field_var'],
|
||||
},
|
||||
{
|
||||
text: `/special/path`,
|
||||
value: `/special/path`,
|
||||
type: 'mean',
|
||||
params: [],
|
||||
},
|
||||
{
|
||||
text: `/some/other/path`,
|
||||
value: `/some/other/path`,
|
||||
}
|
||||
)
|
||||
.build();
|
||||
const value = [`/special/path`, `/some/other/path`];
|
||||
const result = ds.interpolateQueryExpr(value, variableMock, `select that where path = /$tempVar/`);
|
||||
const expectation = `(\\/special\\/path|\\/some\\/other\\/path)`;
|
||||
expect(result).toBe(expectation);
|
||||
});
|
||||
|
||||
it('should return floating point number as it is', () => {
|
||||
const variableMock = queryBuilder()
|
||||
.withId('tempVar')
|
||||
.withName('tempVar')
|
||||
.withMulti(false)
|
||||
.withOptions({
|
||||
text: `1.0`,
|
||||
value: `1.0`,
|
||||
})
|
||||
.build();
|
||||
const value = `1.0`;
|
||||
const result = ds.interpolateQueryExpr(value, variableMock, `select value / $tempVar from /^measurement$/`);
|
||||
const expectation = `1.0`;
|
||||
expect(result).toBe(expectation);
|
||||
});
|
||||
],
|
||||
],
|
||||
};
|
||||
const res = ds.applyVariables(query, { field_var: { text: 'field_3', value: 'field_3' } });
|
||||
const expected = `field_3`;
|
||||
expect(res.select?.[0][0].params?.[0]).toEqual(expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('interpolateQueryExpr', () => {
|
||||
let ds = getMockInfluxDS(getMockDSInstanceSettings(), new TemplateSrv());
|
||||
it('should return the value as it is', () => {
|
||||
const value = 'normalValue';
|
||||
const variableMock = queryBuilder().withId('tempVar').withName('tempVar').withMulti(false).build();
|
||||
const result = ds.interpolateQueryExpr(value, variableMock, 'my query $tempVar');
|
||||
const expectation = 'normalValue';
|
||||
expect(result).toBe(expectation);
|
||||
});
|
||||
|
||||
it('should return the escaped value if the value wrapped in regex', () => {
|
||||
const value = '/special/path';
|
||||
const variableMock = queryBuilder().withId('tempVar').withName('tempVar').withMulti(false).build();
|
||||
const result = ds.interpolateQueryExpr(value, variableMock, 'select that where path = /$tempVar/');
|
||||
const expectation = `\\/special\\/path`;
|
||||
expect(result).toBe(expectation);
|
||||
});
|
||||
|
||||
it('should return the escaped value if the value wrapped in regex 2', () => {
|
||||
const value = '/special/path';
|
||||
const variableMock = queryBuilder().withId('tempVar').withName('tempVar').withMulti(false).build();
|
||||
const result = ds.interpolateQueryExpr(value, variableMock, 'select that where path = /^$tempVar$/');
|
||||
const expectation = `\\/special\\/path`;
|
||||
expect(result).toBe(expectation);
|
||||
});
|
||||
|
||||
it('should return the escaped value if the value wrapped in regex 3', () => {
|
||||
const value = ['env', 'env2', 'env3'];
|
||||
const variableMock = queryBuilder()
|
||||
.withId('tempVar')
|
||||
.withName('tempVar')
|
||||
.withMulti(false)
|
||||
.withIncludeAll(true)
|
||||
.build();
|
||||
const result = ds.interpolateQueryExpr(value, variableMock, 'select from /^($tempVar)$/');
|
||||
const expectation = `(env|env2|env3)`;
|
||||
expect(result).toBe(expectation);
|
||||
});
|
||||
|
||||
it('should **not** return the escaped value if the value **is not** wrapped in regex', () => {
|
||||
const value = '/special/path';
|
||||
const variableMock = queryBuilder().withId('tempVar').withName('tempVar').withMulti(false).build();
|
||||
const result = ds.interpolateQueryExpr(value, variableMock, `select that where path = '$tempVar'`);
|
||||
const expectation = `/special/path`;
|
||||
expect(result).toBe(expectation);
|
||||
});
|
||||
|
||||
it('should **not** return the escaped value if the value **is not** wrapped in regex 2', () => {
|
||||
const value = '12.2';
|
||||
const variableMock = queryBuilder().withId('tempVar').withName('tempVar').withMulti(false).build();
|
||||
const result = ds.interpolateQueryExpr(value, variableMock, `select that where path = '$tempVar'`);
|
||||
const expectation = `12.2`;
|
||||
expect(result).toBe(expectation);
|
||||
});
|
||||
|
||||
it('should escape the value **always** if the variable is a multi-value variable', () => {
|
||||
const value = [`/special/path`, `/some/other/path`];
|
||||
const variableMock = queryBuilder().withId('tempVar').withName('tempVar').withMulti().build();
|
||||
const result = ds.interpolateQueryExpr(value, variableMock, `select that where path = '$tempVar'`);
|
||||
const expectation = `(\\/special\\/path|\\/some\\/other\\/path)`;
|
||||
expect(result).toBe(expectation);
|
||||
});
|
||||
|
||||
it('should escape and join with the pipe even the variable is not multi-value', () => {
|
||||
const variableMock = queryBuilder()
|
||||
.withId('tempVar')
|
||||
.withName('tempVar')
|
||||
.withCurrent('All', '$__all')
|
||||
.withMulti(false)
|
||||
.withAllValue('')
|
||||
.withIncludeAll()
|
||||
.withOptions(
|
||||
{
|
||||
text: 'All',
|
||||
value: '$__all',
|
||||
},
|
||||
{
|
||||
text: `/special/path`,
|
||||
value: `/special/path`,
|
||||
},
|
||||
{
|
||||
text: `/some/other/path`,
|
||||
value: `/some/other/path`,
|
||||
}
|
||||
)
|
||||
.build();
|
||||
const value = [`/special/path`, `/some/other/path`];
|
||||
const result = ds.interpolateQueryExpr(value, variableMock, `select that where path = /$tempVar/`);
|
||||
const expectation = `(\\/special\\/path|\\/some\\/other\\/path)`;
|
||||
expect(result).toBe(expectation);
|
||||
});
|
||||
|
||||
it('should return floating point number as it is', () => {
|
||||
const variableMock = queryBuilder()
|
||||
.withId('tempVar')
|
||||
.withName('tempVar')
|
||||
.withMulti(false)
|
||||
.withOptions({
|
||||
text: `1.0`,
|
||||
value: `1.0`,
|
||||
})
|
||||
.build();
|
||||
const value = `1.0`;
|
||||
const result = ds.interpolateQueryExpr(value, variableMock, `select value / $tempVar from /^measurement$/`);
|
||||
const expectation = `1.0`;
|
||||
expect(result).toBe(expectation);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -174,7 +174,7 @@ export default class InfluxDatasource extends DataSourceWithBackend<InfluxQuery,
|
||||
const variables = scopedVars || {};
|
||||
|
||||
// We want to interpolate these variables on backend.
|
||||
// The pre-calculated values are replaced withe the variable strings.
|
||||
// The pre-calculated values are replaced with the variable strings.
|
||||
variables.__interval = {
|
||||
value: '$__interval',
|
||||
};
|
||||
|
||||
@@ -1,443 +0,0 @@
|
||||
import { of } from 'rxjs';
|
||||
|
||||
import { DataQueryRequest, dateTime, ScopedVars } from '@grafana/data/src';
|
||||
import { FetchResponse } from '@grafana/runtime/src';
|
||||
import config from 'app/core/config';
|
||||
|
||||
import { TemplateSrv } from '../../../features/templating/template_srv';
|
||||
import { queryBuilder } from '../../../features/variables/shared/testing/builders';
|
||||
|
||||
import InfluxDatasource from './datasource';
|
||||
import {
|
||||
getMockDSInstanceSettings,
|
||||
getMockInfluxDS,
|
||||
mockBackendService,
|
||||
mockInfluxFetchResponse,
|
||||
mockInfluxQueryWithTemplateVars,
|
||||
mockTemplateSrv,
|
||||
} from './mocks';
|
||||
import { InfluxQuery, InfluxVersion } from './types';
|
||||
|
||||
config.featureToggles.influxdbBackendMigration = true;
|
||||
const fetchMock = mockBackendService(mockInfluxFetchResponse());
|
||||
|
||||
describe('InfluxDataSource Backend Mode', () => {
|
||||
const text = 'interpolationText';
|
||||
const text2 = 'interpolationText2';
|
||||
const textWithoutFormatRegex = 'interpolationText,interpolationText2';
|
||||
const textWithFormatRegex = 'interpolationText|interpolationText2';
|
||||
const variableMap: Record<string, string> = {
|
||||
$interpolationVar: text,
|
||||
$interpolationVar2: text2,
|
||||
};
|
||||
const adhocFilters = [
|
||||
{
|
||||
key: 'adhoc',
|
||||
operator: '=',
|
||||
value: 'val',
|
||||
condition: '',
|
||||
},
|
||||
];
|
||||
const templateSrv = mockTemplateSrv(
|
||||
jest.fn(() => {
|
||||
return adhocFilters;
|
||||
}),
|
||||
jest.fn((target?: string, scopedVars?: ScopedVars, format?: string | Function): string => {
|
||||
if (!format) {
|
||||
return variableMap[target!] || '';
|
||||
}
|
||||
if (format === 'regex') {
|
||||
return textWithFormatRegex;
|
||||
}
|
||||
return textWithoutFormatRegex;
|
||||
})
|
||||
);
|
||||
|
||||
let queryOptions: DataQueryRequest<InfluxQuery>;
|
||||
let influxQuery: InfluxQuery;
|
||||
const now = dateTime('2023-09-16T21:26:00Z');
|
||||
|
||||
beforeEach(() => {
|
||||
queryOptions = {
|
||||
app: 'dashboard',
|
||||
interval: '10',
|
||||
intervalMs: 10,
|
||||
requestId: 'A-testing',
|
||||
startTime: 0,
|
||||
range: {
|
||||
from: dateTime(now).subtract(15, 'minutes'),
|
||||
to: now,
|
||||
raw: {
|
||||
from: 'now-15m',
|
||||
to: 'now',
|
||||
},
|
||||
},
|
||||
rangeRaw: {
|
||||
from: 'now-15m',
|
||||
to: 'now',
|
||||
},
|
||||
targets: [],
|
||||
timezone: 'UTC',
|
||||
scopedVars: {
|
||||
interval: { text: '1m', value: '1m' },
|
||||
__interval: { text: '1m', value: '1m' },
|
||||
__interval_ms: { text: 60000, value: 60000 },
|
||||
},
|
||||
};
|
||||
|
||||
influxQuery = {
|
||||
refId: 'x',
|
||||
alias: '$interpolationVar',
|
||||
measurement: '$interpolationVar',
|
||||
policy: '$interpolationVar',
|
||||
limit: '$interpolationVar',
|
||||
slimit: '$interpolationVar',
|
||||
tz: '$interpolationVar',
|
||||
tags: [
|
||||
{
|
||||
key: 'cpu',
|
||||
operator: '=~',
|
||||
value: '/^$interpolationVar,$interpolationVar2$/',
|
||||
},
|
||||
],
|
||||
groupBy: [
|
||||
{
|
||||
params: ['$interpolationVar'],
|
||||
type: 'tag',
|
||||
},
|
||||
],
|
||||
select: [
|
||||
[
|
||||
{
|
||||
params: ['$interpolationVar'],
|
||||
type: 'field',
|
||||
},
|
||||
],
|
||||
],
|
||||
};
|
||||
});
|
||||
|
||||
describe('adhoc filters', () => {
|
||||
let fetchReq: { queries: InfluxQuery[] };
|
||||
const ctx = {
|
||||
ds: getMockInfluxDS(getMockDSInstanceSettings(), templateSrv),
|
||||
};
|
||||
beforeEach(async () => {
|
||||
fetchMock.mockImplementation((req) => {
|
||||
fetchReq = req.data;
|
||||
return of(mockInfluxFetchResponse() as FetchResponse);
|
||||
});
|
||||
const req = {
|
||||
...queryOptions,
|
||||
targets: [...queryOptions.targets, { ...influxQuery, adhocFilters }],
|
||||
};
|
||||
ctx.ds.query(req);
|
||||
});
|
||||
|
||||
it('should add adhocFilters to the tags in the query', () => {
|
||||
expect(fetchMock).toHaveBeenCalled();
|
||||
expect(fetchReq).not.toBeNull();
|
||||
expect(fetchReq.queries.length).toBe(1);
|
||||
expect(fetchReq.queries[0].tags).toBeDefined();
|
||||
expect(fetchReq.queries[0].tags?.length).toBe(2);
|
||||
expect(fetchReq.queries[0].tags?.[1].key).toBe(adhocFilters[0].key);
|
||||
expect(fetchReq.queries[0].tags?.[1].value).toBe(adhocFilters[0].value);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when interpolating template variables', () => {
|
||||
const text = 'interpolationText';
|
||||
const text2 = 'interpolationText2';
|
||||
const textWithoutFormatRegex = 'interpolationText,interpolationText2';
|
||||
const textWithFormatRegex = 'interpolationText,interpolationText2';
|
||||
const justText = 'interpolationText';
|
||||
const variableMap: Record<string, string> = {
|
||||
$interpolationVar: text,
|
||||
$interpolationVar2: text2,
|
||||
};
|
||||
const adhocFilters = [
|
||||
{
|
||||
key: 'adhoc',
|
||||
operator: '=',
|
||||
value: 'val',
|
||||
condition: '',
|
||||
},
|
||||
];
|
||||
const templateSrv = mockTemplateSrv(
|
||||
jest.fn((_: string) => adhocFilters),
|
||||
jest.fn((target?: string, scopedVars?: ScopedVars, format?: string | Function): string => {
|
||||
if (!format) {
|
||||
return variableMap[target!] || '';
|
||||
}
|
||||
if (format === 'regex') {
|
||||
return textWithFormatRegex;
|
||||
}
|
||||
return textWithoutFormatRegex;
|
||||
})
|
||||
);
|
||||
const ds = new InfluxDatasource(getMockDSInstanceSettings(), templateSrv);
|
||||
|
||||
function influxChecks(query: InfluxQuery) {
|
||||
expect(templateSrv.replace).toBeCalledTimes(12);
|
||||
expect(query.alias).toBe(text);
|
||||
expect(query.measurement).toBe(textWithFormatRegex);
|
||||
expect(query.policy).toBe(justText);
|
||||
expect(query.limit).toBe(justText);
|
||||
expect(query.slimit).toBe(justText);
|
||||
expect(query.tz).toBe(text);
|
||||
expect(query.tags![0].value).toBe(textWithFormatRegex);
|
||||
expect(query.groupBy![0].params![0]).toBe(justText);
|
||||
expect(query.select![0][0].params![0]).toBe(justText);
|
||||
expect(query.adhocFilters?.[0].key).toBe(adhocFilters[0].key);
|
||||
}
|
||||
|
||||
it('should apply all template variables with InfluxQL mode', () => {
|
||||
ds.version = ds.version = InfluxVersion.InfluxQL;
|
||||
ds.access = 'proxy';
|
||||
const query = ds.applyTemplateVariables(mockInfluxQueryWithTemplateVars(adhocFilters), {
|
||||
interpolationVar: { text: text, value: text },
|
||||
interpolationVar2: { text: 'interpolationText2', value: 'interpolationText2' },
|
||||
});
|
||||
influxChecks(query);
|
||||
});
|
||||
|
||||
it('should apply all scopedVars to tags', () => {
|
||||
ds.version = InfluxVersion.InfluxQL;
|
||||
ds.access = 'proxy';
|
||||
const query = ds.applyTemplateVariables(mockInfluxQueryWithTemplateVars(adhocFilters), {
|
||||
interpolationVar: { text: text, value: text },
|
||||
interpolationVar2: { text: 'interpolationText2', value: 'interpolationText2' },
|
||||
});
|
||||
if (!query.tags?.length) {
|
||||
throw new Error('Tags are not defined');
|
||||
}
|
||||
const value = query.tags[0].value;
|
||||
const scopedVars = 'interpolationText,interpolationText2';
|
||||
expect(value).toBe(scopedVars);
|
||||
});
|
||||
});
|
||||
|
||||
describe('variable interpolation with chained variables with backend mode', () => {
|
||||
const variablesMock = [
|
||||
queryBuilder().withId('var1').withName('var1').withCurrent('var1').build(),
|
||||
queryBuilder().withId('path').withName('path').withCurrent('/etc/hosts').build(),
|
||||
queryBuilder()
|
||||
.withId('field_var')
|
||||
.withName('field_var')
|
||||
.withMulti(true)
|
||||
.withOptions(
|
||||
{
|
||||
text: `field_1`,
|
||||
value: `field_1`,
|
||||
},
|
||||
{
|
||||
text: `field_2`,
|
||||
value: `field_2`,
|
||||
},
|
||||
{
|
||||
text: `field_3`,
|
||||
value: `field_3`,
|
||||
}
|
||||
)
|
||||
.withCurrent(['field_1', 'field_3'])
|
||||
.build(),
|
||||
];
|
||||
const mockTemplateService = new TemplateSrv({
|
||||
getVariables: () => variablesMock,
|
||||
getVariableWithName: (name: string) => variablesMock.filter((v) => v.name === name)[0],
|
||||
getFilteredVariables: jest.fn(),
|
||||
});
|
||||
mockTemplateService.getAdhocFilters = jest.fn((_: string) => []);
|
||||
let ds = getMockInfluxDS(getMockDSInstanceSettings(), mockTemplateService);
|
||||
const fetchMockImpl = () =>
|
||||
of({
|
||||
data: {
|
||||
status: 'success',
|
||||
results: [
|
||||
{
|
||||
series: [
|
||||
{
|
||||
name: 'measurement',
|
||||
columns: ['name'],
|
||||
values: [['cpu']],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
fetchMock.mockImplementation(fetchMockImpl);
|
||||
});
|
||||
|
||||
it('should render chained regex variables with floating point number', () => {
|
||||
ds.metricFindQuery(`SELECT sum("piece_count") FROM "rp"."pdata" WHERE diameter <= $maxSED`, {
|
||||
...queryOptions,
|
||||
scopedVars: { maxSED: { text: '8.1', value: '8.1' } },
|
||||
});
|
||||
const qe = `SELECT sum("piece_count") FROM "rp"."pdata" WHERE diameter <= 8.1`;
|
||||
const qData = fetchMock.mock.calls[0][0].data.queries[0].query;
|
||||
expect(qData).toBe(qe);
|
||||
});
|
||||
|
||||
it('should render chained regex variables with URL', () => {
|
||||
ds.metricFindQuery('SHOW TAG VALUES WITH KEY = "agent_url" WHERE agent_url =~ /^$var1$/', {
|
||||
...queryOptions,
|
||||
scopedVars: {
|
||||
var1: {
|
||||
text: 'https://aaaa-aa-aaa.bbb.ccc.ddd:8443/ggggg',
|
||||
value: 'https://aaaa-aa-aaa.bbb.ccc.ddd:8443/ggggg',
|
||||
},
|
||||
},
|
||||
});
|
||||
const qe = `SHOW TAG VALUES WITH KEY = "agent_url" WHERE agent_url =~ /^https:\\/\\/aaaa-aa-aaa\\.bbb\\.ccc\\.ddd:8443\\/ggggg$/`;
|
||||
expect(fetchMock).toHaveBeenCalled();
|
||||
const qData = fetchMock.mock.calls[0][0].data.queries[0].query;
|
||||
expect(qData).toBe(qe);
|
||||
});
|
||||
|
||||
it('should render chained regex variables with floating point number and url', () => {
|
||||
ds.metricFindQuery(
|
||||
'SELECT sum("piece_count") FROM "rp"."pdata" WHERE diameter <= $maxSED AND agent_url =~ /^$var1$/',
|
||||
{
|
||||
...queryOptions,
|
||||
scopedVars: {
|
||||
var1: {
|
||||
text: 'https://aaaa-aa-aaa.bbb.ccc.ddd:8443/ggggg',
|
||||
value: 'https://aaaa-aa-aaa.bbb.ccc.ddd:8443/ggggg',
|
||||
},
|
||||
maxSED: { text: '8.1', value: '8.1' },
|
||||
},
|
||||
}
|
||||
);
|
||||
const qe = `SELECT sum("piece_count") FROM "rp"."pdata" WHERE diameter <= 8.1 AND agent_url =~ /^https:\\/\\/aaaa-aa-aaa\\.bbb\\.ccc\\.ddd:8443\\/ggggg$/`;
|
||||
const qData = fetchMock.mock.calls[0][0].data.queries[0].query;
|
||||
expect(qData).toBe(qe);
|
||||
});
|
||||
|
||||
it('should interpolate variable inside a regex pattern', () => {
|
||||
const query: InfluxQuery = {
|
||||
refId: 'A',
|
||||
tags: [
|
||||
{
|
||||
key: 'key',
|
||||
operator: '=~',
|
||||
value: '/^.*-$var1$/',
|
||||
},
|
||||
],
|
||||
};
|
||||
const res = ds.applyVariables(query, {});
|
||||
const expected = `/^.*-var1$/`;
|
||||
expect(res.tags?.[0].value).toEqual(expected);
|
||||
});
|
||||
|
||||
it('should remove regex wrappers when operator is not a regex operator', () => {
|
||||
const query: InfluxQuery = {
|
||||
refId: 'A',
|
||||
tags: [
|
||||
{
|
||||
key: 'key',
|
||||
operator: '=',
|
||||
value: '/^$path$/',
|
||||
},
|
||||
],
|
||||
};
|
||||
const res = ds.applyVariables(query, {});
|
||||
const expected = `/etc/hosts`;
|
||||
expect(res.tags?.[0].value).toEqual(expected);
|
||||
});
|
||||
|
||||
it('should interpolate field keys with given scopedVars', () => {
|
||||
const query: InfluxQuery = {
|
||||
refId: 'A',
|
||||
tags: [
|
||||
{
|
||||
key: 'key',
|
||||
operator: '=',
|
||||
value: 'value',
|
||||
},
|
||||
],
|
||||
select: [
|
||||
[
|
||||
{
|
||||
type: 'field',
|
||||
params: ['$field_var'],
|
||||
},
|
||||
{
|
||||
type: 'mean',
|
||||
params: [],
|
||||
},
|
||||
],
|
||||
],
|
||||
};
|
||||
const res = ds.applyVariables(query, { field_var: { text: 'field_3', value: 'field_3' } });
|
||||
const expected = `field_3`;
|
||||
expect(res.select?.[0][0].params?.[0]).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe('metric find query', () => {
|
||||
let ds = getMockInfluxDS(getMockDSInstanceSettings());
|
||||
it('handles multiple frames', async () => {
|
||||
const fetchMockImpl = () => {
|
||||
return of(mockMetricFindQueryResponse);
|
||||
};
|
||||
|
||||
fetchMock.mockImplementation(fetchMockImpl);
|
||||
const values = await ds.getTagValues({ key: 'test_id', filters: [] });
|
||||
expect(fetchMock).toHaveBeenCalled();
|
||||
expect(values.length).toBe(5);
|
||||
expect(values[0].text).toBe('test-t2-1');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const mockMetricFindQueryResponse = {
|
||||
data: {
|
||||
results: {
|
||||
metricFindQuery: {
|
||||
status: 200,
|
||||
frames: [
|
||||
{
|
||||
schema: {
|
||||
name: 'NoneNone',
|
||||
refId: 'metricFindQuery',
|
||||
fields: [
|
||||
{
|
||||
name: 'Value',
|
||||
type: 'string',
|
||||
typeInfo: {
|
||||
frame: 'string',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
data: {
|
||||
values: [['test-t2-1', 'test-t2-10']],
|
||||
},
|
||||
},
|
||||
{
|
||||
schema: {
|
||||
name: 'some-other',
|
||||
refId: 'metricFindQuery',
|
||||
fields: [
|
||||
{
|
||||
name: 'Value',
|
||||
type: 'string',
|
||||
typeInfo: {
|
||||
frame: 'string',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
data: {
|
||||
values: [['test-t2-1', 'test-t2-10', 'test-t2-2', 'test-t2-3', 'test-t2-4']],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -3,14 +3,10 @@ import { lastValueFrom } from 'rxjs';
|
||||
import { SQLQuery } from '@grafana/sql';
|
||||
import config from 'app/core/config';
|
||||
|
||||
import { getMockDSInstanceSettings, mockBackendService, mockTemplateSrv } from './__mocks__/datasource';
|
||||
import { mockInfluxQueryRequest } from './__mocks__/request';
|
||||
import { mockInfluxSQLFetchResponse } from './__mocks__/response';
|
||||
import InfluxDatasource from './datasource';
|
||||
import {
|
||||
getMockDSInstanceSettings,
|
||||
mockBackendService,
|
||||
mockInfluxQueryRequest,
|
||||
mockInfluxSQLFetchResponse,
|
||||
mockTemplateSrv,
|
||||
} from './mocks';
|
||||
import { InfluxVersion } from './types';
|
||||
|
||||
config.featureToggles.influxdbBackendMigration = true;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { TemplateSrv } from '@grafana/runtime';
|
||||
|
||||
import { getMockDSInstanceSettings, mockBackendService, mockInfluxSQLVariableFetchResponse } from '../mocks';
|
||||
import { getMockDSInstanceSettings, mockBackendService } from '../__mocks__/datasource';
|
||||
import { mockInfluxSQLVariableFetchResponse } from '../__mocks__/response';
|
||||
|
||||
import { FlightSQLDatasource } from './datasource.flightsql';
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import config from 'app/core/config';
|
||||
|
||||
import { getMockInfluxDS } from './__mocks__/datasource';
|
||||
import { getAllMeasurements, getAllPolicies, getFieldKeys, getTagKeys, getTagValues } from './influxql_metadata_query';
|
||||
import { getMockInfluxDS } from './mocks';
|
||||
import { InfluxQuery } from './types';
|
||||
|
||||
describe('influx_metadata_query', () => {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { templateSrvStub as templateService } from './__mocks__/datasource';
|
||||
import { buildMetadataQuery } from './influxql_query_builder';
|
||||
import { templateSrvStub as templateService } from './mocks';
|
||||
import { DEFAULT_POLICY } from './types';
|
||||
|
||||
describe('influxql-query-builder', () => {
|
||||
|
||||
@@ -6,8 +6,8 @@ import { FetchResponse } from '@grafana/runtime';
|
||||
import config from 'app/core/config';
|
||||
import { backendSrv } from 'app/core/services/backend_srv'; // will use the version in __mocks__
|
||||
|
||||
import { getMockDSInstanceSettings, getMockInfluxDS } from './__mocks__/datasource';
|
||||
import InfluxQueryModel from './influx_query_model';
|
||||
import { getMockDSInstanceSettings, getMockInfluxDS } from './mocks';
|
||||
import ResponseParser, { getSelectedParams } from './response_parser';
|
||||
import { InfluxQuery } from './types';
|
||||
|
||||
|
||||
Reference in New Issue
Block a user