diff --git a/public/app/plugins/datasource/jaeger/datasource.test.ts b/public/app/plugins/datasource/jaeger/datasource.test.ts index 1d63001c6e0..d1f5edb6c92 100644 --- a/public/app/plugins/datasource/jaeger/datasource.test.ts +++ b/public/app/plugins/datasource/jaeger/datasource.test.ts @@ -1,21 +1,32 @@ -import { JaegerDatasource, JaegerQuery } from './datasource'; import { + ArrayVector, DataQueryRequest, DataSourceInstanceSettings, + dateTime, FieldType, PluginType, - dateTime, - ArrayVector, } from '@grafana/data'; -import { BackendSrv, BackendSrvRequest, getBackendSrv, setBackendSrv } from '@grafana/runtime'; +import { backendSrv } from 'app/core/services/backend_srv'; +import { of, throwError } from 'rxjs'; +import { createFetchResponse } from 'test/helpers/createFetchResponse'; +import { JaegerDatasource, JaegerQuery } from './datasource'; import { testResponse } from './testResponse'; +jest.mock('@grafana/runtime', () => ({ + ...((jest.requireActual('@grafana/runtime') as unknown) as object), + getBackendSrv: () => backendSrv, +})); + describe('JaegerDatasource', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + it('returns trace when queried', async () => { - await withMockedBackendSrv(makeBackendSrvMock('12345'), async () => { - const ds = new JaegerDatasource(defaultSettings); - const response = await ds.query(defaultQuery).toPromise(); - expect(response.data[0].fields).toMatchObject( + setupFetchMock({ data: [testResponse] }); + const ds = new JaegerDatasource(defaultSettings); + await expect(ds.query(defaultQuery)).toEmitValuesWith((val) => { + expect(val[0].data[0].fields).toMatchObject( [ { name: 'traceID', values: ['3fa414edcef6ad90', '3fa414edcef6ad90'] }, { name: 'spanID', values: ['3fa414edcef6ad90', '0f5c1808567e4403'] }, @@ -59,20 +70,19 @@ describe('JaegerDatasource', () => { }); it('returns trace when traceId with special characters is queried', async () => { - await withMockedBackendSrv(makeBackendSrvMock('a/b'), async () => { - const ds = new JaegerDatasource(defaultSettings); - const query = { - ...defaultQuery, - targets: [ - { - query: 'a/b', - refId: '1', - }, - ], - }; - await ds.query(query).toPromise(); - // there is expect makeBackendSrvMock checking correct encoding - }); + const mock = setupFetchMock({ data: [testResponse] }); + const ds = new JaegerDatasource(defaultSettings); + const query = { + ...defaultQuery, + targets: [ + { + query: 'a/b', + refId: '1', + }, + ], + }; + await ds.query(query).toPromise(); + expect(mock).toBeCalledWith({ url: `${defaultSettings.url}/api/traces/a%2Fb` }); }); it('returns empty response if trace id is not specified', async () => { @@ -93,120 +103,75 @@ describe('JaegerDatasource', () => { describe('when performing testDataSource', () => { describe('and call succeeds', () => { it('should return successfully', async () => { - const backendSrvMock = makeTestDatasourceMock( - Promise.resolve({ - statusText: 'OK', - status: 200, - data: { - data: ['service1'], - }, - }) - ); + setupFetchMock({ data: ['service1'] }); - await withMockedBackendSrv(backendSrvMock, async () => { - const ds = new JaegerDatasource(defaultSettings); - const response = await ds.testDatasource(); - expect(response.status).toEqual('success'); - expect(response.message).toBe('Data source connected and services found.'); - }); + const ds = new JaegerDatasource(defaultSettings); + const response = await ds.testDatasource(); + expect(response.status).toEqual('success'); + expect(response.message).toBe('Data source connected and services found.'); }); }); describe('and call succeeds, but returns no services', () => { it('should display an error', async () => { - const backendSrvMock = makeTestDatasourceMock( - Promise.resolve({ - statusText: 'OK', - status: 200, - }) - ); + setupFetchMock(undefined); - await withMockedBackendSrv(backendSrvMock, async () => { - const ds = new JaegerDatasource(defaultSettings); - const response = await ds.testDatasource(); - expect(response.status).toEqual('error'); - expect(response.message).toBe( - 'Data source connected, but no services received. Verify that Jaeger is configured properly.' - ); - }); + const ds = new JaegerDatasource(defaultSettings); + const response = await ds.testDatasource(); + expect(response.status).toEqual('error'); + expect(response.message).toBe( + 'Data source connected, but no services received. Verify that Jaeger is configured properly.' + ); }); }); describe('and call returns error with message', () => { it('should return the formatted error', async () => { - const backendSrvMock = { - datasourceRequest(options: BackendSrvRequest): Promise { - return Promise.reject({ - statusText: 'Not found', - status: 404, - data: { - message: '404 page not found', - }, - }); - }, - } as BackendSrv; + setupFetchMock( + undefined, + throwError({ + statusText: 'Not found', + status: 404, + data: { + message: '404 page not found', + }, + }) + ); - await withMockedBackendSrv(backendSrvMock, async () => { - const ds = new JaegerDatasource(defaultSettings); - const response = await ds.testDatasource(); - expect(response.status).toEqual('error'); - expect(response.message).toBe('Jaeger: Not found. 404. 404 page not found'); - }); + const ds = new JaegerDatasource(defaultSettings); + const response = await ds.testDatasource(); + expect(response.status).toEqual('error'); + expect(response.message).toBe('Jaeger: Not found. 404. 404 page not found'); }); }); describe('and call returns error without message', () => { it('should return JSON error', async () => { - const backendSrvMock = { - datasourceRequest(options: BackendSrvRequest): Promise { - return Promise.reject({ - statusText: 'Bad gateway', - status: 502, - data: { - errors: ['Could not connect to Jaeger backend'], - }, - }); - }, - } as BackendSrv; + setupFetchMock( + undefined, + throwError({ + statusText: 'Bad gateway', + status: 502, + data: { + errors: ['Could not connect to Jaeger backend'], + }, + }) + ); - await withMockedBackendSrv(backendSrvMock, async () => { - const ds = new JaegerDatasource(defaultSettings); - const response = await ds.testDatasource(); - expect(response.status).toEqual('error'); - expect(response.message).toBe('Jaeger: Bad gateway. 502. {"errors":["Could not connect to Jaeger backend"]}'); - }); + const ds = new JaegerDatasource(defaultSettings); + const response = await ds.testDatasource(); + expect(response.status).toEqual('error'); + expect(response.message).toBe('Jaeger: Bad gateway. 502. {"errors":["Could not connect to Jaeger backend"]}'); }); }); }); -function makeTestDatasourceMock(result: Promise) { - return { - datasourceRequest(options: BackendSrvRequest): Promise { - return result; - }, - } as BackendSrv; -} +function setupFetchMock(response: any, mock?: any) { + const defaultMock = () => mock ?? of(createFetchResponse(response)); -function makeBackendSrvMock(traceId: string) { - return { - datasourceRequest(options: BackendSrvRequest): Promise { - expect(options.url.substr(options.url.length - 17, options.url.length)).toBe( - `/api/traces/${encodeURIComponent(traceId)}` - ); - return Promise.resolve({ - data: { - data: [testResponse], - }, - }); - }, - } as any; -} - -async function withMockedBackendSrv(srv: BackendSrv, fn: () => Promise) { - const oldSrv = getBackendSrv(); - setBackendSrv(srv); - await fn(); - setBackendSrv(oldSrv); + const fetchMock = jest.spyOn(backendSrv, 'fetch'); + fetchMock.mockImplementation(defaultMock); + return fetchMock; } const defaultSettings: DataSourceInstanceSettings = { @@ -214,6 +179,7 @@ const defaultSettings: DataSourceInstanceSettings = { uid: '0', type: 'tracing', name: 'jaeger', + url: 'http://grafana.com', meta: { id: 'jaeger', name: 'jaeger', diff --git a/public/app/plugins/datasource/jaeger/datasource.ts b/public/app/plugins/datasource/jaeger/datasource.ts index a7716a6282c..02bd4817d5a 100644 --- a/public/app/plugins/datasource/jaeger/datasource.ts +++ b/public/app/plugins/datasource/jaeger/datasource.ts @@ -10,11 +10,10 @@ import { MutableDataFrame, } from '@grafana/data'; import { BackendSrvRequest, getBackendSrv } from '@grafana/runtime'; -import { from, Observable, of } from 'rxjs'; -import { catchError, map } from 'rxjs/operators'; - -import { getTimeSrv, TimeSrv } from 'app/features/dashboard/services/TimeSrv'; import { serializeParams } from 'app/core/utils/fetch'; +import { getTimeSrv, TimeSrv } from 'app/features/dashboard/services/TimeSrv'; +import { Observable, of } from 'rxjs'; +import { catchError, map } from 'rxjs/operators'; import { createTraceFrame } from './responseTransform'; export type JaegerQuery = { @@ -100,16 +99,14 @@ export class JaegerDatasource extends DataSourceApi { } private _request(apiUrl: string, data?: any, options?: Partial): Observable> { - // 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 url = `${this.instanceSettings.url}${apiUrl}${params.length ? `?${params}` : ''}`; const req = { ...options, url, }; - return from(getBackendSrv().datasourceRequest(req)); + return getBackendSrv().fetch(req); } }