mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
This reverts commit 862f09376f.
This commit is contained in:
@@ -1,39 +1,82 @@
|
||||
import { DataSourceInstanceSettings, FieldType, MutableDataFrame, PluginType } from '@grafana/data';
|
||||
import { backendSrv } from 'app/core/services/backend_srv';
|
||||
import { of } from 'rxjs';
|
||||
import { createFetchResponse } from 'test/helpers/createFetchResponse';
|
||||
import { TempoDatasource } from './datasource';
|
||||
|
||||
jest.mock('../../../../../packages/grafana-runtime/src/services/backendSrv.ts', () => ({
|
||||
getBackendSrv: () => backendSrv,
|
||||
}));
|
||||
|
||||
jest.mock('../../../../../packages/grafana-runtime/src/utils/queryResponse.ts', () => ({
|
||||
toDataQueryResponse: (resp: any) => resp,
|
||||
}));
|
||||
|
||||
describe('Tempo data source', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
import { TempoDatasource, TempoQuery } from './datasource';
|
||||
import { DataQueryRequest, DataSourceInstanceSettings, FieldType, PluginType, dateTime } from '@grafana/data';
|
||||
import { BackendSrv, BackendSrvRequest, getBackendSrv, setBackendSrv } from '@grafana/runtime';
|
||||
|
||||
describe('JaegerDatasource', () => {
|
||||
it('returns trace when queried', async () => {
|
||||
const responseDataFrame = new MutableDataFrame({ fields: [{ name: 'trace', values: ['{}'] }] });
|
||||
setupBackendSrv([responseDataFrame]);
|
||||
const ds = new TempoDatasource(defaultSettings);
|
||||
await expect(ds.query({ targets: [{ query: '12345' }] } as any)).toEmitValuesWith((response) => {
|
||||
const field = response[0].data[0].fields[0];
|
||||
await withMockedBackendSrv(makeBackendSrvMock('12345'), async () => {
|
||||
const ds = new TempoDatasource(defaultSettings);
|
||||
const response = await ds.query(defaultQuery).toPromise();
|
||||
const field = response.data[0].fields[0];
|
||||
expect(field.name).toBe('trace');
|
||||
expect(field.type).toBe(FieldType.trace);
|
||||
expect(field.values.get(0)).toEqual({
|
||||
traceId: '12345',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('returns trace when traceId with special characters is queried', async () => {
|
||||
await withMockedBackendSrv(makeBackendSrvMock('a/b'), async () => {
|
||||
const ds = new TempoDatasource(defaultSettings);
|
||||
const query = {
|
||||
...defaultQuery,
|
||||
targets: [
|
||||
{
|
||||
query: 'a/b',
|
||||
refId: '1',
|
||||
},
|
||||
],
|
||||
};
|
||||
const response = await ds.query(query).toPromise();
|
||||
const field = response.data[0].fields[0];
|
||||
expect(field.name).toBe('trace');
|
||||
expect(field.type).toBe(FieldType.trace);
|
||||
expect(field.values.get(0)).toEqual({
|
||||
traceId: 'a/b',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('returns empty response if trace id is not specified', async () => {
|
||||
const ds = new TempoDatasource(defaultSettings);
|
||||
const response = await ds
|
||||
.query({
|
||||
...defaultQuery,
|
||||
targets: [],
|
||||
})
|
||||
.toPromise();
|
||||
const field = response.data[0].fields[0];
|
||||
expect(field.name).toBe('trace');
|
||||
expect(field.type).toBe(FieldType.trace);
|
||||
expect(field.values.length).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
function setupBackendSrv(response: any) {
|
||||
const defaultMock = () => of(createFetchResponse(response));
|
||||
function makeBackendSrvMock(traceId: string) {
|
||||
return {
|
||||
datasourceRequest(options: BackendSrvRequest): Promise<any> {
|
||||
expect(options.url.substr(options.url.length - 17, options.url.length)).toBe(
|
||||
`/api/traces/${encodeURIComponent(traceId)}`
|
||||
);
|
||||
return Promise.resolve({
|
||||
data: {
|
||||
data: [
|
||||
{
|
||||
traceId,
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
},
|
||||
} as any;
|
||||
}
|
||||
|
||||
const fetchMock = jest.spyOn(backendSrv, 'fetch');
|
||||
fetchMock.mockImplementation(defaultMock);
|
||||
async function withMockedBackendSrv(srv: BackendSrv, fn: () => Promise<void>) {
|
||||
const oldSrv = getBackendSrv();
|
||||
setBackendSrv(srv);
|
||||
await fn();
|
||||
setBackendSrv(oldSrv);
|
||||
}
|
||||
|
||||
const defaultSettings: DataSourceInstanceSettings = {
|
||||
@@ -51,3 +94,26 @@ const defaultSettings: DataSourceInstanceSettings = {
|
||||
},
|
||||
jsonData: {},
|
||||
};
|
||||
|
||||
const defaultQuery: DataQueryRequest<TempoQuery> = {
|
||||
requestId: '1',
|
||||
dashboardId: 0,
|
||||
interval: '0',
|
||||
intervalMs: 10,
|
||||
panelId: 0,
|
||||
scopedVars: {},
|
||||
range: {
|
||||
from: dateTime().subtract(1, 'h'),
|
||||
to: dateTime(),
|
||||
raw: { from: '1h', to: 'now' },
|
||||
},
|
||||
timezone: 'browser',
|
||||
app: 'explore',
|
||||
startTime: 0,
|
||||
targets: [
|
||||
{
|
||||
query: '12345',
|
||||
refId: '1',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
@@ -1,63 +1,121 @@
|
||||
import {
|
||||
DataFrame,
|
||||
DataQuery,
|
||||
dateMath,
|
||||
DateTime,
|
||||
MutableDataFrame,
|
||||
DataSourceApi,
|
||||
DataSourceInstanceSettings,
|
||||
DataQueryRequest,
|
||||
DataQueryResponse,
|
||||
DataSourceInstanceSettings,
|
||||
DataQuery,
|
||||
FieldType,
|
||||
MutableDataFrame,
|
||||
} from '@grafana/data';
|
||||
import { DataSourceWithBackend } from '@grafana/runtime';
|
||||
import { Observable } from 'rxjs';
|
||||
import { getBackendSrv, BackendSrvRequest } from '@grafana/runtime';
|
||||
import { Observable, from, of } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
|
||||
import { getTimeSrv, TimeSrv } from 'app/features/dashboard/services/TimeSrv';
|
||||
import { serializeParams } from 'app/core/utils/fetch';
|
||||
|
||||
export type TempoQuery = {
|
||||
query: string;
|
||||
} & DataQuery;
|
||||
|
||||
export class TempoDatasource extends DataSourceWithBackend<TempoQuery> {
|
||||
constructor(instanceSettings: DataSourceInstanceSettings) {
|
||||
export class TempoDatasource extends DataSourceApi<TempoQuery> {
|
||||
constructor(private instanceSettings: DataSourceInstanceSettings, private readonly timeSrv: TimeSrv = getTimeSrv()) {
|
||||
super(instanceSettings);
|
||||
}
|
||||
|
||||
query(options: DataQueryRequest<TempoQuery>): Observable<DataQueryResponse> {
|
||||
return super.query(options).pipe(
|
||||
map((response) => {
|
||||
if (response.error) {
|
||||
return response;
|
||||
}
|
||||
async metadataRequest(url: string, params?: Record<string, any>): Promise<any> {
|
||||
const res = await this._request(url, params, { hideFromInspector: true }).toPromise();
|
||||
return res.data.data;
|
||||
}
|
||||
|
||||
return {
|
||||
data: [
|
||||
new MutableDataFrame({
|
||||
fields: [
|
||||
{
|
||||
name: 'trace',
|
||||
type: FieldType.trace,
|
||||
values: [JSON.parse((response.data as DataFrame[])[0].fields[0].values.get(0))],
|
||||
query(options: DataQueryRequest<TempoQuery>): Observable<DataQueryResponse> {
|
||||
// At this moment we expect only one target. In case we somehow change the UI to be able to show multiple
|
||||
// traces at one we need to change this.
|
||||
const id = options.targets[0]?.query;
|
||||
if (id) {
|
||||
return this._request(`/api/traces/${encodeURIComponent(id)}`).pipe(
|
||||
map((response) => {
|
||||
return {
|
||||
data: [
|
||||
new MutableDataFrame({
|
||||
fields: [
|
||||
{
|
||||
name: 'trace',
|
||||
type: FieldType.trace,
|
||||
values: response?.data?.data || [],
|
||||
},
|
||||
],
|
||||
meta: {
|
||||
preferredVisualisationType: 'trace',
|
||||
},
|
||||
],
|
||||
meta: {
|
||||
preferredVisualisationType: 'trace',
|
||||
}),
|
||||
],
|
||||
};
|
||||
})
|
||||
);
|
||||
} else {
|
||||
return of({
|
||||
data: [
|
||||
new MutableDataFrame({
|
||||
fields: [
|
||||
{
|
||||
name: 'trace',
|
||||
type: FieldType.trace,
|
||||
values: [],
|
||||
},
|
||||
}),
|
||||
],
|
||||
};
|
||||
})
|
||||
);
|
||||
],
|
||||
meta: {
|
||||
preferredVisualisationType: 'trace',
|
||||
},
|
||||
}),
|
||||
],
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async testDatasource(): Promise<any> {
|
||||
const response = await super.query({ targets: [{ query: '', refId: 'A' }] } as any).toPromise();
|
||||
|
||||
if (!response.error?.message?.startsWith('failed to get trace')) {
|
||||
return { status: 'error', message: 'Data source is not working' };
|
||||
try {
|
||||
await this._request(`/api/traces/random`).toPromise();
|
||||
} catch (e) {
|
||||
// If all went well this request will get back with 400 - Bad request
|
||||
if (e?.status !== 400) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
return { status: 'success', message: 'Data source is working' };
|
||||
}
|
||||
|
||||
getTimeRange(): { start: number; end: number } {
|
||||
const range = this.timeSrv.timeRange();
|
||||
return {
|
||||
start: getTime(range.from, false),
|
||||
end: getTime(range.to, true),
|
||||
};
|
||||
}
|
||||
|
||||
getQueryDisplayText(query: TempoQuery) {
|
||||
return query.query;
|
||||
}
|
||||
|
||||
private _request(apiUrl: string, data?: any, options?: Partial<BackendSrvRequest>): Observable<Record<string, any>> {
|
||||
// Hack for proxying metadata requests
|
||||
const baseUrl = `/api/datasources/proxy/${this.instanceSettings.id}`;
|
||||
const params = data ? serializeParams(data) : '';
|
||||
const url = `${baseUrl}${apiUrl}${params.length ? `?${params}` : ''}`;
|
||||
const req = {
|
||||
...options,
|
||||
url,
|
||||
};
|
||||
|
||||
return from(getBackendSrv().datasourceRequest(req));
|
||||
}
|
||||
}
|
||||
|
||||
function getTime(date: string | DateTime, roundUp: boolean) {
|
||||
if (typeof date === 'string') {
|
||||
date = dateMath.parse(date, roundUp)!;
|
||||
}
|
||||
return date.valueOf() * 1000;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user