92900: Update docs & specs for AuthRequestService

This commit is contained in:
Yura Bondarenko
2022-08-25 13:59:40 +02:00
parent e464c0f8c7
commit db169251df
2 changed files with 146 additions and 31 deletions

View File

@@ -7,57 +7,156 @@ import { TestScheduler } from 'rxjs/testing';
import { createSuccessfulRemoteDataObject } from '../../shared/remote-data.utils'; import { createSuccessfulRemoteDataObject } from '../../shared/remote-data.utils';
import { ShortLivedToken } from './models/short-lived-token.model'; import { ShortLivedToken } from './models/short-lived-token.model';
import { RemoteData } from '../data/remote-data'; import { RemoteData } from '../data/remote-data';
import { HttpOptions } from '../dspace-rest/dspace-rest.service';
import objectContaining = jasmine.objectContaining;
import { AuthStatus } from './models/auth-status.model';
import { RestRequestMethod } from '../data/rest-request-method';
describe(`AuthRequestService`, () => { describe(`AuthRequestService`, () => {
let halService: HALEndpointService; let halService: HALEndpointService;
let endpointURL: string; let endpointURL: string;
let requestID: string;
let shortLivedToken: ShortLivedToken; let shortLivedToken: ShortLivedToken;
let shortLivedTokenRD: RemoteData<ShortLivedToken>; let shortLivedTokenRD: RemoteData<ShortLivedToken>;
let requestService: RequestService; let requestService: RequestService;
let rdbService: RemoteDataBuildService; let rdbService: RemoteDataBuildService;
let service: AuthRequestService; let service;
let testScheduler; let testScheduler;
class TestAuthRequestService extends AuthRequestService { const status = new AuthStatus();
constructor(
hes: HALEndpointService,
rs: RequestService,
rdbs: RemoteDataBuildService
) {
super(hes, rs, rdbs);
}
protected createShortLivedTokenRequest(href: string): PostRequest { class TestAuthRequestService extends AuthRequestService {
return new PostRequest(this.requestService.generateRequestId(), href); constructor(
} hes: HALEndpointService,
rs: RequestService,
rdbs: RemoteDataBuildService
) {
super(hes, rs, rdbs);
} }
const init = (cold: typeof TestScheduler.prototype.createColdObservable) => { protected createShortLivedTokenRequest(href: string): PostRequest {
endpointURL = 'https://rest.api/auth'; return new PostRequest(this.requestService.generateRequestId(), href);
shortLivedToken = Object.assign(new ShortLivedToken(), { }
value: 'some-token' }
});
shortLivedTokenRD = createSuccessfulRemoteDataObject(shortLivedToken);
halService = jasmine.createSpyObj('halService', { const init = (cold: typeof TestScheduler.prototype.createColdObservable) => {
'getEndpoint': cold('a', { a: endpointURL }) endpointURL = 'https://rest.api/auth';
}); requestID = 'requestID';
requestService = jasmine.createSpyObj('requestService', { shortLivedToken = Object.assign(new ShortLivedToken(), {
'send': null value: 'some-token'
}); });
rdbService = jasmine.createSpyObj('rdbService', { shortLivedTokenRD = createSuccessfulRemoteDataObject(shortLivedToken);
'buildFromRequestUUID': cold('a', { a: shortLivedTokenRD })
});
service = new TestAuthRequestService(halService, requestService, rdbService); halService = jasmine.createSpyObj('halService', {
}; 'getEndpoint': cold('a', { a: endpointURL })
});
requestService = jasmine.createSpyObj('requestService', {
'generateRequestId': requestID,
'send': null,
});
rdbService = jasmine.createSpyObj('rdbService', {
'buildFromRequestUUID': cold('a', { a: shortLivedTokenRD })
});
service = new TestAuthRequestService(halService, requestService, rdbService);
spyOn(service as any, 'fetchRequest').and.returnValue(cold('a', { a: createSuccessfulRemoteDataObject(status) }));
};
beforeEach(() => {
testScheduler = new TestScheduler((actual, expected) => {
expect(actual).toEqual(expected);
});
});
describe('REST request methods', () => {
let options: HttpOptions;
beforeEach(() => { beforeEach(() => {
testScheduler = new TestScheduler((actual, expected) => { options = Object.create({});
expect(actual).toEqual(expected); });
describe('GET', () => {
it('should send a GET request to the right endpoint and return the auth status', () => {
testScheduler.run(({ cold, expectObservable, flush }) => {
init(cold);
expectObservable(service.getRequest('method', options)).toBe('a', {
a: objectContaining({ payload: status }),
});
flush();
expect(requestService.send).toHaveBeenCalledWith(objectContaining({
uuid: requestID,
href: endpointURL + '/method',
method: RestRequestMethod.GET,
body: undefined,
options,
}));
expect((service as any).fetchRequest).toHaveBeenCalledWith(requestID);
});
});
it('should send the request even if caller doesn\'t subscribe to the response', () => {
testScheduler.run(({ cold, flush }) => {
init(cold);
service.getRequest('method', options);
flush();
expect(requestService.send).toHaveBeenCalledWith(objectContaining({
uuid: requestID,
href: endpointURL + '/method',
method: RestRequestMethod.GET,
body: undefined,
options,
}));
expect((service as any).fetchRequest).toHaveBeenCalledWith(requestID);
});
}); });
}); });
describe('POST', () => {
it('should send a POST request to the right endpoint and return the auth status', () => {
testScheduler.run(({ cold, expectObservable, flush }) => {
init(cold);
expectObservable(service.postToEndpoint('method', { content: 'something' }, options)).toBe('a', {
a: objectContaining({ payload: status }),
});
flush();
expect(requestService.send).toHaveBeenCalledWith(objectContaining({
uuid: requestID,
href: endpointURL + '/method',
method: RestRequestMethod.POST,
body: { content: 'something' },
options,
}));
expect((service as any).fetchRequest).toHaveBeenCalledWith(requestID);
});
});
it('should send the request even if caller doesn\'t subscribe to the response', () => {
testScheduler.run(({ cold, flush }) => {
init(cold);
service.postToEndpoint('method', { content: 'something' }, options);
flush();
expect(requestService.send).toHaveBeenCalledWith(objectContaining({
uuid: requestID,
href: endpointURL + '/method',
method: RestRequestMethod.POST,
body: { content: 'something' },
options,
}));
expect((service as any).fetchRequest).toHaveBeenCalledWith(requestID);
});
});
});
});
describe(`getShortlivedToken`, () => { describe(`getShortlivedToken`, () => {
it(`should call createShortLivedTokenRequest with the url for the endpoint`, () => { it(`should call createShortLivedTokenRequest with the url for the endpoint`, () => {
testScheduler.run(({ cold, expectObservable, flush }) => { testScheduler.run(({ cold, expectObservable, flush }) => {

View File

@@ -26,6 +26,11 @@ export abstract class AuthRequestService {
) { ) {
} }
/**
* Fetch the response to a request from the cache, once it's completed.
* @param requestId the UUID of the request for which to retrieve the response
* @protected
*/
protected fetchRequest(requestId: string): Observable<RemoteData<AuthStatus>> { protected fetchRequest(requestId: string): Observable<RemoteData<AuthStatus>> {
return this.rdbService.buildFromRequestUUID<AuthStatus>(requestId).pipe( return this.rdbService.buildFromRequestUUID<AuthStatus>(requestId).pipe(
getFirstCompletedRemoteData(), getFirstCompletedRemoteData(),
@@ -36,6 +41,12 @@ export abstract class AuthRequestService {
return isNotEmpty(method) ? `${endpoint}/${method}` : `${endpoint}`; return isNotEmpty(method) ? `${endpoint}/${method}` : `${endpoint}`;
} }
/**
* Send a POST request to an authentication endpoint
* @param method the method to send to (e.g. 'status')
* @param body the data to send (optional)
* @param options the HTTP options for the request
*/
public postToEndpoint(method: string, body?: any, options?: HttpOptions): Observable<RemoteData<AuthStatus>> { public postToEndpoint(method: string, body?: any, options?: HttpOptions): Observable<RemoteData<AuthStatus>> {
const requestId = this.requestService.generateRequestId(); const requestId = this.requestService.generateRequestId();
@@ -52,6 +63,11 @@ export abstract class AuthRequestService {
return this.fetchRequest(requestId); return this.fetchRequest(requestId);
} }
/**
* Send a GET request to an authentication endpoint
* @param method the method to send to (e.g. 'status')
* @param options the HTTP options for the request
*/
public getRequest(method: string, options?: HttpOptions): Observable<RemoteData<AuthStatus>> { public getRequest(method: string, options?: HttpOptions): Observable<RemoteData<AuthStatus>> {
const requestId = this.requestService.generateRequestId(); const requestId = this.requestService.generateRequestId();