From d24c5efa1565d6238c272c70e409db152443d5ea Mon Sep 17 00:00:00 2001 From: Harshitha KP Date: Wed, 4 Mar 2020 01:46:05 -0500 Subject: [PATCH 1/3] test: add new scenario for async-local storage Add a new scenario of multiple clients sharing a single data callback function managing their response data through AsyncLocalStorage APIs Refs: https://github.com/nodejs/node/pull/32063 Refs: https://github.com/nodejs/node/issues/32060 Refs: https://github.com/nodejs/node/issues/32062#issuecomment-593957787 Co-authored-by: Gireesh Punathil --- ...t-async-local-storage-http-multiclients.js | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 test/parallel/test-async-local-storage-http-multiclients.js diff --git a/test/parallel/test-async-local-storage-http-multiclients.js b/test/parallel/test-async-local-storage-http-multiclients.js new file mode 100644 index 00000000000000..86b6f32cd3068b --- /dev/null +++ b/test/parallel/test-async-local-storage-http-multiclients.js @@ -0,0 +1,64 @@ +'use strict'; +const common = require('../common'); + +const assert = require('assert'); +const { AsyncLocalStorage } = require('async_hooks'); +const http = require('http'); +const cls = new AsyncLocalStorage(); +const NUM_CLIENTS = 10; + +// Run multiple clients that receive data from a server +// in multiple chunks, in a single non-closure function. +// Use the AsyncLocalStorage (ALS) APIs to maintain the context +// and data download. Make sure that individual clients +// receive their respective data, with no conflicts. + +// Set up a server, that sends large buffers of data, filled +// with cardinal numbers, increasing per request +let index = 0; +const server = http.createServer((q, r) => { + // Send a large chunk as response, otherwise the data + // may be coalesced, and the callback in the client + // may be called only once, defeating the purpose of test + r.end((index++).toString().repeat(1024 * 1024)); +}); + +server.listen(0, common.mustCall(() => { + for (let i = 0; i < NUM_CLIENTS; i++) { + cls.run(new Map(), common.mustCall(() => { + const options = { port: server.address().port }; + const req = http.get(options, common.mustCall((res) => { + const store = cls.getStore(); + store.set('data', ''); + + // Make ondata and onend non-closure + // functions and fully dependent on ALS + res.on('data', ondata); + res.on('end', onend); + })); + req.end(); + })); + } +})); + +// Accumulate the instantaneous data with the store data +function ondata(d) { + const store = cls.getStore(); + assert.notStrictEqual(store, undefined); + let chunk = store.get('data'); + chunk += d; + store.set('data', chunk); +} + +// Retrieve the store data, and test for homogeneity +let endCount = 0; +function onend() { + const store = cls.getStore(); + assert.notStrictEqual(store, undefined); + const chunk = store.get('data'); + const re = new RegExp(chunk[0], 'g'); + assert.strictEqual(chunk.replace(re, '').length, 0); + if (++endCount === NUM_CLIENTS) { + server.close(); + } +} From 59965cd015de0ae3fef12f0c7a7acf3a39b46a6c Mon Sep 17 00:00:00 2001 From: Harshitha KP Date: Wed, 4 Mar 2020 03:06:52 -0500 Subject: [PATCH 2/3] fixup: address review comments --- ...t-async-local-storage-http-multiclients.js | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/test/parallel/test-async-local-storage-http-multiclients.js b/test/parallel/test-async-local-storage-http-multiclients.js index 86b6f32cd3068b..2c873ae25001b5 100644 --- a/test/parallel/test-async-local-storage-http-multiclients.js +++ b/test/parallel/test-async-local-storage-http-multiclients.js @@ -1,6 +1,5 @@ 'use strict'; const common = require('../common'); - const assert = require('assert'); const { AsyncLocalStorage } = require('async_hooks'); const http = require('http'); @@ -13,14 +12,14 @@ const NUM_CLIENTS = 10; // and data download. Make sure that individual clients // receive their respective data, with no conflicts. -// Set up a server, that sends large buffers of data, filled +// Set up a server that sends large buffers of data, filled // with cardinal numbers, increasing per request let index = 0; const server = http.createServer((q, r) => { // Send a large chunk as response, otherwise the data - // may be coalesced, and the callback in the client - // may be called only once, defeating the purpose of test - r.end((index++).toString().repeat(1024 * 1024)); + // may be sent in a single chunk, and the callback in the + // client may be called only once, defeating the purpose of test + r.end((index++ % 10).toString().repeat(1024 * 1024)); }); server.listen(0, common.mustCall(() => { @@ -33,15 +32,16 @@ server.listen(0, common.mustCall(() => { // Make ondata and onend non-closure // functions and fully dependent on ALS + res.setEncoding('utf8'); res.on('data', ondata); - res.on('end', onend); + res.on('end', common.mustCall(onend)); })); req.end(); })); } })); -// Accumulate the instantaneous data with the store data +// Accumulate the current data chunk with the store data function ondata(d) { const store = cls.getStore(); assert.notStrictEqual(store, undefined); @@ -55,9 +55,8 @@ let endCount = 0; function onend() { const store = cls.getStore(); assert.notStrictEqual(store, undefined); - const chunk = store.get('data'); - const re = new RegExp(chunk[0], 'g'); - assert.strictEqual(chunk.replace(re, '').length, 0); + const data = store.get('data'); + assert.strictEqual(data, data[0].repeat(data.length)); if (++endCount === NUM_CLIENTS) { server.close(); } From 6b9f0f6621affa8e772103dc254ec3ac7db29953 Mon Sep 17 00:00:00 2001 From: Harshitha K P Date: Thu, 12 Mar 2020 16:02:12 +0530 Subject: [PATCH 3/3] fixup: address review comment --- .../test-async-local-storage-http-multiclients.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/test/parallel/test-async-local-storage-http-multiclients.js b/test/parallel/test-async-local-storage-http-multiclients.js index 2c873ae25001b5..1903d5825d75ba 100644 --- a/test/parallel/test-async-local-storage-http-multiclients.js +++ b/test/parallel/test-async-local-storage-http-multiclients.js @@ -1,5 +1,6 @@ 'use strict'; const common = require('../common'); +const Countdown = require('../common/countdown'); const assert = require('assert'); const { AsyncLocalStorage } = require('async_hooks'); const http = require('http'); @@ -22,6 +23,10 @@ const server = http.createServer((q, r) => { r.end((index++ % 10).toString().repeat(1024 * 1024)); }); +const countdown = new Countdown(NUM_CLIENTS, () => { + server.close(); +}); + server.listen(0, common.mustCall(() => { for (let i = 0; i < NUM_CLIENTS; i++) { cls.run(new Map(), common.mustCall(() => { @@ -51,13 +56,10 @@ function ondata(d) { } // Retrieve the store data, and test for homogeneity -let endCount = 0; function onend() { const store = cls.getStore(); assert.notStrictEqual(store, undefined); const data = store.get('data'); assert.strictEqual(data, data[0].repeat(data.length)); - if (++endCount === NUM_CLIENTS) { - server.close(); - } + countdown.dec(); }