|
|
@ -2,11 +2,12 @@ import { |
|
|
|
CoreApp, |
|
|
|
CoreApp, |
|
|
|
DataFrame, |
|
|
|
DataFrame, |
|
|
|
DataQueryError, |
|
|
|
DataQueryError, |
|
|
|
DataQueryRequest, |
|
|
|
getDefaultTimeRange, |
|
|
|
DataSourceApi, |
|
|
|
DataSourceApi, |
|
|
|
dateTime, |
|
|
|
dateTime, |
|
|
|
LoadingState, |
|
|
|
LoadingState, |
|
|
|
PanelData, |
|
|
|
PanelData, |
|
|
|
|
|
|
|
DataQueryRequest, |
|
|
|
} from '@grafana/data'; |
|
|
|
} from '@grafana/data'; |
|
|
|
import { MetaAnalyticsEventName, reportMetaAnalytics } from '@grafana/runtime'; |
|
|
|
import { MetaAnalyticsEventName, reportMetaAnalytics } from '@grafana/runtime'; |
|
|
|
|
|
|
|
|
|
|
@ -84,155 +85,196 @@ const multipleDataframesWithSameRefId = [ |
|
|
|
}, |
|
|
|
}, |
|
|
|
]; |
|
|
|
]; |
|
|
|
|
|
|
|
|
|
|
|
function getTestData(requestApp: string, series: DataFrame[] = []): PanelData { |
|
|
|
function getTestData( |
|
|
|
|
|
|
|
overrides: Partial<DataQueryRequest> = {}, |
|
|
|
|
|
|
|
series?: DataFrame[], |
|
|
|
|
|
|
|
errors?: DataQueryError[] |
|
|
|
|
|
|
|
): PanelData { |
|
|
|
const now = dateTime(); |
|
|
|
const now = dateTime(); |
|
|
|
return { |
|
|
|
return { |
|
|
|
request: { |
|
|
|
request: { |
|
|
|
app: requestApp, |
|
|
|
app: CoreApp.Dashboard, |
|
|
|
panelId: 2, |
|
|
|
|
|
|
|
startTime: now.unix(), |
|
|
|
startTime: now.unix(), |
|
|
|
endTime: now.add(1, 's').unix(), |
|
|
|
endTime: now.add(1, 's').unix(), |
|
|
|
} as DataQueryRequest, |
|
|
|
interval: '1s', |
|
|
|
series, |
|
|
|
intervalMs: 1000, |
|
|
|
state: LoadingState.Done, |
|
|
|
range: getDefaultTimeRange(), |
|
|
|
timeRange: { |
|
|
|
requestId: '1', |
|
|
|
from: dateTime(), |
|
|
|
scopedVars: {}, |
|
|
|
to: dateTime(), |
|
|
|
targets: [], |
|
|
|
raw: { from: '1h', to: 'now' }, |
|
|
|
timezone: 'utc', |
|
|
|
|
|
|
|
...overrides, |
|
|
|
}, |
|
|
|
}, |
|
|
|
}; |
|
|
|
series: series || [], |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function getTestDataForExplore(requestApp: string, series: DataFrame[] = []): PanelData { |
|
|
|
|
|
|
|
const now = dateTime(); |
|
|
|
|
|
|
|
const error: DataQueryError = { message: 'test error' }; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return { |
|
|
|
|
|
|
|
request: { |
|
|
|
|
|
|
|
app: requestApp, |
|
|
|
|
|
|
|
startTime: now.unix(), |
|
|
|
|
|
|
|
endTime: now.add(1, 's').unix(), |
|
|
|
|
|
|
|
} as DataQueryRequest, |
|
|
|
|
|
|
|
series, |
|
|
|
|
|
|
|
state: LoadingState.Done, |
|
|
|
state: LoadingState.Done, |
|
|
|
timeRange: { |
|
|
|
timeRange: getDefaultTimeRange(), |
|
|
|
from: dateTime(), |
|
|
|
errors, |
|
|
|
to: dateTime(), |
|
|
|
|
|
|
|
raw: { from: '1h', to: 'now' }, |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
error: error, |
|
|
|
|
|
|
|
}; |
|
|
|
}; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
describe('emitDataRequestEvent - from a dashboard panel', () => { |
|
|
|
describe('emitDataRequestEvent', () => { |
|
|
|
it('Should report meta analytics', () => { |
|
|
|
describe('From a dashboard panel', () => { |
|
|
|
const data = getTestData(CoreApp.Dashboard); |
|
|
|
it('Should report meta analytics', () => { |
|
|
|
emitDataRequestEvent(datasource)(data); |
|
|
|
const data = getTestData({ |
|
|
|
|
|
|
|
|
|
|
|
expect(reportMetaAnalytics).toBeCalledTimes(1); |
|
|
|
|
|
|
|
expect(reportMetaAnalytics).toBeCalledWith( |
|
|
|
|
|
|
|
expect.objectContaining({ |
|
|
|
|
|
|
|
eventName: MetaAnalyticsEventName.DataRequest, |
|
|
|
|
|
|
|
datasourceName: datasource.name, |
|
|
|
|
|
|
|
datasourceUid: datasource.uid, |
|
|
|
|
|
|
|
datasourceType: datasource.type, |
|
|
|
|
|
|
|
source: 'dashboard', |
|
|
|
|
|
|
|
panelId: 2, |
|
|
|
panelId: 2, |
|
|
|
dashboardUid: 'test', // from dashboard srv
|
|
|
|
}); |
|
|
|
dataSize: 0, |
|
|
|
emitDataRequestEvent(datasource)(data); |
|
|
|
duration: 1, |
|
|
|
|
|
|
|
totalQueries: 0, |
|
|
|
|
|
|
|
cachedQueries: 0, |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
it('Should report meta analytics with counts for cached and total queries', () => { |
|
|
|
expect(reportMetaAnalytics).toBeCalledTimes(1); |
|
|
|
const data = getTestData(CoreApp.Dashboard, partiallyCachedSeries); |
|
|
|
expect(reportMetaAnalytics).toBeCalledWith( |
|
|
|
emitDataRequestEvent(datasource)(data); |
|
|
|
expect.objectContaining({ |
|
|
|
|
|
|
|
eventName: MetaAnalyticsEventName.DataRequest, |
|
|
|
expect(reportMetaAnalytics).toBeCalledTimes(1); |
|
|
|
datasourceName: datasource.name, |
|
|
|
expect(reportMetaAnalytics).toBeCalledWith( |
|
|
|
datasourceUid: datasource.uid, |
|
|
|
expect.objectContaining({ |
|
|
|
datasourceType: datasource.type, |
|
|
|
eventName: MetaAnalyticsEventName.DataRequest, |
|
|
|
source: CoreApp.Dashboard, |
|
|
|
datasourceName: datasource.name, |
|
|
|
panelId: 2, |
|
|
|
datasourceUid: datasource.uid, |
|
|
|
dashboardUid: 'test', // from dashboard srv
|
|
|
|
datasourceType: datasource.type, |
|
|
|
dataSize: 0, |
|
|
|
source: 'dashboard', |
|
|
|
duration: 1, |
|
|
|
panelId: 2, |
|
|
|
totalQueries: 0, |
|
|
|
dashboardUid: 'test', |
|
|
|
cachedQueries: 0, |
|
|
|
dataSize: 2, |
|
|
|
}) |
|
|
|
duration: 1, |
|
|
|
); |
|
|
|
totalQueries: 2, |
|
|
|
}); |
|
|
|
cachedQueries: 1, |
|
|
|
|
|
|
|
}) |
|
|
|
it('Should report meta analytics with counts for cached and total queries', () => { |
|
|
|
); |
|
|
|
const data = getTestData( |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
panelId: 2, |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
partiallyCachedSeries |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
emitDataRequestEvent(datasource)(data); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
expect(reportMetaAnalytics).toBeCalledTimes(1); |
|
|
|
|
|
|
|
expect(reportMetaAnalytics).toBeCalledWith( |
|
|
|
|
|
|
|
expect.objectContaining({ |
|
|
|
|
|
|
|
eventName: MetaAnalyticsEventName.DataRequest, |
|
|
|
|
|
|
|
datasourceName: datasource.name, |
|
|
|
|
|
|
|
datasourceUid: datasource.uid, |
|
|
|
|
|
|
|
datasourceType: datasource.type, |
|
|
|
|
|
|
|
source: CoreApp.Dashboard, |
|
|
|
|
|
|
|
panelId: 2, |
|
|
|
|
|
|
|
dashboardUid: 'test', |
|
|
|
|
|
|
|
dataSize: 2, |
|
|
|
|
|
|
|
duration: 1, |
|
|
|
|
|
|
|
totalQueries: 2, |
|
|
|
|
|
|
|
cachedQueries: 1, |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
it('Should report meta analytics with counts for cached and total queries when same refId spread across multiple DataFrames', () => { |
|
|
|
|
|
|
|
const data = getTestData( |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
panelId: 2, |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
multipleDataframesWithSameRefId |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
emitDataRequestEvent(datasource)(data); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
expect(reportMetaAnalytics).toBeCalledTimes(1); |
|
|
|
|
|
|
|
expect(reportMetaAnalytics).toBeCalledWith( |
|
|
|
|
|
|
|
expect.objectContaining({ |
|
|
|
|
|
|
|
eventName: MetaAnalyticsEventName.DataRequest, |
|
|
|
|
|
|
|
datasourceName: datasource.name, |
|
|
|
|
|
|
|
datasourceUid: datasource.uid, |
|
|
|
|
|
|
|
datasourceType: datasource.type, |
|
|
|
|
|
|
|
source: CoreApp.Dashboard, |
|
|
|
|
|
|
|
panelId: 2, |
|
|
|
|
|
|
|
dashboardUid: 'test', // from dashboard srv
|
|
|
|
|
|
|
|
dataSize: 2, |
|
|
|
|
|
|
|
duration: 1, |
|
|
|
|
|
|
|
totalQueries: 1, |
|
|
|
|
|
|
|
cachedQueries: 1, |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
it('Should not report meta analytics twice if the request receives multiple responses', () => { |
|
|
|
|
|
|
|
const data = getTestData(); |
|
|
|
|
|
|
|
const fn = emitDataRequestEvent(datasource); |
|
|
|
|
|
|
|
fn(data); |
|
|
|
|
|
|
|
fn(data); |
|
|
|
|
|
|
|
expect(reportMetaAnalytics).toBeCalledTimes(1); |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
it('Should not report meta analytics in edit mode', () => { |
|
|
|
|
|
|
|
mockGetUrlSearchParams.mockImplementationOnce(() => { |
|
|
|
|
|
|
|
return { editPanel: 2 }; |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
const data = getTestData(); |
|
|
|
|
|
|
|
emitDataRequestEvent(datasource)(data); |
|
|
|
|
|
|
|
expect(reportMetaAnalytics).not.toBeCalled(); |
|
|
|
|
|
|
|
}); |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
it('Should report meta analytics with counts for cached and total queries when same refId spread across multiple DataFrames', () => { |
|
|
|
// Previously we filtered out Explore and Correlations events due to too many errors being generated while a user is building a query
|
|
|
|
const data = getTestData(CoreApp.Dashboard, multipleDataframesWithSameRefId); |
|
|
|
// This tests that we send an event for both queries but do not record errors
|
|
|
|
emitDataRequestEvent(datasource)(data); |
|
|
|
describe('From Explore', () => { |
|
|
|
|
|
|
|
const data = getTestData( |
|
|
|
expect(reportMetaAnalytics).toBeCalledTimes(1); |
|
|
|
{ |
|
|
|
expect(reportMetaAnalytics).toBeCalledWith( |
|
|
|
app: CoreApp.Explore, |
|
|
|
expect.objectContaining({ |
|
|
|
}, |
|
|
|
eventName: MetaAnalyticsEventName.DataRequest, |
|
|
|
undefined, |
|
|
|
datasourceName: datasource.name, |
|
|
|
[{ message: 'test error' }] |
|
|
|
datasourceUid: datasource.uid, |
|
|
|
|
|
|
|
datasourceType: datasource.type, |
|
|
|
|
|
|
|
source: 'dashboard', |
|
|
|
|
|
|
|
panelId: 2, |
|
|
|
|
|
|
|
dashboardUid: 'test', // from dashboard srv
|
|
|
|
|
|
|
|
dataSize: 2, |
|
|
|
|
|
|
|
duration: 1, |
|
|
|
|
|
|
|
totalQueries: 1, |
|
|
|
|
|
|
|
cachedQueries: 1, |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
); |
|
|
|
); |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
it('Should not report meta analytics twice if the request receives multiple responses', () => { |
|
|
|
it('Should report meta analytics', () => { |
|
|
|
const data = getTestData(CoreApp.Dashboard); |
|
|
|
emitDataRequestEvent(datasource)(data); |
|
|
|
const fn = emitDataRequestEvent(datasource); |
|
|
|
|
|
|
|
fn(data); |
|
|
|
|
|
|
|
fn(data); |
|
|
|
|
|
|
|
expect(reportMetaAnalytics).toBeCalledTimes(1); |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
it('Should not report meta analytics in edit mode', () => { |
|
|
|
expect(reportMetaAnalytics).toBeCalledTimes(1); |
|
|
|
mockGetUrlSearchParams.mockImplementationOnce(() => { |
|
|
|
expect(reportMetaAnalytics).toBeCalledWith( |
|
|
|
return { editPanel: 2 }; |
|
|
|
expect.objectContaining({ |
|
|
|
|
|
|
|
eventName: MetaAnalyticsEventName.DataRequest, |
|
|
|
|
|
|
|
source: CoreApp.Explore, |
|
|
|
|
|
|
|
datasourceName: 'test', |
|
|
|
|
|
|
|
datasourceUid: 'test', |
|
|
|
|
|
|
|
dataSize: 0, |
|
|
|
|
|
|
|
duration: 1, |
|
|
|
|
|
|
|
totalQueries: 0, |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
it('Should not report errors', () => { |
|
|
|
|
|
|
|
emitDataRequestEvent(datasource)(data); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
expect(reportMetaAnalytics).toBeCalledTimes(1); |
|
|
|
|
|
|
|
expect(reportMetaAnalytics).toBeCalledWith(expect.not.objectContaining({ error: 'test error' })); |
|
|
|
}); |
|
|
|
}); |
|
|
|
const data = getTestData(CoreApp.Dashboard); |
|
|
|
|
|
|
|
emitDataRequestEvent(datasource)(data); |
|
|
|
|
|
|
|
expect(reportMetaAnalytics).not.toBeCalled(); |
|
|
|
|
|
|
|
}); |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Previously we filtered out Explore events due to too many errors being generated while a user is building a query
|
|
|
|
// Previously we filtered out Explore and Correlations events due to too many errors being generated while a user is building a query
|
|
|
|
// This tests that we send an event for Explore queries but do not record errors
|
|
|
|
// This tests that we send an event for both queries but do not record errors
|
|
|
|
describe('emitDataRequestEvent - from Explore', () => { |
|
|
|
describe('From Correlations', () => { |
|
|
|
it('Should report meta analytics', () => { |
|
|
|
const data = getTestData( |
|
|
|
const data = getTestDataForExplore(CoreApp.Explore); |
|
|
|
{ |
|
|
|
emitDataRequestEvent(datasource)(data); |
|
|
|
app: CoreApp.Correlations, |
|
|
|
|
|
|
|
}, |
|
|
|
expect(reportMetaAnalytics).toBeCalledTimes(1); |
|
|
|
undefined, |
|
|
|
expect(reportMetaAnalytics).toBeCalledWith( |
|
|
|
[{ message: 'some error' }] |
|
|
|
expect.objectContaining({ |
|
|
|
|
|
|
|
eventName: MetaAnalyticsEventName.DataRequest, |
|
|
|
|
|
|
|
source: 'explore', |
|
|
|
|
|
|
|
datasourceName: 'test', |
|
|
|
|
|
|
|
datasourceUid: 'test', |
|
|
|
|
|
|
|
dataSize: 0, |
|
|
|
|
|
|
|
duration: 1, |
|
|
|
|
|
|
|
totalQueries: 0, |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
); |
|
|
|
); |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
describe('emitDataRequestEvent - from Explore', () => { |
|
|
|
it('Should report meta analytics', () => { |
|
|
|
|
|
|
|
emitDataRequestEvent(datasource)(data); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
expect(reportMetaAnalytics).toBeCalledTimes(1); |
|
|
|
|
|
|
|
expect(reportMetaAnalytics).toBeCalledWith( |
|
|
|
|
|
|
|
expect.objectContaining({ |
|
|
|
|
|
|
|
eventName: MetaAnalyticsEventName.DataRequest, |
|
|
|
|
|
|
|
source: CoreApp.Correlations, |
|
|
|
|
|
|
|
datasourceName: 'test', |
|
|
|
|
|
|
|
datasourceUid: 'test', |
|
|
|
|
|
|
|
dataSize: 0, |
|
|
|
|
|
|
|
duration: 1, |
|
|
|
|
|
|
|
totalQueries: 0, |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
it('Should not report errors', () => { |
|
|
|
it('Should not report errors', () => { |
|
|
|
const data = getTestDataForExplore(CoreApp.Explore); |
|
|
|
|
|
|
|
emitDataRequestEvent(datasource)(data); |
|
|
|
emitDataRequestEvent(datasource)(data); |
|
|
|
|
|
|
|
|
|
|
|
expect(reportMetaAnalytics).toBeCalledTimes(1); |
|
|
|
expect(reportMetaAnalytics).toBeCalledTimes(1); |
|
|
|