The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
grafana/public/app/features/explore/state/epics/runQueriesBatchEpic.test.ts

425 lines
15 KiB

import { mockExploreState } from 'test/mocks/mockExploreState';
import { epicTester } from 'test/core/redux/epicTester';
import { runQueriesBatchEpic } from './runQueriesBatchEpic';
import {
runQueriesBatchAction,
queryStartAction,
historyUpdatedAction,
processQueryResultsAction,
processQueryErrorsAction,
limitMessageRatePayloadAction,
resetExploreAction,
updateDatasourceInstanceAction,
changeRefreshIntervalAction,
clearQueriesAction,
stateSaveAction,
} from '../actionTypes';
import { LoadingState, DataFrame, FieldType, DataFrameHelper } from '@grafana/data';
import { DataQueryRequest } from '@grafana/ui';
const testContext = () => {
const series: DataFrame[] = [
new DataFrameHelper({
fields: [
{
name: 'Value',
values: [],
},
{
name: 'Time',
type: FieldType.time,
config: {
unit: 'dateTimeAsIso',
},
values: [],
},
],
refId: 'A',
}),
];
const response = { data: series };
return {
response,
series,
};
};
describe('runQueriesBatchEpic', () => {
let originalDateNow = Date.now;
beforeEach(() => {
originalDateNow = Date.now;
Date.now = () => 1337;
});
afterEach(() => {
Date.now = originalDateNow;
});
describe('when runQueriesBatchAction is dispatched', () => {
describe('and query targets are not live', () => {
describe('and query is successful', () => {
it('then correct actions are dispatched', () => {
const { response, series } = testContext();
const { exploreId, state, history, datasourceId } = mockExploreState();
epicTester(runQueriesBatchEpic, state)
.whenActionIsDispatched(
runQueriesBatchAction({ exploreId, queryOptions: { live: false, interval: '', maxDataPoints: 1980 } })
)
.whenQueryReceivesResponse(response)
.thenResultingActionsEqual(
queryStartAction({ exploreId }),
historyUpdatedAction({ exploreId, history }),
processQueryResultsAction({
exploreId,
delta: null,
series,
latency: 0,
datasourceId,
loadingState: LoadingState.Done,
}),
stateSaveAction()
);
});
});
describe('and query is not successful', () => {
it('then correct actions are dispatched', () => {
const error = {
message: 'Error parsing line x',
};
const { exploreId, state, datasourceId } = mockExploreState();
epicTester(runQueriesBatchEpic, state)
.whenActionIsDispatched(
runQueriesBatchAction({ exploreId, queryOptions: { live: false, interval: '', maxDataPoints: 1980 } })
)
.whenQueryThrowsError(error)
.thenResultingActionsEqual(
queryStartAction({ exploreId }),
processQueryErrorsAction({ exploreId, response: error, datasourceId })
);
});
});
});
describe('and query targets are live', () => {
describe('and state equals Streaming', () => {
it('then correct actions are dispatched', () => {
const { exploreId, state, datasourceId } = mockExploreState();
const unsubscribe = jest.fn();
const serieA: any = {
fields: [],
rows: [],
refId: 'A',
};
const serieB: any = {
fields: [],
rows: [],
refId: 'B',
};
epicTester(runQueriesBatchEpic, state)
.whenActionIsDispatched(
runQueriesBatchAction({ exploreId, queryOptions: { live: true, interval: '', maxDataPoints: 1980 } })
)
.whenQueryObserverReceivesEvent({
state: LoadingState.Streaming,
delta: [serieA],
key: 'some key',
request: {} as DataQueryRequest,
unsubscribe,
})
.whenQueryObserverReceivesEvent({
state: LoadingState.Streaming,
delta: [serieB],
key: 'some key',
request: {} as DataQueryRequest,
unsubscribe,
})
.thenResultingActionsEqual(
queryStartAction({ exploreId }),
limitMessageRatePayloadAction({ exploreId, series: [serieA], datasourceId }),
limitMessageRatePayloadAction({ exploreId, series: [serieB], datasourceId })
);
});
});
describe('and state equals Error', () => {
it('then correct actions are dispatched', () => {
const { exploreId, state, datasourceId } = mockExploreState();
const unsubscribe = jest.fn();
const error = { message: 'Something went really wrong!' };
epicTester(runQueriesBatchEpic, state)
.whenActionIsDispatched(
runQueriesBatchAction({ exploreId, queryOptions: { live: true, interval: '', maxDataPoints: 1980 } })
)
.whenQueryObserverReceivesEvent({
state: LoadingState.Error,
error,
key: 'some key',
request: {} as DataQueryRequest,
unsubscribe,
})
.thenResultingActionsEqual(
queryStartAction({ exploreId }),
processQueryErrorsAction({ exploreId, response: error, datasourceId })
);
});
});
describe('and state equals Done', () => {
it('then correct actions are dispatched', () => {
const { exploreId, state, datasourceId, history } = mockExploreState();
const unsubscribe = jest.fn();
const serieA: any = {
fields: [],
rows: [],
refId: 'A',
};
const serieB: any = {
fields: [],
rows: [],
refId: 'B',
};
const delta = [serieA, serieB];
epicTester(runQueriesBatchEpic, state)
.whenActionIsDispatched(
runQueriesBatchAction({ exploreId, queryOptions: { live: true, interval: '', maxDataPoints: 1980 } })
)
.whenQueryObserverReceivesEvent({
state: LoadingState.Done,
data: null,
delta,
key: 'some key',
request: {} as DataQueryRequest,
unsubscribe,
})
.thenResultingActionsEqual(
queryStartAction({ exploreId }),
historyUpdatedAction({ exploreId, history }),
processQueryResultsAction({
exploreId,
delta,
series: null,
latency: 0,
datasourceId,
loadingState: LoadingState.Done,
}),
stateSaveAction()
);
});
});
});
describe('and another runQueriesBatchAction is dispatched', () => {
it('then the observable should be unsubscribed', () => {
const { response, series } = testContext();
const { exploreId, state, history, datasourceId } = mockExploreState();
const unsubscribe = jest.fn();
epicTester(runQueriesBatchEpic, state)
.whenActionIsDispatched(
runQueriesBatchAction({ exploreId, queryOptions: { live: false, interval: '', maxDataPoints: 1980 } }) // first observable
)
.whenQueryReceivesResponse(response)
.whenQueryObserverReceivesEvent({
key: 'some key',
request: {} as DataQueryRequest,
state: LoadingState.Loading, // fake just to setup and test unsubscribe
unsubscribe,
})
.whenActionIsDispatched(
// second observable and unsubscribes the first observable
runQueriesBatchAction({ exploreId, queryOptions: { live: true, interval: '', maxDataPoints: 800 } })
)
.whenQueryReceivesResponse(response)
.whenQueryObserverReceivesEvent({
key: 'some key',
request: {} as DataQueryRequest,
state: LoadingState.Loading, // fake just to setup and test unsubscribe
unsubscribe,
})
.thenResultingActionsEqual(
queryStartAction({ exploreId }), // output from first observable
historyUpdatedAction({ exploreId, history }), // output from first observable
processQueryResultsAction({
exploreId,
delta: null,
series,
latency: 0,
datasourceId,
loadingState: LoadingState.Done,
}),
stateSaveAction(),
// output from first observable
queryStartAction({ exploreId }), // output from second observable
historyUpdatedAction({ exploreId, history }), // output from second observable
processQueryResultsAction({
exploreId,
delta: null,
series,
latency: 0,
datasourceId,
loadingState: LoadingState.Done,
}),
stateSaveAction()
// output from second observable
);
expect(unsubscribe).toBeCalledTimes(1); // first unsubscribe should be called but not second as that isn't unsubscribed
});
});
describe('and resetExploreAction is dispatched', () => {
it('then the observable should be unsubscribed', () => {
const { response, series } = testContext();
const { exploreId, state, history, datasourceId } = mockExploreState();
const unsubscribe = jest.fn();
epicTester(runQueriesBatchEpic, state)
.whenActionIsDispatched(
runQueriesBatchAction({ exploreId, queryOptions: { live: false, interval: '', maxDataPoints: 1980 } })
)
.whenQueryReceivesResponse(response)
.whenQueryObserverReceivesEvent({
key: 'some key',
request: {} as DataQueryRequest,
state: LoadingState.Loading, // fake just to setup and test unsubscribe
unsubscribe,
})
.whenActionIsDispatched(resetExploreAction()) // unsubscribes the observable
.whenQueryReceivesResponse(response) // new updates will not reach anywhere
.thenResultingActionsEqual(
queryStartAction({ exploreId }),
historyUpdatedAction({ exploreId, history }),
processQueryResultsAction({
exploreId,
delta: null,
series,
latency: 0,
datasourceId,
loadingState: LoadingState.Done,
}),
stateSaveAction()
);
expect(unsubscribe).toBeCalledTimes(1);
});
});
describe('and updateDatasourceInstanceAction is dispatched', () => {
it('then the observable should be unsubscribed', () => {
const { response, series } = testContext();
const { exploreId, state, history, datasourceId, datasourceInstance } = mockExploreState();
const unsubscribe = jest.fn();
epicTester(runQueriesBatchEpic, state)
.whenActionIsDispatched(
runQueriesBatchAction({ exploreId, queryOptions: { live: false, interval: '', maxDataPoints: 1980 } })
)
.whenQueryReceivesResponse(response)
.whenQueryObserverReceivesEvent({
key: 'some key',
request: {} as DataQueryRequest,
state: LoadingState.Loading, // fake just to setup and test unsubscribe
unsubscribe,
})
.whenActionIsDispatched(updateDatasourceInstanceAction({ exploreId, datasourceInstance })) // unsubscribes the observable
.whenQueryReceivesResponse(response) // new updates will not reach anywhere
.thenResultingActionsEqual(
queryStartAction({ exploreId }),
historyUpdatedAction({ exploreId, history }),
processQueryResultsAction({
exploreId,
delta: null,
series,
latency: 0,
datasourceId,
loadingState: LoadingState.Done,
}),
stateSaveAction()
);
expect(unsubscribe).toBeCalledTimes(1);
});
});
describe('and changeRefreshIntervalAction is dispatched', () => {
it('then the observable should be unsubscribed', () => {
const { response, series } = testContext();
const { exploreId, state, history, datasourceId } = mockExploreState();
const unsubscribe = jest.fn();
epicTester(runQueriesBatchEpic, state)
.whenActionIsDispatched(
runQueriesBatchAction({ exploreId, queryOptions: { live: false, interval: '', maxDataPoints: 1980 } })
)
.whenQueryReceivesResponse(response)
.whenQueryObserverReceivesEvent({
key: 'some key',
request: {} as DataQueryRequest,
state: LoadingState.Loading, // fake just to setup and test unsubscribe
unsubscribe,
})
.whenActionIsDispatched(changeRefreshIntervalAction({ exploreId, refreshInterval: '' })) // unsubscribes the observable
.whenQueryReceivesResponse(response) // new updates will not reach anywhere
.thenResultingActionsEqual(
queryStartAction({ exploreId }),
historyUpdatedAction({ exploreId, history }),
processQueryResultsAction({
exploreId,
delta: null,
series,
latency: 0,
datasourceId,
loadingState: LoadingState.Done,
}),
stateSaveAction()
);
expect(unsubscribe).toBeCalledTimes(1);
});
});
describe('and clearQueriesAction is dispatched', () => {
it('then the observable should be unsubscribed', () => {
const { response, series } = testContext();
const { exploreId, state, history, datasourceId } = mockExploreState();
const unsubscribe = jest.fn();
epicTester(runQueriesBatchEpic, state)
.whenActionIsDispatched(
runQueriesBatchAction({ exploreId, queryOptions: { live: false, interval: '', maxDataPoints: 1980 } })
)
.whenQueryReceivesResponse(response)
.whenQueryObserverReceivesEvent({
key: 'some key',
request: {} as DataQueryRequest,
state: LoadingState.Loading, // fake just to setup and test unsubscribe
unsubscribe,
})
.whenActionIsDispatched(clearQueriesAction({ exploreId })) // unsubscribes the observable
.whenQueryReceivesResponse(response) // new updates will not reach anywhere
.thenResultingActionsEqual(
queryStartAction({ exploreId }),
historyUpdatedAction({ exploreId, history }),
processQueryResultsAction({
exploreId,
delta: null,
series,
latency: 0,
datasourceId,
loadingState: LoadingState.Done,
}),
stateSaveAction()
);
expect(unsubscribe).toBeCalledTimes(1);
});
});
});
});