Skip to content

Commit b8b0192

Browse files
FlarnaRafaelGSS
authored andcommitted
test: add ALS test using http agent keep alive
Add a test to verify AsyncLocalStore functionality for HTTP using a keep alive agent. AsyncLocalStore moves away from using async_hooks therefore relying on async_hooks tests alone is not longer valid. PR-URL: #58017 Refs: #55712 Refs: #13325 Reviewed-By: Luigi Pinca <luigipinca@gmail.com> Reviewed-By: Stephen Belanger <admin@stephenbelanger.com> Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent 5e9cac2 commit b8b0192

File tree

1 file changed

+83
-0
lines changed

1 file changed

+83
-0
lines changed
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
'use strict';
2+
const common = require('../common');
3+
const assert = require('node:assert');
4+
const { AsyncLocalStorage } = require('node:async_hooks');
5+
const http = require('node:http');
6+
7+
// Similar as test-async-hooks-http-agent added via
8+
// https://github.com/nodejs/node/issues/13325 but verifies
9+
// AsyncLocalStorage functionality instead async_hooks
10+
11+
const cls = new AsyncLocalStorage();
12+
13+
// Make sure a single socket is transparently reused for 2 requests.
14+
const agent = new http.Agent({
15+
keepAlive: true,
16+
keepAliveMsecs: Infinity,
17+
maxSockets: 1
18+
});
19+
20+
const server = http.createServer(common.mustCall((req, res) => {
21+
req.once('data', common.mustCallAtLeast(() => {
22+
res.writeHead(200, { 'Content-Type': 'text/plain' });
23+
res.write('foo');
24+
}));
25+
req.on('end', common.mustCall(() => {
26+
res.end('bar');
27+
}));
28+
}, 2)).listen(0, common.mustCall(() => {
29+
const port = server.address().port;
30+
const payload = 'hello world';
31+
32+
// First request. This is useless except for adding a socket to the
33+
// agent’s pool for reuse.
34+
cls.run('first', common.mustCall(() => {
35+
assert.strictEqual(cls.getStore(), 'first');
36+
const r1 = http.request({
37+
agent, port, method: 'POST'
38+
}, common.mustCall((res) => {
39+
assert.strictEqual(cls.getStore(), 'first');
40+
res.on('data', common.mustCallAtLeast(() => {
41+
assert.strictEqual(cls.getStore(), 'first');
42+
}));
43+
res.on('end', common.mustCall(() => {
44+
assert.strictEqual(cls.getStore(), 'first');
45+
// setImmediate() to give the agent time to register the freed socket.
46+
setImmediate(common.mustCall(() => {
47+
assert.strictEqual(cls.getStore(), 'first');
48+
49+
cls.run('second', common.mustCall(() => {
50+
// Second request. To re-create the exact conditions from the
51+
// referenced issue, we use a POST request without chunked encoding
52+
// (hence the Content-Length header) and call .end() after the
53+
// response header has already been received.
54+
const r2 = http.request({
55+
agent, port, method: 'POST', headers: {
56+
'Content-Length': payload.length
57+
}
58+
}, common.mustCall((res) => {
59+
assert.strictEqual(cls.getStore(), 'second');
60+
// Empty payload, to hit the “right” code path.
61+
r2.end('');
62+
63+
res.on('data', common.mustCallAtLeast(() => {
64+
assert.strictEqual(cls.getStore(), 'second');
65+
}));
66+
res.on('end', common.mustCall(() => {
67+
assert.strictEqual(cls.getStore(), 'second');
68+
// Clean up to let the event loop stop.
69+
server.close();
70+
agent.destroy();
71+
}));
72+
}));
73+
74+
// Schedule a payload to be written immediately, but do not end the
75+
// request just yet.
76+
r2.write(payload);
77+
}));
78+
}));
79+
}));
80+
}));
81+
r1.end(payload);
82+
}));
83+
}));

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy