Comparing version 3.2.0 to 3.3.0
'use strict' | ||
/* global WeakRef, FinalizationRegistry */ | ||
const { InvalidArgumentError, InvalidReturnValueError } = require('./core/errors') | ||
const Pool = require('./pool') | ||
const { weakCache } = require('./core/util') | ||
const util = require('./core/util') | ||
const { kAgentOpts, kAgentCache, kAgentCleanup } = require('./core/symbols') | ||
const kAgentFactory = Symbol('agent factory') | ||
class Agent { | ||
constructor (opts) { | ||
this[kAgentFactory] = weakCache(origin => new Pool(origin, opts)) | ||
this[kAgentOpts] = opts | ||
this[kAgentCache] = new Map() | ||
this[kAgentCleanup] = new FinalizationRegistry(key => { | ||
// get the WeakRef from the cache | ||
const ref = this[kAgentCache].get(key) | ||
// if the WeakRef exists and the object has been reclaimed | ||
if (ref !== undefined && ref.deref() === undefined) { | ||
// remove the WeakRef from the cache | ||
this[kAgentCache].delete(key) | ||
} | ||
}) | ||
} | ||
@@ -19,4 +29,46 @@ | ||
return this[kAgentFactory](origin) | ||
// check the cache for an existing WeakRef | ||
const ref = this[kAgentCache].get(origin) | ||
// if one exists in the cache try to return the WeakRef | ||
if (ref !== undefined) { | ||
const cached = ref.deref() | ||
if (cached !== undefined) { | ||
return cached | ||
} | ||
} | ||
// otherwise, if it isn't in the cache or the reference has been cleaned up, create a new one! | ||
const value = new Pool(origin, this[kAgentOpts]) | ||
// add a WeakRef of the value to the cache | ||
this[kAgentCache].set(origin, new WeakRef(value)) | ||
// add the value to the finalization registry | ||
this[kAgentCleanup].register(value, origin) | ||
return value | ||
} | ||
close () { | ||
const closePromises = [] | ||
for (const ref of this[kAgentCache].values()) { | ||
const pool = ref.deref() | ||
if (pool) { | ||
closePromises.push(pool.close()) | ||
} | ||
} | ||
return Promise.all(closePromises) | ||
} | ||
destroy () { | ||
const destroyPromises = [] | ||
for (const ref of this[kAgentCache].values()) { | ||
const pool = ref.deref() | ||
if (pool) { | ||
destroyPromises.push(pool.destroy()) | ||
} | ||
} | ||
return Promise.all(destroyPromises) | ||
} | ||
} | ||
@@ -40,10 +92,2 @@ | ||
return (url, { agent = globalAgent, method = 'GET', ...opts } = {}, ...additionalArgs) => { | ||
if (url === undefined || url === null) { | ||
throw new InvalidArgumentError('Argument url must be defined') | ||
} | ||
if (!agent || typeof agent.get !== 'function') { | ||
throw new InvalidArgumentError('Argument agent must implement Agent') | ||
} | ||
if (opts.path != null) { | ||
@@ -53,11 +97,8 @@ throw new InvalidArgumentError('unsupported opts.path') | ||
// if url is a string transform into URL inst. otherwise use as is | ||
url = typeof url === 'string' ? new URL(url) : url | ||
// ensure it atleast has a non-empty string origin | ||
if (!url || typeof url.origin !== 'string' || url.origin === '') { | ||
throw new InvalidArgumentError('Argument url.origin must be a non-empty string') | ||
} | ||
const { origin, pathname, search } = util.parseURL(url) | ||
const client = agent.get(url.origin) | ||
const path = `${pathname || '/'}${search || ''}` | ||
const client = agent.get(origin) | ||
if (client && typeof client[requestType] !== 'function') { | ||
@@ -67,4 +108,2 @@ throw new InvalidReturnValueError(`Client returned from Agent.get() does not implement method ${requestType}`) | ||
const path = url.path || `${url.pathname || '/'}${url.search || ''}` | ||
return client[requestType]({ ...opts, method, path }, ...additionalArgs) | ||
@@ -71,0 +110,0 @@ } |
@@ -7,2 +7,3 @@ 'use strict' | ||
const { addSignal, removeSignal } = require('./abort-signal') | ||
const assert = require('assert') | ||
@@ -41,2 +42,4 @@ class UpgradeHandler extends AsyncResource { | ||
assert.strictEqual(statusCode, 101) | ||
removeSignal(this) | ||
@@ -43,0 +46,0 @@ |
'use strict' | ||
const { URL } = require('url') | ||
const net = require('net') | ||
@@ -111,14 +110,6 @@ const tls = require('tls') | ||
if (typeof url === 'string') { | ||
url = new URL(url) | ||
if (maxHeaderSize != null && !Number.isFinite(maxHeaderSize)) { | ||
throw new InvalidArgumentError('invalid maxHeaderSize') | ||
} | ||
if (!url || typeof url !== 'object') { | ||
throw new InvalidArgumentError('invalid url') | ||
} | ||
if (url.port != null && url.port !== '' && !Number.isFinite(parseInt(url.port))) { | ||
throw new InvalidArgumentError('invalid port') | ||
} | ||
if (socketPath != null && typeof socketPath !== 'string') { | ||
@@ -128,18 +119,2 @@ throw new InvalidArgumentError('invalid socketPath') | ||
if (url.hostname != null && typeof url.hostname !== 'string') { | ||
throw new InvalidArgumentError('invalid hostname') | ||
} | ||
if (!/https?/.test(url.protocol)) { | ||
throw new InvalidArgumentError('invalid protocol') | ||
} | ||
if (/\/.+/.test(url.pathname) || url.search || url.hash) { | ||
throw new InvalidArgumentError('invalid url') | ||
} | ||
if (maxHeaderSize != null && !Number.isFinite(maxHeaderSize)) { | ||
throw new InvalidArgumentError('invalid maxHeaderSize') | ||
} | ||
if (keepAliveTimeout != null && (!Number.isFinite(keepAliveTimeout) || keepAliveTimeout <= 0)) { | ||
@@ -168,3 +143,3 @@ throw new InvalidArgumentError('invalid keepAliveTimeout') | ||
this[kMaxHeadersSize] = maxHeaderSize || 16384 | ||
this[kUrl] = url | ||
this[kUrl] = util.parseOrigin(url) | ||
this[kSocketPath] = socketPath | ||
@@ -202,2 +177,6 @@ this[kKeepAliveDefaultTimeout] = keepAliveTimeout == null ? 4e3 : keepAliveTimeout | ||
get url () { | ||
return this[kUrl] | ||
} | ||
get pipelining () { | ||
@@ -204,0 +183,0 @@ return this[kPipelining] |
@@ -34,3 +34,6 @@ module.exports = { | ||
kTLSSession: Symbol('tls session cache'), | ||
kHostHeader: Symbol('host header') | ||
kHostHeader: Symbol('host header'), | ||
kAgentOpts: Symbol('agent opts'), | ||
kAgentCache: Symbol('agent cache'), | ||
kAgentCleanup: Symbol('agent cleanup') | ||
} |
'use strict' | ||
/* global WeakRef, FinalizationRegistry */ | ||
@@ -9,3 +8,3 @@ const assert = require('assert') | ||
const net = require('net') | ||
const { NotSupportedError } = require('./errors') | ||
const { InvalidArgumentError } = require('./errors') | ||
@@ -18,2 +17,46 @@ function nop () {} | ||
function parseURL (url) { | ||
if (typeof url === 'string') { | ||
url = new URL(url) | ||
} | ||
if (!url || typeof url !== 'object') { | ||
throw new InvalidArgumentError('invalid url') | ||
} | ||
if (url.port != null && url.port !== '' && !Number.isFinite(parseInt(url.port))) { | ||
throw new InvalidArgumentError('invalid port') | ||
} | ||
if (url.hostname != null && typeof url.hostname !== 'string') { | ||
throw new InvalidArgumentError('invalid hostname') | ||
} | ||
if (!/https?/.test(url.protocol)) { | ||
throw new InvalidArgumentError('invalid protocol') | ||
} | ||
if (!(url instanceof URL)) { | ||
const port = url.port || { | ||
'http:': 80, | ||
'https:': 443 | ||
}[url.protocol] | ||
assert(port != null) | ||
const path = url.path || `${url.pathname || '/'}${url.search || ''}` | ||
url = new URL(`${url.protocol}//${url.hostname}:${port}${path}`) | ||
} | ||
return url | ||
} | ||
function parseOrigin (url) { | ||
url = parseURL(url) | ||
if (/\/.+/.test(url.pathname) || url.search || url.hash) { | ||
throw new InvalidArgumentError('invalid url') | ||
} | ||
return url | ||
} | ||
function getServerName (host) { | ||
@@ -116,43 +159,6 @@ if (!host) { | ||
/* istanbul ignore next: https://github.com/tc39/proposal-weakrefs */ | ||
function weakCache (fn) { | ||
/* istanbul ignore next: */ | ||
if (typeof WeakRef === 'undefined' || typeof FinalizationRegistry === 'undefined') { | ||
throw new NotSupportedError('In order to use this feature, `WeakRef` and `FinalizationRegistry` must be defined as global objects. Check your Node.js version to be sure it is v14.6.0 or greater.') | ||
} | ||
const cache = new Map() | ||
const cleanup = new FinalizationRegistry(key => { | ||
// get the WeakRef from the cache | ||
const ref = cache.get(key) | ||
// if the WeakRef exists and the object has been reclaimed | ||
if (ref !== undefined && ref.deref() === undefined) { | ||
// remove the WeakRef from the cache | ||
cache.delete(key) | ||
} | ||
}) | ||
return key => { | ||
// check the cache for an existing WeakRef | ||
const ref = cache.get(key) | ||
// if one exists in the cache try to return the WeakRef | ||
if (ref !== undefined) { | ||
const cached = ref.deref() | ||
if (cached !== undefined) { | ||
return cached | ||
} | ||
} | ||
// otherwise, if it isn't in the cache or the reference has been cleaned up, create a new one! | ||
const value = fn(key) | ||
// add a WeakRef of the value to the cache | ||
cache.set(key, new WeakRef(value)) | ||
// add the value to the finalization registry | ||
cleanup.register(value, key) | ||
return value | ||
} | ||
} | ||
module.exports = { | ||
nop, | ||
parseOrigin, | ||
parseURL, | ||
getServerName, | ||
@@ -166,4 +172,3 @@ errnoException, | ||
bodyLength, | ||
isBuffer, | ||
weakCache | ||
isBuffer | ||
} |
@@ -11,4 +11,6 @@ 'use strict' | ||
const FixedQueue = require('./node/fixed-queue') | ||
const util = require('./core/util') | ||
const kClients = Symbol('clients') | ||
const kNeedDrain = Symbol('needDrain') | ||
const kQueue = Symbol('queue') | ||
@@ -23,8 +25,11 @@ const kDestroyed = Symbol('destroyed') | ||
const kOnDisconnect = Symbol('onDisconnect') | ||
const kPending = Symbol('pending') | ||
const kConnected = Symbol('connected') | ||
const kConnections = Symbol('connections') | ||
class Pool extends EventEmitter { | ||
constructor (url, options = {}) { | ||
constructor (origin, opts = {}) { | ||
super() | ||
const { connections } = options | ||
const { connections, ...options } = opts | ||
@@ -35,3 +40,4 @@ if (connections != null && (!Number.isFinite(connections) || connections < 0)) { | ||
this[kUrl] = url | ||
this[kConnections] = connections || null | ||
this[kUrl] = util.parseOrigin(origin) | ||
this[kOptions] = JSON.parse(JSON.stringify(options)) | ||
@@ -43,2 +49,5 @@ this[kQueue] = new FixedQueue() | ||
this[kClients] = [] | ||
this[kNeedDrain] = false | ||
this[kPending] = 0 | ||
this[kConnected] = 0 | ||
@@ -55,6 +64,12 @@ const pool = this | ||
} | ||
pool[kPending]-- | ||
this.dispatch(item.opts, item.handler) | ||
} | ||
if (pool[kClosedResolve] && queue.isEmpty()) { | ||
if (pool[kNeedDrain] && !pool[kPending]) { | ||
pool[kNeedDrain] = false | ||
pool.emit('drain') | ||
} | ||
if (pool[kClosedResolve] && !pool[kPending]) { | ||
Promise | ||
@@ -67,10 +82,40 @@ .all(pool[kClients].map(c => c.close())) | ||
this[kOnConnect] = function onConnect () { | ||
pool[kConnected]++ | ||
pool.emit('connect', this) | ||
} | ||
this[kOnDisconnect] = function onDisconnect () { | ||
pool.emit('disconnect', this) | ||
this[kOnDisconnect] = function onDisconnect (err) { | ||
pool[kConnected]-- | ||
pool.emit('disconnect', this, err) | ||
} | ||
} | ||
get url () { | ||
return this[kUrl] | ||
} | ||
get connected () { | ||
return this[kConnected] | ||
} | ||
get busy () { | ||
return this[kPending] > 0 | ||
} | ||
get pending () { | ||
return this[kPending] | ||
} | ||
// TODO: get running () {} | ||
// TODO: get size () {} | ||
get destroyed () { | ||
return this[kDestroyed] | ||
} | ||
get closed () { | ||
return this[kClosedPromise] != null | ||
} | ||
dispatch (opts, handler) { | ||
@@ -89,5 +134,4 @@ try { | ||
if (!client) { | ||
const { connections, ...options } = this[kOptions] | ||
if (!connections || this[kClients].length < connections) { | ||
client = new Client(this[kUrl], options) | ||
if (!this[kConnections] || this[kClients].length < this[kConnections]) { | ||
client = new Client(this[kUrl], this[kOptions]) | ||
.on('drain', this[kOnDrain]) | ||
@@ -102,3 +146,5 @@ .on('connect', this[kOnConnect]) | ||
if (!client) { | ||
this[kNeedDrain] = true | ||
this[kQueue].push({ opts, handler }) | ||
this[kPending]++ | ||
} else { | ||
@@ -130,2 +176,5 @@ client.dispatch(opts, handler) | ||
} | ||
this[kClosedPromise] = this[kClosedPromise].then(() => { | ||
this[kDestroyed] = true | ||
}) | ||
} | ||
@@ -132,0 +181,0 @@ |
{ | ||
"name": "undici", | ||
"version": "3.2.0", | ||
"version": "3.3.0", | ||
"description": "An HTTP/1.1 client, written from scratch for Node.js", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -52,3 +52,3 @@ # undici | ||
for await (const data of body) { | ||
console.log('data', chunk) | ||
console.log('data', data) | ||
} | ||
@@ -511,2 +511,6 @@ | ||
#### `client.url: URL` | ||
Returns url passed to `undici.Pool(url, opts)`. | ||
#### `client.pipelining: Number` | ||
@@ -575,2 +579,28 @@ | ||
#### `pool.url: URL` | ||
Returns url passed to `undici.Pool(url, opts)`. | ||
#### `pool.connected: Integer` | ||
Number of active connections in pool. | ||
#### `pool.pending: Number` | ||
Number of queued requests. | ||
#### `pool.busy: Boolean` | ||
True if pool is saturated or blocked. Indicates whether dispatching | ||
further requests is meaningful. | ||
#### `pool.closed: Boolean` | ||
True after `pool.close()` has been called. | ||
#### `pool.destroyed: Boolean` | ||
True after `pool.destroyed()` has been called or `pool.close()` has been | ||
called and the client shutdown has completed. | ||
#### `pool.request(opts[, callback]): Promise|Void` | ||
@@ -610,31 +640,12 @@ | ||
* `'drain'`, emitted when pool is no longer fully | ||
saturated. | ||
* `'connect'`, emitted when a client has connected, the `Client` | ||
instance is passed as argument. | ||
* `'disconnect'`, emitted when a client has disconnected, the `Client` | ||
instance is passed as argument. | ||
* `'disconnect'`, emitted when a client has disconnected. The first argument is the | ||
`Client` instance, the second is the the error that caused the disconnection. | ||
<a name='errors'></a> | ||
### `undici.errors` | ||
Undici exposes a variety of error objects that you can use to enhance your error handling. | ||
You can find all the error objects inside the `errors` key. | ||
```js | ||
const { errors } = require('undici') | ||
``` | ||
| Error | Error Codes | Description | | ||
| -----------------------------|-----------------------------------|------------------------------------------------| | ||
| `InvalidArgumentError` | `UND_ERR_INVALID_ARG` | passed an invalid argument. | | ||
| `InvalidReturnValueError` | `UND_ERR_INVALID_RETURN_VALUE` | returned an invalid value. | | ||
| `RequestAbortedError` | `UND_ERR_ABORTED` | the request has been aborted by the user | | ||
| `ClientDestroyedError` | `UND_ERR_DESTROYED` | trying to use a destroyed client. | | ||
| `ClientClosedError` | `UND_ERR_CLOSED` | trying to use a closed client. | | ||
| `SocketError` | `UND_ERR_SOCKET` | there is an error with the socket. | | ||
| `NotSupportedError` | `UND_ERR_NOT_SUPPORTED` | encountered unsupported functionality. | | ||
| `ContentLengthMismatchError` | `UND_ERR_CONTENT_LENGTH_MISMATCH`| body does not match content-length header | | ||
| `InformationalError` | `UND_ERR_INFO` | expected error with reason | | ||
| `TrailerMismatchError` | `UND_ERR_TRAILER_MISMATCH` | trailers did not match specification | | ||
<a name='agent'></a> | ||
### `new undici.Agent(opts)` | ||
@@ -726,2 +737,25 @@ | ||
<a name='errors'></a> | ||
### `undici.errors` | ||
Undici exposes a variety of error objects that you can use to enhance your error handling. | ||
You can find all the error objects inside the `errors` key. | ||
```js | ||
const { errors } = require('undici') | ||
``` | ||
| Error | Error Codes | Description | | ||
| -----------------------------|-----------------------------------|------------------------------------------------| | ||
| `InvalidArgumentError` | `UND_ERR_INVALID_ARG` | passed an invalid argument. | | ||
| `InvalidReturnValueError` | `UND_ERR_INVALID_RETURN_VALUE` | returned an invalid value. | | ||
| `RequestAbortedError` | `UND_ERR_ABORTED` | the request has been aborted by the user | | ||
| `ClientDestroyedError` | `UND_ERR_DESTROYED` | trying to use a destroyed client. | | ||
| `ClientClosedError` | `UND_ERR_CLOSED` | trying to use a closed client. | | ||
| `SocketError` | `UND_ERR_SOCKET` | there is an error with the socket. | | ||
| `NotSupportedError` | `UND_ERR_NOT_SUPPORTED` | encountered unsupported functionality. | | ||
| `ContentLengthMismatchError` | `UND_ERR_CONTENT_LENGTH_MISMATCH`| body does not match content-length header | | ||
| `InformationalError` | `UND_ERR_INFO` | expected error with reason | | ||
| `TrailerMismatchError` | `UND_ERR_TRAILER_MISMATCH` | trailers did not match specification | | ||
## Specification Compliance | ||
@@ -728,0 +762,0 @@ |
@@ -8,2 +8,3 @@ 'use strict' | ||
const { InvalidArgumentError, InvalidReturnValueError } = require('../lib/core/errors') | ||
const { errors } = require('..') | ||
@@ -13,3 +14,3 @@ const SKIP = typeof WeakRef === 'undefined' || typeof FinalizationRegistry === 'undefined' | ||
tap.test('Agent', { skip: SKIP }, t => { | ||
t.plan(5) | ||
t.plan(6) | ||
@@ -45,2 +46,85 @@ t.test('setGlobalAgent', t => { | ||
t.test('Agent close and destroy', t => { | ||
t.plan(2) | ||
t.test('agent should close internal pools', t => { | ||
t.plan(2) | ||
const wanted = 'payload' | ||
const server = http.createServer((req, res) => { | ||
res.setHeader('Content-Type', 'text/plain') | ||
res.end(wanted) | ||
}) | ||
t.tearDown(server.close.bind(server)) | ||
server.listen(0, () => { | ||
const agent = new Agent() | ||
const origin = `http://localhost:${server.address().port}` | ||
request(origin, { agent }) | ||
.then(() => { | ||
t.pass('first request should resolve') | ||
}) | ||
.catch(err => { | ||
t.fail(err) | ||
}) | ||
const pool = agent.get(origin) | ||
pool.once('connect', () => { | ||
agent.close().then(() => { | ||
request(origin, { agent }) | ||
.then(() => { | ||
t.fail('second request should not resolve') | ||
}) | ||
.catch(err => { | ||
t.error(err instanceof errors.ClientClosedError) | ||
}) | ||
}) | ||
}) | ||
}) | ||
}) | ||
t.test('agent should destroy internal pools', t => { | ||
t.plan(2) | ||
const wanted = 'payload' | ||
const server = http.createServer((req, res) => { | ||
res.setHeader('Content-Type', 'text/plain') | ||
res.end(wanted) | ||
}) | ||
t.tearDown(server.close.bind(server)) | ||
server.listen(0, () => { | ||
const agent = new Agent() | ||
const origin = `http://localhost:${server.address().port}` | ||
request(origin, { agent }) | ||
.then(() => { | ||
t.fail() | ||
}) | ||
.catch(err => { | ||
t.ok(err instanceof errors.ClientDestroyedError) | ||
}) | ||
const pool = agent.get(origin) | ||
pool.once('connect', () => { | ||
agent.destroy().then(() => { | ||
request(origin, { agent }) | ||
.then(() => { | ||
t.fail() | ||
}) | ||
.catch(err => { | ||
t.ok(err instanceof errors.ClientDestroyedError) | ||
}) | ||
}) | ||
}) | ||
}) | ||
}) | ||
}) | ||
t.test('request a resource', t => { | ||
@@ -47,0 +131,0 @@ t.plan(5) |
@@ -12,3 +12,3 @@ 'use strict' | ||
test('basic get', (t) => { | ||
t.plan(23) | ||
t.plan(24) | ||
@@ -38,2 +38,4 @@ const server = createServer((req, res) => { | ||
t.strictEqual(client.url.origin, `http://localhost:${server.address().port}`) | ||
const signal = new EE() | ||
@@ -621,3 +623,3 @@ client.request({ | ||
port: server.address().port, | ||
protocol: 'http' | ||
protocol: 'http:' | ||
}) | ||
@@ -648,3 +650,3 @@ t.tearDown(client.close.bind(client)) | ||
port: server.address().port, | ||
protocol: 'http' | ||
protocol: 'http:' | ||
}) | ||
@@ -672,3 +674,3 @@ t.tearDown(client.close.bind(client)) | ||
port: server.address().port, | ||
protocol: 'http' | ||
protocol: 'http:' | ||
}) | ||
@@ -675,0 +677,0 @@ t.tearDown(client.destroy.bind(client)) |
@@ -18,3 +18,3 @@ 'use strict' | ||
t.plan(clients * 3) | ||
t.plan(clients * 6) | ||
@@ -40,4 +40,7 @@ const server = createServer((req, res) => { | ||
}) | ||
pool.on('disconnect', (client) => { | ||
t.strictEqual(client instanceof Client, true) | ||
pool.on('disconnect', (client, error) => { | ||
t.true(client instanceof Client) | ||
t.true(error instanceof errors.InformationalError) | ||
t.strictEqual(error.code, 'UND_ERR_INFO') | ||
t.strictEqual(error.message, 'socket idle timeout') | ||
}) | ||
@@ -58,3 +61,3 @@ | ||
test('basic get', (t) => { | ||
t.plan(9) | ||
t.plan(14) | ||
@@ -73,2 +76,4 @@ const server = createServer((req, res) => { | ||
t.strictEqual(client.url.origin, `http://localhost:${server.address().port}`) | ||
client.request({ path: '/', method: 'GET' }, (err, { statusCode, headers, body }) => { | ||
@@ -87,4 +92,7 @@ t.error(err) | ||
t.strictEqual(client.destroyed, false) | ||
t.strictEqual(client.closed, false) | ||
client.close((err) => { | ||
t.error(err) | ||
t.strictEqual(client.destroyed, true) | ||
client.destroy((err) => { | ||
@@ -97,4 +105,6 @@ t.error(err) | ||
}) | ||
t.strictEqual(client.closed, true) | ||
}) | ||
}) | ||
test('URL as arg', (t) => { | ||
@@ -141,2 +151,3 @@ t.plan(9) | ||
}) | ||
test('basic get error async/await', (t) => { | ||
@@ -340,3 +351,3 @@ t.plan(2) | ||
test('busy', (t) => { | ||
t.plan(8 * 6) | ||
t.plan(8 * 8 + 2 + 1) | ||
@@ -356,5 +367,13 @@ const server = createServer((req, res) => { | ||
}) | ||
let connected = 0 | ||
client.on('drain', () => { | ||
t.pass() | ||
}) | ||
client.on('connect', () => { | ||
t.strictEqual(client.connected, ++connected) | ||
}) | ||
t.tearDown(client.destroy.bind(client)) | ||
for (let n = 0; n < 8; ++n) { | ||
for (let n = 1; n <= 8; ++n) { | ||
client.request({ path: '/', method: 'GET' }, (err, { statusCode, headers, body }) => { | ||
@@ -372,2 +391,4 @@ t.error(err) | ||
}) | ||
t.strictEqual(client.pending, Math.max(n - 2, 0)) | ||
t.strictEqual(client.busy, n > 2) | ||
} | ||
@@ -986,3 +1007,3 @@ }) | ||
test('pool destroy fails queued requests', (t) => { | ||
t.plan(4) | ||
t.plan(6) | ||
@@ -1016,5 +1037,7 @@ const server = createServer((req, res) => { | ||
t.strictEqual(client.destroyed, false) | ||
client.destroy(_err, () => { | ||
t.pass() | ||
}) | ||
t.strictEqual(client.destroyed, true) | ||
@@ -1021,0 +1044,0 @@ client.request({ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
426962
13565
801