diff --git a/src/app/core/auth/auth-request.service.spec.ts b/src/app/core/auth/auth-request.service.spec.ts index 707daf9e30..2afeb26b02 100644 --- a/src/app/core/auth/auth-request.service.spec.ts +++ b/src/app/core/auth/auth-request.service.spec.ts @@ -7,57 +7,156 @@ import { TestScheduler } from 'rxjs/testing'; import { createSuccessfulRemoteDataObject } from '../../shared/remote-data.utils'; import { ShortLivedToken } from './models/short-lived-token.model'; 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`, () => { let halService: HALEndpointService; let endpointURL: string; + let requestID: string; let shortLivedToken: ShortLivedToken; let shortLivedTokenRD: RemoteData; let requestService: RequestService; let rdbService: RemoteDataBuildService; - let service: AuthRequestService; + let service; let testScheduler; - class TestAuthRequestService extends AuthRequestService { - constructor( - hes: HALEndpointService, - rs: RequestService, - rdbs: RemoteDataBuildService - ) { - super(hes, rs, rdbs); - } + const status = new AuthStatus(); - protected createShortLivedTokenRequest(href: string): PostRequest { - return new PostRequest(this.requestService.generateRequestId(), href); - } + class TestAuthRequestService extends AuthRequestService { + constructor( + hes: HALEndpointService, + rs: RequestService, + rdbs: RemoteDataBuildService + ) { + super(hes, rs, rdbs); } - const init = (cold: typeof TestScheduler.prototype.createColdObservable) => { - endpointURL = 'https://rest.api/auth'; - shortLivedToken = Object.assign(new ShortLivedToken(), { - value: 'some-token' - }); - shortLivedTokenRD = createSuccessfulRemoteDataObject(shortLivedToken); + protected createShortLivedTokenRequest(href: string): PostRequest { + return new PostRequest(this.requestService.generateRequestId(), href); + } + } - halService = jasmine.createSpyObj('halService', { - 'getEndpoint': cold('a', { a: endpointURL }) - }); - requestService = jasmine.createSpyObj('requestService', { - 'send': null - }); - rdbService = jasmine.createSpyObj('rdbService', { - 'buildFromRequestUUID': cold('a', { a: shortLivedTokenRD }) - }); + const init = (cold: typeof TestScheduler.prototype.createColdObservable) => { + endpointURL = 'https://rest.api/auth'; + requestID = 'requestID'; + shortLivedToken = Object.assign(new ShortLivedToken(), { + value: 'some-token' + }); + shortLivedTokenRD = createSuccessfulRemoteDataObject(shortLivedToken); - 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(() => { - testScheduler = new TestScheduler((actual, expected) => { - expect(actual).toEqual(expected); + options = Object.create({}); + }); + + 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`, () => { it(`should call createShortLivedTokenRequest with the url for the endpoint`, () => { testScheduler.run(({ cold, expectObservable, flush }) => { diff --git a/src/app/core/auth/auth-request.service.ts b/src/app/core/auth/auth-request.service.ts index bcaa5972ac..4087989a6b 100644 --- a/src/app/core/auth/auth-request.service.ts +++ b/src/app/core/auth/auth-request.service.ts @@ -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> { return this.rdbService.buildFromRequestUUID(requestId).pipe( getFirstCompletedRemoteData(), @@ -36,6 +41,12 @@ export abstract class AuthRequestService { 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> { const requestId = this.requestService.generateRequestId(); @@ -52,6 +63,11 @@ export abstract class AuthRequestService { 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> { const requestId = this.requestService.generateRequestId();