mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
* Refactor: Removes replaceUrl from actions * Refactor: Moves saveState thunk to epic * Refactor: Moves thunks to epics * Wip: removes resulttype and queries once * Refactor: LiveTailing uses observer in query * Refactor: Creates epics folder for epics and move back actioncreators * Tests: Adds tests for epics and reducer * Fix: Checks for undefined as well * Refactor: Cleans up previous live tailing implementation * Chore: merge with master * Fix: Fixes url issuses and prom graph in Panels * Refactor: Removes supportsStreaming and adds sockets to DataSourcePluginMeta instead * Refactor: Changes the way we create TimeSeries * Refactor: Renames sockets to streaming * Refactor: Changes the way Explore does incremental updates * Refactor: Removes unused method * Refactor: Adds back Loading indication
422 lines
15 KiB
TypeScript
422 lines
15 KiB
TypeScript
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, DataQueryRequest, SeriesData, FieldType } from '@grafana/ui';
|
|
|
|
const testContext = () => {
|
|
const series: SeriesData[] = [
|
|
{
|
|
fields: [
|
|
{
|
|
name: 'Value',
|
|
},
|
|
{
|
|
name: 'Time',
|
|
type: FieldType.time,
|
|
unit: 'dateTimeAsIso',
|
|
},
|
|
],
|
|
rows: [],
|
|
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 = {
|
|
fields: [],
|
|
rows: [],
|
|
refId: 'A',
|
|
};
|
|
const serieB = {
|
|
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 = {
|
|
fields: [],
|
|
rows: [],
|
|
refId: 'A',
|
|
};
|
|
const serieB = {
|
|
fields: [],
|
|
rows: [],
|
|
refId: 'B',
|
|
};
|
|
const delta = [serieA, serieB];
|
|
|
|
epicTester(runQueriesBatchEpic, state)
|
|
.whenActionIsDispatched(
|
|
runQueriesBatchAction({ exploreId, queryOptions: { live: true, interval: '', maxDataPoints: 1980 } })
|
|
)
|
|
.whenQueryObserverReceivesEvent({
|
|
state: LoadingState.Done,
|
|
series: 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);
|
|
});
|
|
});
|
|
});
|
|
});
|