Skip to content
Snippets Groups Projects
Commit bd749074 authored by Viktor Vorobev's avatar Viktor Vorobev
Browse files

Merged in NRRPLT-8958-allow-failed-proxy-connections (pull request #56)

NRRPLT-8958 allow failed proxy connections

* [NRRPLT-8958] Allow several failed proxy connections

* [NRRPLT-8958] Add tests


Approved-by: Ugo Albanese
parent 829d55d7
No related branches found
No related tags found
No related merge requests found
...@@ -2,10 +2,10 @@ ...@@ -2,10 +2,10 @@
* @jest-environment jsdom * @jest-environment jsdom
*/ */
import '@testing-library/jest-dom'; import '@testing-library/jest-dom';
import 'jest-fetch-mock';
import { HttpProxyService } from '../http-proxy-service'; 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 mockURL = 'http://test.url';
const mockEndpoint = '/test/endpoint'; const mockEndpoint = '/test/endpoint';
...@@ -106,4 +106,42 @@ describe('HttpProxyService', () => { ...@@ -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'})).toEqual('/api?q=a&a=q');
expect(httpService.createRequestURL('/api', {q: 'a', a: 'q'}, 'tag')).toEqual('/api?q=a&a=q#tag'); 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
...@@ -12,6 +12,8 @@ export class NRPProxyError extends Error { ...@@ -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 * Class that performs http requests with default request options to proxy
* and monitors proxy connectivity. * and monitors proxy connectivity.
...@@ -27,6 +29,7 @@ export class HttpProxyService extends HttpService { ...@@ -27,6 +29,7 @@ export class HttpProxyService extends HttpService {
this.proxyURL = new URL(config.api.proxy.url); this.proxyURL = new URL(config.api.proxy.url);
this.connected = true; this.connected = true;
this.failedRequestsCount = 0;
} }
/** /**
...@@ -75,13 +78,19 @@ export class HttpProxyService extends HttpService { ...@@ -75,13 +78,19 @@ export class HttpProxyService extends HttpService {
response = await fetch(requestURL, options); response = await fetch(requestURL, options);
// emit CONNECTED event, if needed // emit CONNECTED event, if needed
EventProxyService.instance.emitConnected(); EventProxyService.instance.emitConnected();
this.failedRequestsCount = 0;
} }
catch { catch (error) {
// Throw NRPProxyError once this.failedRequestsCount++; // increment counter on unsuccessful request
EventProxyService.instance.emitDisconnected({ if (this.failedRequestsCount >= MAX_FAILED_REQUESTS) { // only emit event after MAX_FAILED_REQUESTS unsuccessful requests
code: requestURL.href, // emit DISCONNECTED event
data: JSON.stringify(options, null, 4) 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}); return new Response(JSON.stringify([]), {status: 404});
} }
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment