mirror of
https://github.com/eggjs/egg.git
synced 2024-12-04 07:14:30 +00:00
auto fallback to urllib@3 when require urllib4 error <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Expanded CI workflow to include Node.js version 23 for testing. - Enhanced `HttpClientNext` class with improved error handling and configuration management. - Added support for HTTP/2 functionality in the test suite, including self-signed certificate handling. - **Bug Fixes** - Improved error handling for library imports based on Node.js versions. - **Chores** - Updated dependency versions in `package.json`. - Modified HTTP client configuration to include a new `connect` property. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
801 lines
22 KiB
JavaScript
801 lines
22 KiB
JavaScript
const assert = require('node:assert');
|
|
const { once } = require('node:events');
|
|
const { createSecureServer } = require('node:http2');
|
|
const mm = require('egg-mock');
|
|
const urllib = require('urllib');
|
|
const pem = require('https-pem');
|
|
const Httpclient = require('../../../lib/core/httpclient');
|
|
const HttpclientNext = require('../../../lib/core/httpclient_next');
|
|
const utils = require('../../utils');
|
|
|
|
describe('test/lib/core/httpclient.test.js', () => {
|
|
let client;
|
|
let clientNext;
|
|
let url;
|
|
|
|
before(() => {
|
|
client = new Httpclient({
|
|
deprecate: () => {},
|
|
config: {
|
|
httpclient: {
|
|
request: {},
|
|
httpAgent: {},
|
|
httpsAgent: {},
|
|
},
|
|
},
|
|
});
|
|
client.on('request', info => {
|
|
info.args.headers = info.args.headers || {};
|
|
info.args.headers['mock-traceid'] = 'mock-traceid';
|
|
info.args.headers['mock-rpcid'] = 'mock-rpcid';
|
|
});
|
|
|
|
clientNext = new HttpclientNext({
|
|
config: {
|
|
httpclient: {
|
|
request: {},
|
|
},
|
|
},
|
|
});
|
|
clientNext.on('request', info => {
|
|
info.args.headers = info.args.headers || {};
|
|
info.args.headers['mock-traceid'] = 'mock-traceid';
|
|
info.args.headers['mock-rpcid'] = 'mock-rpcid';
|
|
});
|
|
});
|
|
before(async () => {
|
|
url = await utils.startLocalServer();
|
|
});
|
|
|
|
afterEach(mm.restore);
|
|
|
|
it('should request ok with log', done => {
|
|
const args = {
|
|
dataType: 'text',
|
|
};
|
|
client.once('response', info => {
|
|
assert(info.req.options.headers['mock-traceid'] === 'mock-traceid');
|
|
assert(info.req.options.headers['mock-rpcid'] === 'mock-rpcid');
|
|
done();
|
|
});
|
|
|
|
client.request(url, args);
|
|
});
|
|
|
|
it('should curl ok with log', done => {
|
|
const args = {
|
|
dataType: 'text',
|
|
};
|
|
client.once('response', info => {
|
|
assert(info.req.options.headers['mock-traceid'] === 'mock-traceid');
|
|
assert(info.req.options.headers['mock-rpcid'] === 'mock-rpcid');
|
|
done();
|
|
});
|
|
|
|
client.curl(url, args);
|
|
});
|
|
|
|
it('should mock ENETUNREACH error', async () => {
|
|
mm(urllib.HttpClient2.prototype, 'request', () => {
|
|
const err = new Error('connect ENETUNREACH 1.1.1.1:80 - Local (127.0.0.1)');
|
|
err.code = 'ENETUNREACH';
|
|
return Promise.reject(err);
|
|
});
|
|
await assert.rejects(async () => {
|
|
await client.request(url);
|
|
}, err => {
|
|
assert(err.name === 'HttpClientError');
|
|
assert(err.code === 'httpclient_ENETUNREACH');
|
|
assert(err.message === 'connect ENETUNREACH 1.1.1.1:80 - Local (127.0.0.1) [ https://eggjs.org/zh-cn/faq/httpclient_ENETUNREACH ]');
|
|
return true;
|
|
});
|
|
});
|
|
|
|
it('should handle timeout error', async () => {
|
|
await assert.rejects(async () => {
|
|
await client.request(url + '/timeout', { timeout: 100 });
|
|
}, err => {
|
|
assert(err.name === 'ResponseTimeoutError');
|
|
return true;
|
|
});
|
|
});
|
|
|
|
it('should support safeCurl', async () => {
|
|
let ip;
|
|
let family;
|
|
let host;
|
|
mm(client.app.config, 'security', {
|
|
ssrf: {
|
|
checkAddress(aIp, aFamilay, aHost) {
|
|
ip = aIp;
|
|
family = aFamilay;
|
|
host = aHost;
|
|
return true;
|
|
},
|
|
},
|
|
});
|
|
await client.safeCurl(url);
|
|
assert(ip);
|
|
assert(family);
|
|
assert(host);
|
|
});
|
|
|
|
describe('HttpClientNext', () => {
|
|
it('should request ok with log', async () => {
|
|
const args = {
|
|
dataType: 'text',
|
|
};
|
|
let info;
|
|
clientNext.once('response', meta => {
|
|
info = meta;
|
|
});
|
|
const { status } = await clientNext.request(url, args);
|
|
assert(status === 200);
|
|
assert(info.req.options.headers['mock-traceid'] === 'mock-traceid');
|
|
assert(info.req.options.headers['mock-rpcid'] === 'mock-rpcid');
|
|
assert(info.req.args.headers['mock-traceid'] === 'mock-traceid');
|
|
assert(info.req.args.headers['mock-rpcid'] === 'mock-rpcid');
|
|
});
|
|
|
|
it('should curl ok with log', async () => {
|
|
const args = {
|
|
dataType: 'text',
|
|
};
|
|
let info;
|
|
clientNext.once('response', meta => {
|
|
info = meta;
|
|
});
|
|
const { status } = await clientNext.curl(url, args);
|
|
assert(status === 200);
|
|
assert(info.req.options.headers['mock-traceid'] === 'mock-traceid');
|
|
assert(info.req.options.headers['mock-rpcid'] === 'mock-rpcid');
|
|
assert(info.req.args.headers['mock-traceid'] === 'mock-traceid');
|
|
assert(info.req.args.headers['mock-rpcid'] === 'mock-rpcid');
|
|
});
|
|
|
|
it('should request with error', async () => {
|
|
await assert.rejects(async () => {
|
|
const response = await clientNext.request(url + '/error', {
|
|
dataType: 'json',
|
|
});
|
|
console.log(response);
|
|
}, err => {
|
|
assert.equal(err.name, 'JSONResponseFormatError');
|
|
assert.match(err.message, /this is an error/);
|
|
assert(err.res);
|
|
assert.equal(err.res.status, 500);
|
|
return true;
|
|
});
|
|
});
|
|
|
|
it('should support safeCurl', async () => {
|
|
let ip;
|
|
let family;
|
|
let host;
|
|
mm(clientNext.app.config, 'security', {
|
|
ssrf: {
|
|
checkAddress(aIp, aFamilay, aHost) {
|
|
ip = aIp;
|
|
family = aFamilay;
|
|
host = aHost;
|
|
return true;
|
|
},
|
|
},
|
|
});
|
|
await clientNext.safeCurl(url);
|
|
assert(ip);
|
|
assert(family);
|
|
assert(host);
|
|
});
|
|
});
|
|
|
|
describe('httpclient.httpAgent.timeout < 30000', () => {
|
|
let app;
|
|
before(() => {
|
|
app = utils.app('apps/httpclient-agent-timeout-3000');
|
|
return app.ready();
|
|
});
|
|
after(() => app.close());
|
|
|
|
it('should auto reset httpAgent.timeout to 30000', () => {
|
|
// should access httpclient first
|
|
assert(app.httpclient);
|
|
assert(app.config.httpclient.timeout === 3000);
|
|
assert(app.config.httpclient.httpAgent.timeout === 30000);
|
|
assert(app.config.httpclient.httpsAgent.timeout === 30000);
|
|
});
|
|
|
|
it('should set request default global timeout to 10s', () => {
|
|
// should access httpclient first
|
|
assert(app.httpclient);
|
|
assert(app.config.httpclient.request.timeout === 10000);
|
|
});
|
|
|
|
it('should convert compatibility options to agent options', () => {
|
|
// should access httpclient first
|
|
assert(app.httpclient);
|
|
assert(app.config.httpclient.httpAgent.freeSocketTimeout === 2000);
|
|
assert(app.config.httpclient.httpsAgent.freeSocketTimeout === 2000);
|
|
|
|
assert(app.config.httpclient.httpAgent.maxSockets === 100);
|
|
assert(app.config.httpclient.httpsAgent.maxSockets === 100);
|
|
|
|
assert(app.config.httpclient.httpAgent.maxFreeSockets === 100);
|
|
assert(app.config.httpclient.httpsAgent.maxFreeSockets === 100);
|
|
|
|
assert(app.config.httpclient.httpAgent.keepAlive === false);
|
|
assert(app.config.httpclient.httpsAgent.keepAlive === false);
|
|
});
|
|
});
|
|
|
|
describe('httpclient.request.timeout = 100', () => {
|
|
let app;
|
|
before(() => {
|
|
app = utils.app('apps/httpclient-request-timeout-100');
|
|
return app.ready();
|
|
});
|
|
after(() => app.close());
|
|
|
|
it('should set request default global timeout to 100ms', () => {
|
|
return app.httpclient.curl(`${url}/timeout`)
|
|
.catch(err => {
|
|
assert(err);
|
|
assert(err.name === 'ResponseTimeoutError');
|
|
assert(err.message.includes('Response timeout for 100ms'));
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('overwrite httpclient', () => {
|
|
let app;
|
|
before(() => {
|
|
app = utils.app('apps/httpclient-overwrite');
|
|
return app.ready();
|
|
});
|
|
after(() => app.close());
|
|
|
|
it('should set request default global timeout to 100ms', () => {
|
|
return app.httpclient.curl(`${url}/timeout`)
|
|
.catch(err => {
|
|
assert(err);
|
|
assert(err.name === 'ResponseTimeoutError');
|
|
assert(err.message.includes('Response timeout for 100ms'));
|
|
});
|
|
});
|
|
|
|
it('should assert url', () => {
|
|
return app.httpclient.curl('unknown url')
|
|
.catch(err => {
|
|
assert(err);
|
|
assert(err.message.includes('url should start with http, but got unknown url'));
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('overwrite httpclient support useHttpClientNext=true', () => {
|
|
let app;
|
|
before(() => {
|
|
app = utils.app('apps/httpclient-next-overwrite');
|
|
return app.ready();
|
|
});
|
|
after(() => app.close());
|
|
|
|
it('should work', async () => {
|
|
const res = await app.httpclient.request(url);
|
|
assert.equal(res.status, 200);
|
|
assert.equal(res.data.toString(), 'GET /');
|
|
});
|
|
|
|
it('should set request default global timeout to 99ms', () => {
|
|
return app.httpclient.curl(`${url}/timeout`)
|
|
.catch(err => {
|
|
assert(err);
|
|
assert(err.name === 'HttpClientRequestTimeoutError');
|
|
assert(err.message.includes('Request timeout for 99 ms'));
|
|
});
|
|
});
|
|
|
|
it('should assert url', () => {
|
|
return app.httpclient.curl('unknown url')
|
|
.catch(err => {
|
|
assert(err);
|
|
assert(err.message.includes('url should start with http, but got unknown url'));
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('overwrite httpclient support allowH2=true', () => {
|
|
let app;
|
|
before(() => {
|
|
app = utils.app('apps/httpclient-allowH2');
|
|
return app.ready();
|
|
});
|
|
after(() => app.close());
|
|
|
|
it('should work on http2', async () => {
|
|
const res = await app.httpclient.request(url, {
|
|
timeout: 5000,
|
|
});
|
|
assert.equal(res.status, 200);
|
|
assert.equal(res.data.toString(), 'GET /');
|
|
// assert.equal(sensitiveHeaders in res.headers, false);
|
|
const res2 = await app.httpclient.request('https://registry.npmmirror.com/urllib/latest', {
|
|
dataType: 'json',
|
|
timeout: 5000,
|
|
});
|
|
assert.equal(res2.status, 200);
|
|
assert.equal(res2.data.name, 'urllib');
|
|
// assert.equal(sensitiveHeaders in res2.headers, true);
|
|
});
|
|
|
|
it('should work on http2.server with self-signed certificate', async () => {
|
|
const server = createSecureServer(pem);
|
|
server.on('stream', (stream, headers) => {
|
|
assert.equal(headers[':method'], 'GET');
|
|
stream.respond({
|
|
'content-type': 'text/plain; charset=utf-8',
|
|
'x-custom-h2': 'hello',
|
|
':status': 200,
|
|
});
|
|
stream.end('hello h2!');
|
|
// console.log(headers);
|
|
const mainNodejsVersion = parseInt(process.versions.node.split('.')[0]);
|
|
if (mainNodejsVersion >= 18) {
|
|
assert.match(headers['user-agent'], /node\-urllib\/4\.\d+\.\d+/);
|
|
} else {
|
|
assert.match(headers['user-agent'], /node\-urllib\/3\.\d+\.\d+/);
|
|
}
|
|
});
|
|
server.listen(0);
|
|
await once(server, 'listening');
|
|
const response = await app.httpclient.request(`https://localhost:${server.address().port}`, {
|
|
dataType: 'text',
|
|
headers: {
|
|
'x-my-header': 'foo',
|
|
},
|
|
});
|
|
assert.equal(response.status, 200);
|
|
assert.equal(response.headers['x-custom-h2'], 'hello');
|
|
assert.equal(response.data, 'hello h2!');
|
|
server.close();
|
|
});
|
|
|
|
it('should set request default global timeout to 99ms', async () => {
|
|
await assert.rejects(async () => {
|
|
await app.httpclient.curl(`${url}/timeout`);
|
|
}, err => {
|
|
assert.equal(err.name, 'HttpClientRequestTimeoutError');
|
|
assert.match(err.message, /timeout for 99 ms/);
|
|
return true;
|
|
});
|
|
});
|
|
|
|
it('should request http1.1 success', async () => {
|
|
const result = await app.httpclient.curl(`${url}`, {
|
|
dataType: 'text',
|
|
});
|
|
assert.equal(result.status, 200);
|
|
assert.equal(result.data, 'GET /');
|
|
});
|
|
|
|
it('should request http2 success', async () => {
|
|
for (let i = 0; i < 10; i++) {
|
|
const result = await app.httpclient.curl('https://registry.npmmirror.com', {
|
|
dataType: 'json',
|
|
timeout: 5000,
|
|
});
|
|
assert.equal(result.status, 200);
|
|
assert.equal(result.headers['content-type'], 'application/json; charset=utf-8');
|
|
assert.equal(result.data.sync_model, 'all');
|
|
}
|
|
});
|
|
|
|
it('should assert url', async () => {
|
|
await assert.rejects(async () => {
|
|
await app.httpclient.curl('unknown url');
|
|
}, err => {
|
|
assert.match(err.message, /url should start with http, but got unknown url/);
|
|
return true;
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('httpclient tracer', () => {
|
|
let app;
|
|
before(() => {
|
|
app = utils.app('apps/httpclient-tracer');
|
|
return app.ready();
|
|
});
|
|
|
|
after(() => app.close());
|
|
|
|
it('should app request auto set tracer', async () => {
|
|
const httpclient = app.httpclient;
|
|
// httpClient alias to httpclient
|
|
assert(app.httpClient);
|
|
assert.equal(app.httpClient, app.httpclient);
|
|
|
|
let reqTracer;
|
|
let resTracer;
|
|
|
|
httpclient.on('request', function(options) {
|
|
reqTracer = options.args.tracer;
|
|
});
|
|
|
|
httpclient.on('response', function(options) {
|
|
resTracer = options.req.args.tracer;
|
|
});
|
|
|
|
let res = await httpclient.request(url, {
|
|
method: 'GET',
|
|
});
|
|
|
|
assert(res.status === 200);
|
|
assert(reqTracer === resTracer);
|
|
|
|
assert(reqTracer.traceId);
|
|
assert(reqTracer.traceId === resTracer.traceId);
|
|
|
|
reqTracer = null;
|
|
resTracer = null;
|
|
|
|
res = await httpclient.request(url);
|
|
|
|
assert(res.status === 200);
|
|
assert(reqTracer === resTracer);
|
|
|
|
assert(reqTracer.traceId);
|
|
assert(reqTracer.traceId === resTracer.traceId);
|
|
});
|
|
|
|
it('should agent request auto set tracer', async () => {
|
|
const httpclient = app.agent.httpclient;
|
|
|
|
let reqTracer;
|
|
let resTracer;
|
|
|
|
httpclient.on('request', function(options) {
|
|
reqTracer = options.args.tracer;
|
|
});
|
|
|
|
httpclient.on('response', function(options) {
|
|
resTracer = options.req.args.tracer;
|
|
});
|
|
|
|
const res = await httpclient.request(url, {
|
|
method: 'GET',
|
|
});
|
|
|
|
assert(res.status === 200);
|
|
assert(reqTracer === resTracer);
|
|
|
|
assert(reqTracer.traceId);
|
|
assert(reqTracer.traceId === resTracer.traceId);
|
|
});
|
|
|
|
it('should app request with ctx and tracer', async () => {
|
|
const httpclient = app.httpclient;
|
|
|
|
let reqTracer;
|
|
let resTracer;
|
|
|
|
httpclient.on('request', function(options) {
|
|
reqTracer = options.args.tracer;
|
|
});
|
|
|
|
httpclient.on('response', function(options) {
|
|
resTracer = options.req.args.tracer;
|
|
});
|
|
|
|
let res = await httpclient.request(url, {
|
|
method: 'GET',
|
|
});
|
|
|
|
assert(res.status === 200);
|
|
|
|
assert(reqTracer.traceId);
|
|
assert(reqTracer.traceId === resTracer.traceId);
|
|
|
|
reqTracer = null;
|
|
resTracer = null;
|
|
res = await httpclient.request(url, {
|
|
method: 'GET',
|
|
ctx: {},
|
|
tracer: {
|
|
id: '1234',
|
|
},
|
|
});
|
|
|
|
assert(res.status === 200);
|
|
assert(reqTracer.id === resTracer.id);
|
|
assert(reqTracer.id === '1234');
|
|
|
|
reqTracer = null;
|
|
resTracer = null;
|
|
res = await httpclient.request(url, {
|
|
method: 'GET',
|
|
ctx: {
|
|
tracer: {
|
|
id: '5678',
|
|
},
|
|
},
|
|
});
|
|
|
|
assert(res.status === 200);
|
|
assert(reqTracer.id === resTracer.id);
|
|
assert(reqTracer.id === '5678');
|
|
});
|
|
});
|
|
|
|
describe('httpclient next with tracer', () => {
|
|
let app;
|
|
before(() => {
|
|
app = utils.app('apps/httpclient-next-with-tracer');
|
|
return app.ready();
|
|
});
|
|
|
|
after(() => app.close());
|
|
|
|
it('should app request auto set tracer', async () => {
|
|
const httpclient = app.httpclient;
|
|
|
|
let reqTracer;
|
|
let resTracer;
|
|
|
|
httpclient.on('request', function(options) {
|
|
reqTracer = options.args.tracer;
|
|
});
|
|
|
|
httpclient.on('response', function(options) {
|
|
resTracer = options.req.args.tracer;
|
|
});
|
|
|
|
const opaque = { now: Date.now() };
|
|
let res = await httpclient.request(url, {
|
|
method: 'GET',
|
|
dataType: 'text',
|
|
opaque,
|
|
});
|
|
assert(res.opaque === opaque);
|
|
|
|
assert(res.status === 200);
|
|
assert(reqTracer);
|
|
assert(resTracer);
|
|
assert(reqTracer === resTracer);
|
|
|
|
assert(reqTracer.traceId);
|
|
assert(reqTracer.traceId === resTracer.traceId);
|
|
|
|
reqTracer = null;
|
|
resTracer = null;
|
|
|
|
res = await httpclient.request(url);
|
|
|
|
assert(res.status === 200);
|
|
assert(reqTracer === resTracer);
|
|
|
|
assert(reqTracer.traceId);
|
|
assert(reqTracer.traceId === resTracer.traceId);
|
|
});
|
|
|
|
it('should agent request auto set tracer', async () => {
|
|
const httpclient = app.agent.httpclient;
|
|
|
|
let reqTracer;
|
|
let resTracer;
|
|
|
|
httpclient.on('request', function(options) {
|
|
reqTracer = options.args.tracer;
|
|
});
|
|
|
|
httpclient.on('response', function(options) {
|
|
resTracer = options.req.args.tracer;
|
|
});
|
|
|
|
const res = await httpclient.request(url, {
|
|
method: 'GET',
|
|
});
|
|
|
|
assert(res.status === 200);
|
|
assert(reqTracer === resTracer);
|
|
|
|
assert(reqTracer.traceId);
|
|
assert(reqTracer.traceId === resTracer.traceId);
|
|
});
|
|
|
|
it('should app request with ctx and tracer', async () => {
|
|
const httpclient = app.httpclient;
|
|
|
|
let reqTracer;
|
|
let resTracer;
|
|
|
|
httpclient.on('request', function(options) {
|
|
reqTracer = options.args.tracer;
|
|
});
|
|
|
|
httpclient.on('response', function(options) {
|
|
resTracer = options.req.args.tracer;
|
|
});
|
|
|
|
let res = await httpclient.request(url, {
|
|
method: 'GET',
|
|
});
|
|
|
|
assert(res.status === 200);
|
|
|
|
assert(reqTracer.traceId);
|
|
assert(reqTracer.traceId === resTracer.traceId);
|
|
|
|
reqTracer = null;
|
|
resTracer = null;
|
|
res = await httpclient.request(url, {
|
|
method: 'GET',
|
|
ctx: {},
|
|
tracer: {
|
|
id: '1234',
|
|
},
|
|
});
|
|
|
|
assert(res.status === 200);
|
|
assert(reqTracer.id === resTracer.id);
|
|
assert(reqTracer.id === '1234');
|
|
|
|
reqTracer = null;
|
|
resTracer = null;
|
|
res = await httpclient.request(url, {
|
|
method: 'GET',
|
|
ctx: {
|
|
tracer: {
|
|
id: '5678',
|
|
},
|
|
},
|
|
});
|
|
|
|
assert(res.status === 200);
|
|
assert(reqTracer.id === resTracer.id);
|
|
assert(reqTracer.id === '5678');
|
|
});
|
|
});
|
|
|
|
describe('before app ready multi httpclient request tracer', () => {
|
|
let app;
|
|
before(() => {
|
|
app = utils.app('apps/httpclient-tracer');
|
|
return app.ready();
|
|
});
|
|
|
|
after(() => app.close());
|
|
|
|
it('should app request before ready use same tracer', async () => {
|
|
|
|
const httpclient = app.httpclient;
|
|
const reqTracers = [];
|
|
const resTracers = [];
|
|
|
|
httpclient.on('request', function(options) {
|
|
reqTracers.push(options.args.tracer);
|
|
});
|
|
|
|
httpclient.on('response', function(options) {
|
|
resTracers.push(options.req.args.tracer);
|
|
});
|
|
|
|
let res = await httpclient.request(url, {
|
|
method: 'GET',
|
|
timeout: 20000,
|
|
});
|
|
assert(res.status === 200);
|
|
|
|
res = await httpclient.request('https://registry.npmmirror.com', {
|
|
method: 'GET',
|
|
timeout: 20000,
|
|
});
|
|
assert(res.status === 200);
|
|
|
|
res = await httpclient.request('https://npmmirror.com', {
|
|
method: 'GET',
|
|
timeout: 20000,
|
|
});
|
|
assert(res.status === 200);
|
|
|
|
assert(reqTracers.length === 3);
|
|
assert(resTracers.length === 3);
|
|
|
|
assert(reqTracers[0] !== reqTracers[1]);
|
|
assert(reqTracers[1] !== reqTracers[2]);
|
|
|
|
assert(resTracers[0] !== reqTracers[2]);
|
|
assert(resTracers[1] !== resTracers[0]);
|
|
assert(resTracers[2] !== resTracers[1]);
|
|
|
|
assert(reqTracers[0].traceId);
|
|
});
|
|
});
|
|
|
|
describe('compatibility freeSocketKeepAliveTimeout', () => {
|
|
it('should convert freeSocketKeepAliveTimeout to freeSocketTimeout', () => {
|
|
let mockApp = {
|
|
config: {
|
|
httpclient: {
|
|
request: {},
|
|
freeSocketKeepAliveTimeout: 1000,
|
|
httpAgent: {},
|
|
httpsAgent: {},
|
|
},
|
|
},
|
|
};
|
|
let client = new Httpclient(mockApp);
|
|
assert(client);
|
|
assert(mockApp.config.httpclient.freeSocketTimeout === 1000);
|
|
assert(!mockApp.config.httpclient.freeSocketKeepAliveTimeout);
|
|
assert(mockApp.config.httpclient.httpAgent.freeSocketTimeout === 1000);
|
|
assert(mockApp.config.httpclient.httpsAgent.freeSocketTimeout === 1000);
|
|
|
|
mockApp = {
|
|
config: {
|
|
httpclient: {
|
|
request: {},
|
|
httpAgent: {
|
|
freeSocketKeepAliveTimeout: 1001,
|
|
},
|
|
httpsAgent: {
|
|
freeSocketKeepAliveTimeout: 1002,
|
|
},
|
|
},
|
|
},
|
|
};
|
|
client = new Httpclient(mockApp);
|
|
assert(client);
|
|
assert(mockApp.config.httpclient.httpAgent.freeSocketTimeout === 1001);
|
|
assert(!mockApp.config.httpclient.httpAgent.freeSocketKeepAliveTimeout);
|
|
assert(mockApp.config.httpclient.httpsAgent.freeSocketTimeout === 1002);
|
|
assert(!mockApp.config.httpclient.httpsAgent.freeSocketKeepAliveTimeout);
|
|
});
|
|
});
|
|
|
|
describe('httpclient retry', () => {
|
|
let app;
|
|
before(() => {
|
|
app = utils.app('apps/httpclient-retry');
|
|
return app.ready();
|
|
});
|
|
after(() => app.close());
|
|
|
|
it('should retry when httpclient fail', async () => {
|
|
let hasRetry = false;
|
|
const res = await app.httpclient.curl(`${url}/retry`, {
|
|
retry: 1,
|
|
retryDelay: 100,
|
|
isRetry(res) {
|
|
const shouldRetry = res.status >= 500;
|
|
if (shouldRetry) {
|
|
hasRetry = true;
|
|
}
|
|
return shouldRetry;
|
|
},
|
|
});
|
|
|
|
assert(hasRetry);
|
|
assert(res.status === 200);
|
|
});
|
|
|
|
it('should retry when httpclient fail', async () => {
|
|
let hasRetry = false;
|
|
const res = await app.httpclient.curl(`${url}/retry`, {
|
|
retry: 1,
|
|
retryDelay: 100,
|
|
isRetry(res) {
|
|
const shouldRetry = res.status >= 500;
|
|
if (shouldRetry) {
|
|
hasRetry = true;
|
|
}
|
|
return shouldRetry;
|
|
},
|
|
});
|
|
|
|
assert(hasRetry);
|
|
assert(res.status === 200);
|
|
});
|
|
});
|
|
});
|