(cherry picked from commit 9305117902)
Co-authored-by: Hugo Häggmark <hugo.haggmark@grafana.com>
This commit is contained in:
co-authored by
Hugo Häggmark
parent
c11c8b0b4a
commit
5ac4ae37a2
@@ -26,30 +26,28 @@ const getTestContext = () => {
|
|||||||
|
|
||||||
const fetchMock = jest.fn().mockReturnValue(fetchResult);
|
const fetchMock = jest.fn().mockReturnValue(fetchResult);
|
||||||
const setInProgressMock = jest.fn();
|
const setInProgressMock = jest.fn();
|
||||||
const setDoneMock = jest.fn();
|
|
||||||
|
|
||||||
const queueMock: FetchQueue = ({
|
const queueMock: FetchQueue = ({
|
||||||
add: jest.fn(),
|
add: jest.fn(),
|
||||||
setInProgress: setInProgressMock,
|
setInProgress: setInProgressMock,
|
||||||
setDone: setDoneMock,
|
setDone: jest.fn(),
|
||||||
getUpdates: jest.fn(),
|
getUpdates: jest.fn(),
|
||||||
} as unknown) as FetchQueue;
|
} as unknown) as FetchQueue;
|
||||||
|
|
||||||
const responseQueue = new ResponseQueue(queueMock, fetchMock);
|
const responseQueue = new ResponseQueue(queueMock, fetchMock);
|
||||||
|
|
||||||
return { id, options, expects, fetchMock, setInProgressMock, setDoneMock, responseQueue, fetchResult };
|
return { id, options, expects, fetchMock, setInProgressMock, responseQueue, fetchResult };
|
||||||
};
|
};
|
||||||
|
|
||||||
describe('ResponseQueue', () => {
|
describe('ResponseQueue', () => {
|
||||||
describe('add', () => {
|
describe('add', () => {
|
||||||
describe('when called', () => {
|
describe('when called', () => {
|
||||||
it('then the matching fetchQueue entry should be set to inProgress', () => {
|
it('then the matching fetchQueue entry should be set to inProgress', () => {
|
||||||
const { id, options, setInProgressMock, setDoneMock, responseQueue } = getTestContext();
|
const { id, options, setInProgressMock, responseQueue } = getTestContext();
|
||||||
|
|
||||||
responseQueue.add(id, options);
|
responseQueue.add(id, options);
|
||||||
|
|
||||||
expect(setInProgressMock.mock.calls).toEqual([['id']]);
|
expect(setInProgressMock.mock.calls).toEqual([['id']]);
|
||||||
expect(setDoneMock).not.toHaveBeenCalled();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('then a response entry with correct id should be published', done => {
|
it('then a response entry with correct id should be published', done => {
|
||||||
@@ -81,14 +79,13 @@ describe('ResponseQueue', () => {
|
|||||||
|
|
||||||
describe('and when the fetch Observable is completed', () => {
|
describe('and when the fetch Observable is completed', () => {
|
||||||
it('then the matching fetchQueue entry should be set to Done', done => {
|
it('then the matching fetchQueue entry should be set to Done', done => {
|
||||||
const { id, options, responseQueue, setInProgressMock, setDoneMock } = getTestContext();
|
const { id, options, responseQueue, setInProgressMock } = getTestContext();
|
||||||
|
|
||||||
subscribeTester({
|
subscribeTester({
|
||||||
observable: responseQueue.getResponses(id).pipe(first()),
|
observable: responseQueue.getResponses(id).pipe(first()),
|
||||||
expectCallback: data => {
|
expectCallback: data => {
|
||||||
data.observable.subscribe().unsubscribe();
|
data.observable.subscribe().unsubscribe();
|
||||||
expect(setInProgressMock.mock.calls).toEqual([['id']]);
|
expect(setInProgressMock.mock.calls).toEqual([['id']]);
|
||||||
expect(setDoneMock.mock.calls).toEqual([['id']]);
|
|
||||||
},
|
},
|
||||||
doneCallback: done,
|
doneCallback: done,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Observable, Subject } from 'rxjs';
|
import { Observable, Subject } from 'rxjs';
|
||||||
import { filter, finalize } from 'rxjs/operators';
|
import { filter } from 'rxjs/operators';
|
||||||
import { BackendSrvRequest, FetchResponse } from '@grafana/runtime';
|
import { BackendSrvRequest, FetchResponse } from '@grafana/runtime';
|
||||||
import { FetchQueue } from './FetchQueue';
|
import { FetchQueue } from './FetchQueue';
|
||||||
|
|
||||||
@@ -27,17 +27,7 @@ export class ResponseQueue {
|
|||||||
// Let the fetchQueue know that this id has started data fetching.
|
// Let the fetchQueue know that this id has started data fetching.
|
||||||
fetchQueue.setInProgress(id);
|
fetchQueue.setInProgress(id);
|
||||||
|
|
||||||
this.responses.next({
|
this.responses.next({ id, observable: fetch(options) });
|
||||||
id,
|
|
||||||
observable: fetch(options).pipe(
|
|
||||||
// finalize is called whenever this observable is unsubscribed/errored/completed/canceled
|
|
||||||
// https://rxjs.dev/api/operators/finalize
|
|
||||||
finalize(() => {
|
|
||||||
// Let the fetchQueue know that this id is done.
|
|
||||||
fetchQueue.setDone(id);
|
|
||||||
})
|
|
||||||
),
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -65,10 +65,11 @@ export class BackendSrv implements BackendService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fetch<T>(options: BackendSrvRequest): Observable<FetchResponse<T>> {
|
fetch<T>(options: BackendSrvRequest): Observable<FetchResponse<T>> {
|
||||||
return new Observable(observer => {
|
// We need to match an entry added to the queue stream with the entry that is eventually added to the response stream
|
||||||
// We need to match an entry added to the queue stream with the entry that is eventually added to the response stream
|
const id = uuidv4();
|
||||||
const id = uuidv4();
|
const fetchQueue = this.fetchQueue;
|
||||||
|
|
||||||
|
return new Observable(observer => {
|
||||||
// Subscription is an object that is returned whenever you subscribe to an Observable.
|
// Subscription is an object that is returned whenever you subscribe to an Observable.
|
||||||
// You can also use it as a container of many subscriptions and when it is unsubscribed all subscriptions within are also unsubscribed.
|
// You can also use it as a container of many subscriptions and when it is unsubscribed all subscriptions within are also unsubscribed.
|
||||||
const subscriptions: Subscription = new Subscription();
|
const subscriptions: Subscription = new Subscription();
|
||||||
@@ -89,6 +90,9 @@ export class BackendSrv implements BackendService {
|
|||||||
|
|
||||||
// This returned function will be called whenever the returned Observable from the fetch<T> function is unsubscribed/errored/completed/canceled.
|
// This returned function will be called whenever the returned Observable from the fetch<T> function is unsubscribed/errored/completed/canceled.
|
||||||
return function unsubscribe() {
|
return function unsubscribe() {
|
||||||
|
// Change status to Done moved here from ResponseQueue because this unsubscribe was called before the responseQueue produced a result
|
||||||
|
fetchQueue.setDone(id);
|
||||||
|
|
||||||
// When subscriptions is unsubscribed all the implicitly added subscriptions above are also unsubscribed.
|
// When subscriptions is unsubscribed all the implicitly added subscriptions above are also unsubscribed.
|
||||||
subscriptions.unsubscribe();
|
subscriptions.unsubscribe();
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user