diff --git a/src/services/proxy/__tests__/http-proxy-service.test.js b/src/services/proxy/__tests__/http-proxy-service.test.js index 429be2b4dd532644925670d451da0351bec6a4c9..1c9bc70e21213421240495782ea5092775a109df 100644 --- a/src/services/proxy/__tests__/http-proxy-service.test.js +++ b/src/services/proxy/__tests__/http-proxy-service.test.js @@ -2,10 +2,10 @@ * @jest-environment jsdom */ import '@testing-library/jest-dom'; -import 'jest-fetch-mock'; import { HttpProxyService } from '../http-proxy-service'; -import AuthenticationService from '../../authentication-service'; +import EventProxyService from '../event-proxy-service'; +jest.mock('../../authentication-service.js'); const mockURL = 'http://test.url'; const mockEndpoint = '/test/endpoint'; @@ -106,4 +106,42 @@ describe('HttpProxyService', () => { expect(httpService.createRequestURL('/api', {q: 'a', a: 'q'})).toEqual('/api?q=a&a=q'); expect(httpService.createRequestURL('/api', {q: 'a', a: 'q'}, 'tag')).toEqual('/api?q=a&a=q#tag'); }); + + test('emits DISCONNECTED after 3 subsequent failed requests', async () => { + let mockResponse = {}; + + const httpService = new HttpProxyService(); + let spyFetch = jest.spyOn(global, 'fetch'); + + // Prepare fetch mock to throw exceptions + spyFetch.mockImplementationOnce(() => Promise.reject('Failed request')); + spyFetch.mockImplementationOnce(() => Promise.reject('Failed request')); + spyFetch.mockImplementationOnce(() => + Promise.resolve({ status: 200, ok: true, json: () => Promise.resolve({}) }) + ); + spyFetch.mockImplementationOnce(() => Promise.reject('Failed request')); + spyFetch.mockImplementationOnce(() => Promise.reject('Failed request')); + spyFetch.mockImplementationOnce(() => Promise.reject('Failed request')); + + // Mock the emitDisconnected method + const emitDisconnectedSpy = jest.spyOn(EventProxyService.instance, 'emitDisconnected'); + const emitConnectedSpy = jest.spyOn(EventProxyService.instance, 'emitConnected'); + + // The first 2 requests should be 404 but not emit DISCONNECTED + expect((await httpService.httpRequestGET(mockEndpoint)).ok).toBe(false); + expect((await httpService.httpRequestGET(mockEndpoint)).ok).toBe(false); + // The OK request should reset the counter + expect((await httpService.httpRequestGET(mockEndpoint)).ok).toBe(true); + expect(emitConnectedSpy).toHaveBeenCalledTimes(1); + + expect((await httpService.httpRequestGET(mockEndpoint)).ok).toBe(false); + expect((await httpService.httpRequestGET(mockEndpoint)).ok).toBe(false); + expect(emitDisconnectedSpy).not.toHaveBeenCalled(); + try { + await httpService.httpRequestGET(mockEndpoint); + } + catch (error) { + expect(emitDisconnectedSpy).toHaveBeenCalledTimes(1); + } + }); }); \ No newline at end of file diff --git a/src/services/proxy/http-proxy-service.js b/src/services/proxy/http-proxy-service.js index aea4a5f64a08339ab474205bc446648fe50507c9..669d46bd832e0efe847b8bb58bdb68c3aaec6705 100644 --- a/src/services/proxy/http-proxy-service.js +++ b/src/services/proxy/http-proxy-service.js @@ -12,6 +12,8 @@ export class NRPProxyError extends Error { } } +const MAX_FAILED_REQUESTS = 3; + /** * Class that performs http requests with default request options to proxy * and monitors proxy connectivity. @@ -27,6 +29,7 @@ export class HttpProxyService extends HttpService { this.proxyURL = new URL(config.api.proxy.url); this.connected = true; + this.failedRequestsCount = 0; } /** @@ -75,13 +78,19 @@ export class HttpProxyService extends HttpService { response = await fetch(requestURL, options); // emit CONNECTED event, if needed EventProxyService.instance.emitConnected(); + this.failedRequestsCount = 0; } - catch { - // Throw NRPProxyError once - EventProxyService.instance.emitDisconnected({ - code: requestURL.href, - data: JSON.stringify(options, null, 4) - }); + catch (error) { + this.failedRequestsCount++; // increment counter on unsuccessful request + if (this.failedRequestsCount >= MAX_FAILED_REQUESTS) { // only emit event after MAX_FAILED_REQUESTS unsuccessful requests + // emit DISCONNECTED event + EventProxyService.instance.emitDisconnected({ + code: requestURL.href, + data: + 'Error occured: \n' + error.message + '\nwith options:\n' + JSON.stringify(options, null, 4) + }); + } + // TODO: the Error is thrown (emitDisconnected) before the response is generated ?? return new Response(JSON.stringify([]), {status: 404}); }