mirror of
https://github.com/grafana/grafana.git
synced 2025-01-26 16:27:02 -06:00
DataFrame: Add cached response notice for X-Cache: HIT header (#45564)
This commit is contained in:
parent
af2d19b02e
commit
01df00fd0f
@ -1,6 +1,6 @@
|
||||
import { DataQuery, toDataFrameDTO, DataFrame } from '@grafana/data';
|
||||
import { FetchError, FetchResponse } from 'src/services';
|
||||
import { BackendDataSourceResponse, toDataQueryResponse, toTestingStatus } from './queryResponse';
|
||||
import { BackendDataSourceResponse, cachedResponseNotice, toDataQueryResponse, toTestingStatus } from './queryResponse';
|
||||
|
||||
const resp = {
|
||||
data: {
|
||||
@ -277,6 +277,55 @@ describe('Query Response parser', () => {
|
||||
expect(ids).toEqual(['A', 'B']);
|
||||
});
|
||||
|
||||
describe('Cache notice', () => {
|
||||
let resp: any;
|
||||
|
||||
beforeEach(() => {
|
||||
resp = {
|
||||
url: '',
|
||||
type: 'basic',
|
||||
config: { url: '' },
|
||||
status: 200,
|
||||
statusText: 'OK',
|
||||
ok: true,
|
||||
redirected: false,
|
||||
headers: new Headers(),
|
||||
data: {
|
||||
results: {
|
||||
A: { frames: [{ schema: { fields: [] } }] },
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
test('adds notice for responses with X-Cache: HIT header', () => {
|
||||
const queries: DataQuery[] = [{ refId: 'A' }];
|
||||
resp.headers.set('X-Cache', 'HIT');
|
||||
expect(toDataQueryResponse(resp, queries).data[0].meta.notices).toStrictEqual([cachedResponseNotice]);
|
||||
});
|
||||
|
||||
test('does not remove existing notices', () => {
|
||||
const queries: DataQuery[] = [{ refId: 'A' }];
|
||||
resp.headers.set('X-Cache', 'HIT');
|
||||
resp.data.results.A.frames[0].schema.meta = { notices: [{ severity: 'info', text: 'Example' }] };
|
||||
expect(toDataQueryResponse(resp, queries).data[0].meta.notices).toStrictEqual([
|
||||
{ severity: 'info', text: 'Example' },
|
||||
cachedResponseNotice,
|
||||
]);
|
||||
});
|
||||
|
||||
test('does not add notice for responses with X-Cache: MISS header', () => {
|
||||
const queries: DataQuery[] = [{ refId: 'A' }];
|
||||
resp.headers.set('X-Cache', 'MISS');
|
||||
expect(toDataQueryResponse(resp, queries).data[0].meta?.notices).toBeUndefined();
|
||||
});
|
||||
|
||||
test('does not add notice for responses without X-Cache header', () => {
|
||||
const queries: DataQuery[] = [{ refId: 'A' }];
|
||||
expect(toDataQueryResponse(resp, queries).data[0].meta?.notices).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
test('resultWithError', () => {
|
||||
// Generated from:
|
||||
// qdr.Responses[q.GetRefID()] = backend.DataResponse{
|
||||
|
@ -12,10 +12,13 @@ import {
|
||||
DataQuery,
|
||||
DataFrameJSON,
|
||||
dataFrameFromJSON,
|
||||
QueryResultMetaNotice,
|
||||
} from '@grafana/data';
|
||||
import { FetchError, FetchResponse } from '../services';
|
||||
import { toDataQueryError } from './toDataQueryError';
|
||||
|
||||
export const cachedResponseNotice: QueryResultMetaNotice = { severity: 'info', text: 'Cached response' };
|
||||
|
||||
/**
|
||||
* Single response object from a backend data source. Properties are optional but response should contain at least
|
||||
* an error or a some data (but can contain both). Main way to send data is with dataframes attribute as series and
|
||||
@ -62,6 +65,7 @@ export function toDataQueryResponse(
|
||||
if ((res as FetchResponse).data?.results) {
|
||||
const results = (res as FetchResponse).data.results;
|
||||
const refIDs = queries?.length ? queries.map((q) => q.refId) : Object.keys(results);
|
||||
const cachedResponse = isCachedResponse(res as FetchResponse);
|
||||
const data: DataResponse[] = [];
|
||||
|
||||
for (const refId of refIDs) {
|
||||
@ -85,7 +89,10 @@ export function toDataQueryResponse(
|
||||
}
|
||||
|
||||
if (dr.frames?.length) {
|
||||
for (const js of dr.frames) {
|
||||
for (let js of dr.frames) {
|
||||
if (cachedResponse) {
|
||||
js = addCacheNotice(js);
|
||||
}
|
||||
const df = dataFrameFromJSON(js);
|
||||
if (!df.refId) {
|
||||
df.refId = dr.refId;
|
||||
@ -128,6 +135,28 @@ export function toDataQueryResponse(
|
||||
return rsp;
|
||||
}
|
||||
|
||||
function isCachedResponse(res: FetchResponse<BackendDataSourceResponse | undefined>): boolean {
|
||||
const headers = res?.headers;
|
||||
if (!headers || !headers.get) {
|
||||
return false;
|
||||
}
|
||||
return headers.get('X-Cache') === 'HIT';
|
||||
}
|
||||
|
||||
function addCacheNotice(frame: DataFrameJSON): DataFrameJSON {
|
||||
return {
|
||||
...frame,
|
||||
schema: {
|
||||
...frame.schema,
|
||||
fields: [...(frame.schema?.fields ?? [])],
|
||||
meta: {
|
||||
...frame.schema?.meta,
|
||||
notices: [...(frame.schema?.meta?.notices ?? []), cachedResponseNotice],
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Data sources using api/ds/query to test data sources can use this function to
|
||||
* handle errors and convert them to TestingStatus object.
|
||||
|
Loading…
Reference in New Issue
Block a user