mirror of https://github.com/grafana/grafana
CloudMonitoring: Move data manipulation to backend (#41379)
parent
a45e4ff73f
commit
fc3d3ff003
@ -1,79 +0,0 @@ |
||||
import { of } from 'rxjs'; |
||||
|
||||
import Api from './api'; |
||||
import { backendSrv } from 'app/core/services/backend_srv'; // will use the version in __mocks__
|
||||
import { createFetchResponse } from 'test/helpers/createFetchResponse'; |
||||
|
||||
jest.mock('@grafana/runtime', () => ({ |
||||
...((jest.requireActual('@grafana/runtime') as unknown) as object), |
||||
getBackendSrv: () => backendSrv, |
||||
})); |
||||
|
||||
const response = [ |
||||
{ label: 'test1', value: 'test1' }, |
||||
{ label: 'test2', value: 'test2' }, |
||||
]; |
||||
|
||||
type Args = { path?: string; options?: any; response?: any; cache?: any }; |
||||
|
||||
async function getTestContext({ path = 'some-resource', options = {}, response = {}, cache }: Args = {}) { |
||||
jest.clearAllMocks(); |
||||
|
||||
const fetchMock = jest.spyOn(backendSrv, 'fetch'); |
||||
|
||||
fetchMock.mockImplementation((options: any) => { |
||||
const data = { [options.url.match(/([^\/]*)\/*$/)![1].split('?')[0]]: response }; |
||||
return of(createFetchResponse(data)); |
||||
}); |
||||
|
||||
const api = new Api('/cloudmonitoring/'); |
||||
|
||||
if (cache) { |
||||
api.cache[path] = cache; |
||||
} |
||||
|
||||
const res = await api.get(path, options); |
||||
|
||||
return { res, api, fetchMock }; |
||||
} |
||||
|
||||
describe('api', () => { |
||||
describe('when resource was cached', () => { |
||||
test.each(['some-resource', 'some-resource?some=param', 'test/some-resource?param'])( |
||||
'should return cached value and not load from source', |
||||
async (path) => { |
||||
const { res, api, fetchMock } = await getTestContext({ path, cache: response }); |
||||
|
||||
expect(res).toEqual(response); |
||||
expect(api.cache[path]).toEqual(response); |
||||
expect(fetchMock).not.toHaveBeenCalled(); |
||||
} |
||||
); |
||||
}); |
||||
|
||||
describe('when resource was not cached', () => { |
||||
test.each(['some-resource', 'some-resource?some=param', 'test/some-resource?param'])( |
||||
'should return from source and not from cache', |
||||
async (path) => { |
||||
const { res, api, fetchMock } = await getTestContext({ path, response }); |
||||
|
||||
expect(res).toEqual(response); |
||||
expect(api.cache[path]).toEqual(response); |
||||
expect(fetchMock).toHaveBeenCalled(); |
||||
} |
||||
); |
||||
}); |
||||
|
||||
describe('when cache should be bypassed', () => { |
||||
test.each(['some-resource', 'some-resource?some=param', 'test/some-resource?param'])( |
||||
'should return from source and not from cache', |
||||
async (path) => { |
||||
const options = { useCache: false }; |
||||
const { res, fetchMock } = await getTestContext({ path, response, cache: response, options }); |
||||
|
||||
expect(res).toEqual(response); |
||||
expect(fetchMock).toHaveBeenCalled(); |
||||
} |
||||
); |
||||
}); |
||||
}); |
||||
@ -1,87 +0,0 @@ |
||||
import { lastValueFrom, Observable, of } from 'rxjs'; |
||||
import { catchError, map } from 'rxjs/operators'; |
||||
import { SelectableValue } from '@grafana/data'; |
||||
import { FetchResponse, getBackendSrv } from '@grafana/runtime'; |
||||
|
||||
import appEvents from 'app/core/app_events'; |
||||
import { CoreEvents } from 'app/types'; |
||||
import { formatCloudMonitoringError } from './functions'; |
||||
import { MetricDescriptor } from './types'; |
||||
|
||||
export interface PostResponse { |
||||
results: Record<string, any>; |
||||
} |
||||
|
||||
interface Options { |
||||
responseMap?: (res: any) => SelectableValue<string> | MetricDescriptor; |
||||
baseUrl?: string; |
||||
useCache?: boolean; |
||||
} |
||||
|
||||
export default class Api { |
||||
cache: { [key: string]: Array<SelectableValue<string>> }; |
||||
defaultOptions: Options; |
||||
|
||||
constructor(private baseUrl: string) { |
||||
this.cache = {}; |
||||
this.defaultOptions = { |
||||
useCache: true, |
||||
responseMap: (res: any) => res, |
||||
baseUrl: this.baseUrl, |
||||
}; |
||||
} |
||||
|
||||
get(path: string, options?: Options): Promise<Array<SelectableValue<string>> | MetricDescriptor[]> { |
||||
const { useCache, responseMap, baseUrl } = { ...this.defaultOptions, ...options }; |
||||
|
||||
if (useCache && this.cache[path]) { |
||||
return Promise.resolve(this.cache[path]); |
||||
} |
||||
|
||||
return lastValueFrom( |
||||
getBackendSrv() |
||||
.fetch<Record<string, any>>({ |
||||
url: baseUrl + path, |
||||
method: 'GET', |
||||
}) |
||||
.pipe( |
||||
map((response) => { |
||||
const responsePropName = path.match(/([^\/]*)\/*$/)![1].split('?')[0]; |
||||
let res = []; |
||||
if (response && response.data && response.data[responsePropName]) { |
||||
res = response.data[responsePropName].map(responseMap); |
||||
} |
||||
|
||||
if (useCache) { |
||||
this.cache[path] = res; |
||||
} |
||||
|
||||
return res; |
||||
}), |
||||
catchError((error) => { |
||||
appEvents.emit(CoreEvents.dsRequestError, { |
||||
error: { data: { error: formatCloudMonitoringError(error) } }, |
||||
}); |
||||
return of([]); |
||||
}) |
||||
) |
||||
); |
||||
} |
||||
|
||||
post(data: Record<string, any>): Observable<FetchResponse<PostResponse>> { |
||||
return getBackendSrv().fetch<PostResponse>({ |
||||
url: '/api/ds/query', |
||||
method: 'POST', |
||||
data, |
||||
}); |
||||
} |
||||
|
||||
test(projectName: string) { |
||||
return lastValueFrom( |
||||
getBackendSrv().fetch<any>({ |
||||
url: `${this.baseUrl}${projectName}/metricDescriptors`, |
||||
method: 'GET', |
||||
}) |
||||
); |
||||
} |
||||
} |
||||
Loading…
Reference in new issue