Pipe decoded socket strings and give lane jobs their own tmpdirs

After socket.setEncoding(enc), socket.pipe(destination) wrote the raw
bytes it read to the destination. It now writes the decoded strings, as
Node's pipe writes each string chunk: the destination receives their
UTF-8 bytes, and a partial character the decoder holds at EOF is written
before the destination ends.

tests/node-parallel/run.mjs runs each job's files with its own
TEST_THREAD_ID, as Node's test runner does, so test/common/tmpdir gives
concurrent files different directories instead of one shared .tmp.0.
This commit is contained in:
Chris Tate
2026-10-29 23:16:13 -05:00
parent d80b34d92d
commit f67678b422
9 changed files with 220 additions and 60 deletions
@@ -54790,6 +54790,7 @@
"tests/corpus/2988-http-static-client-abort.ts",
"tests/corpus/net-paused-socket-exit.cjs",
"tests/corpus/net-server-socket-peer-close.cjs",
"tests/corpus/net-socket-encoding-pipe.cjs",
"tests/corpus/net-socket-method-values.cjs",
"tests/corpus/net-socket-set-encoding-names.ts",
"tests/corpus/net-socket-write-rejected.cjs",
@@ -56346,7 +56347,8 @@
"tests/corpus/net-socket-write-rejected.cjs",
"tests/corpus/net-socket-method-values.cjs",
"tests/corpus/net-paused-socket-exit.cjs",
"tests/corpus/net-server-socket-peer-close.cjs"
"tests/corpus/net-server-socket-peer-close.cjs",
"tests/corpus/net-socket-encoding-pipe.cjs"
]
},
"anchorSource": "exact"
@@ -56434,7 +56436,8 @@
"tests/corpus/net-socket-write-rejected.cjs",
"tests/corpus/net-socket-method-values.cjs",
"tests/corpus/net-paused-socket-exit.cjs",
"tests/corpus/net-server-socket-peer-close.cjs"
"tests/corpus/net-server-socket-peer-close.cjs",
"tests/corpus/net-socket-encoding-pipe.cjs"
]
},
"anchorSource": "exact"
@@ -59466,6 +59469,7 @@
"tests/corpus/2689-http-server-timeout-properties.ts",
"tests/corpus/net-paused-socket-exit.cjs",
"tests/corpus/net-server-socket-peer-close.cjs",
"tests/corpus/net-socket-encoding-pipe.cjs",
"tests/corpus/net-socket-method-values.cjs",
"tests/corpus/net-socket-set-encoding-names.ts",
"tests/corpus/net-socket-write-rejected.cjs"
@@ -61731,7 +61735,8 @@
"tests/corpus/net-socket-write-rejected.cjs",
"tests/corpus/net-socket-method-values.cjs",
"tests/corpus/net-paused-socket-exit.cjs",
"tests/corpus/net-server-socket-peer-close.cjs"
"tests/corpus/net-server-socket-peer-close.cjs",
"tests/corpus/net-socket-encoding-pipe.cjs"
]
},
"anchorSource": "exact"
@@ -62044,7 +62049,8 @@
"tests/corpus/net-socket-write-rejected.cjs",
"tests/corpus/net-socket-method-values.cjs",
"tests/corpus/net-paused-socket-exit.cjs",
"tests/corpus/net-server-socket-peer-close.cjs"
"tests/corpus/net-server-socket-peer-close.cjs",
"tests/corpus/net-socket-encoding-pipe.cjs"
]
},
"anchorSource": "exact"
@@ -63875,6 +63881,7 @@
"tests/corpus/2689-http-server-timeout-properties.ts",
"tests/corpus/net-paused-socket-exit.cjs",
"tests/corpus/net-server-socket-peer-close.cjs",
"tests/corpus/net-socket-encoding-pipe.cjs",
"tests/corpus/net-socket-method-values.cjs",
"tests/corpus/net-socket-set-encoding-names.ts",
"tests/corpus/net-socket-write-rejected.cjs"
@@ -63978,7 +63985,8 @@
"tests/corpus/net-socket-write-rejected.cjs",
"tests/corpus/net-socket-method-values.cjs",
"tests/corpus/net-paused-socket-exit.cjs",
"tests/corpus/net-server-socket-peer-close.cjs"
"tests/corpus/net-server-socket-peer-close.cjs",
"tests/corpus/net-socket-encoding-pipe.cjs"
]
},
"anchorSource": "exact"
@@ -64079,7 +64087,8 @@
"tests/corpus/net-socket-write-rejected.cjs",
"tests/corpus/net-socket-method-values.cjs",
"tests/corpus/net-paused-socket-exit.cjs",
"tests/corpus/net-server-socket-peer-close.cjs"
"tests/corpus/net-server-socket-peer-close.cjs",
"tests/corpus/net-socket-encoding-pipe.cjs"
]
},
"anchorSource": "exact"
@@ -72076,6 +72085,7 @@
"tests/corpus/5659-net-blocklist-socketaddress.ts",
"tests/corpus/net-paused-socket-exit.cjs",
"tests/corpus/net-server-socket-peer-close.cjs",
"tests/corpus/net-socket-encoding-pipe.cjs",
"tests/corpus/net-socket-method-values.cjs",
"tests/corpus/net-socket-set-encoding-names.ts",
"tests/corpus/net-socket-write-rejected.cjs",
@@ -72692,7 +72702,8 @@
"tests/corpus/net-socket-write-rejected.cjs",
"tests/corpus/net-socket-method-values.cjs",
"tests/corpus/net-paused-socket-exit.cjs",
"tests/corpus/net-server-socket-peer-close.cjs"
"tests/corpus/net-server-socket-peer-close.cjs",
"tests/corpus/net-socket-encoding-pipe.cjs"
]
},
"anchorSource": "exact"
@@ -72719,7 +72730,8 @@
"tests/corpus/net-socket-write-rejected.cjs",
"tests/corpus/net-socket-method-values.cjs",
"tests/corpus/net-paused-socket-exit.cjs",
"tests/corpus/net-server-socket-peer-close.cjs"
"tests/corpus/net-server-socket-peer-close.cjs",
"tests/corpus/net-socket-encoding-pipe.cjs"
]
},
"anchorSource": "exact"
@@ -72782,7 +72794,8 @@
"tests/corpus/net-socket-write-rejected.cjs",
"tests/corpus/net-socket-method-values.cjs",
"tests/corpus/net-paused-socket-exit.cjs",
"tests/corpus/net-server-socket-peer-close.cjs"
"tests/corpus/net-server-socket-peer-close.cjs",
"tests/corpus/net-socket-encoding-pipe.cjs"
]
},
"anchorSource": "exact"
@@ -72809,7 +72822,8 @@
"tests/corpus/net-socket-write-rejected.cjs",
"tests/corpus/net-socket-method-values.cjs",
"tests/corpus/net-paused-socket-exit.cjs",
"tests/corpus/net-server-socket-peer-close.cjs"
"tests/corpus/net-server-socket-peer-close.cjs",
"tests/corpus/net-socket-encoding-pipe.cjs"
]
},
"anchorSource": "exact"
@@ -72836,7 +72850,8 @@
"tests/corpus/net-socket-write-rejected.cjs",
"tests/corpus/net-socket-method-values.cjs",
"tests/corpus/net-paused-socket-exit.cjs",
"tests/corpus/net-server-socket-peer-close.cjs"
"tests/corpus/net-server-socket-peer-close.cjs",
"tests/corpus/net-socket-encoding-pipe.cjs"
]
},
"anchorSource": "exact"
@@ -72863,7 +72878,8 @@
"tests/corpus/net-socket-write-rejected.cjs",
"tests/corpus/net-socket-method-values.cjs",
"tests/corpus/net-paused-socket-exit.cjs",
"tests/corpus/net-server-socket-peer-close.cjs"
"tests/corpus/net-server-socket-peer-close.cjs",
"tests/corpus/net-socket-encoding-pipe.cjs"
]
},
"anchorSource": "exact"
@@ -72890,7 +72906,8 @@
"tests/corpus/net-socket-write-rejected.cjs",
"tests/corpus/net-socket-method-values.cjs",
"tests/corpus/net-paused-socket-exit.cjs",
"tests/corpus/net-server-socket-peer-close.cjs"
"tests/corpus/net-server-socket-peer-close.cjs",
"tests/corpus/net-socket-encoding-pipe.cjs"
]
},
"anchorSource": "exact"
@@ -73238,7 +73255,8 @@
"tests/corpus/net-socket-write-rejected.cjs",
"tests/corpus/net-socket-method-values.cjs",
"tests/corpus/net-paused-socket-exit.cjs",
"tests/corpus/net-server-socket-peer-close.cjs"
"tests/corpus/net-server-socket-peer-close.cjs",
"tests/corpus/net-socket-encoding-pipe.cjs"
]
},
"anchorSource": "exact"
@@ -73283,7 +73301,8 @@
"tests/corpus/net-socket-write-rejected.cjs",
"tests/corpus/net-socket-method-values.cjs",
"tests/corpus/net-paused-socket-exit.cjs",
"tests/corpus/net-server-socket-peer-close.cjs"
"tests/corpus/net-server-socket-peer-close.cjs",
"tests/corpus/net-socket-encoding-pipe.cjs"
]
},
"anchorSource": "exact"
@@ -73310,7 +73329,8 @@
"tests/corpus/net-socket-write-rejected.cjs",
"tests/corpus/net-socket-method-values.cjs",
"tests/corpus/net-paused-socket-exit.cjs",
"tests/corpus/net-server-socket-peer-close.cjs"
"tests/corpus/net-server-socket-peer-close.cjs",
"tests/corpus/net-socket-encoding-pipe.cjs"
]
},
"anchorSource": "exact"
@@ -73376,7 +73396,8 @@
"tests/corpus/net-socket-write-rejected.cjs",
"tests/corpus/net-socket-method-values.cjs",
"tests/corpus/net-paused-socket-exit.cjs",
"tests/corpus/net-server-socket-peer-close.cjs"
"tests/corpus/net-server-socket-peer-close.cjs",
"tests/corpus/net-socket-encoding-pipe.cjs"
]
},
"anchorSource": "exact"
@@ -73403,7 +73424,8 @@
"tests/corpus/net-socket-write-rejected.cjs",
"tests/corpus/net-socket-method-values.cjs",
"tests/corpus/net-paused-socket-exit.cjs",
"tests/corpus/net-server-socket-peer-close.cjs"
"tests/corpus/net-server-socket-peer-close.cjs",
"tests/corpus/net-socket-encoding-pipe.cjs"
]
},
"anchorSource": "exact"
@@ -73502,7 +73524,8 @@
"tests/corpus/net-socket-write-rejected.cjs",
"tests/corpus/net-socket-method-values.cjs",
"tests/corpus/net-paused-socket-exit.cjs",
"tests/corpus/net-server-socket-peer-close.cjs"
"tests/corpus/net-server-socket-peer-close.cjs",
"tests/corpus/net-socket-encoding-pipe.cjs"
]
},
"anchorSource": "exact"
@@ -73586,7 +73609,8 @@
"tests/corpus/net-socket-write-rejected.cjs",
"tests/corpus/net-socket-method-values.cjs",
"tests/corpus/net-paused-socket-exit.cjs",
"tests/corpus/net-server-socket-peer-close.cjs"
"tests/corpus/net-server-socket-peer-close.cjs",
"tests/corpus/net-socket-encoding-pipe.cjs"
]
},
"anchorSource": "exact"
@@ -74235,7 +74259,8 @@
"tests/corpus/net-socket-write-rejected.cjs",
"tests/corpus/net-socket-method-values.cjs",
"tests/corpus/net-paused-socket-exit.cjs",
"tests/corpus/net-server-socket-peer-close.cjs"
"tests/corpus/net-server-socket-peer-close.cjs",
"tests/corpus/net-socket-encoding-pipe.cjs"
]
},
"anchorSource": "exact"
@@ -74262,7 +74287,8 @@
"tests/corpus/net-socket-write-rejected.cjs",
"tests/corpus/net-socket-method-values.cjs",
"tests/corpus/net-paused-socket-exit.cjs",
"tests/corpus/net-server-socket-peer-close.cjs"
"tests/corpus/net-server-socket-peer-close.cjs",
"tests/corpus/net-socket-encoding-pipe.cjs"
]
},
"anchorSource": "exact"
@@ -74289,7 +74315,8 @@
"tests/corpus/net-socket-write-rejected.cjs",
"tests/corpus/net-socket-method-values.cjs",
"tests/corpus/net-paused-socket-exit.cjs",
"tests/corpus/net-server-socket-peer-close.cjs"
"tests/corpus/net-server-socket-peer-close.cjs",
"tests/corpus/net-socket-encoding-pipe.cjs"
]
},
"anchorSource": "exact"
@@ -74316,7 +74343,8 @@
"tests/corpus/net-socket-write-rejected.cjs",
"tests/corpus/net-socket-method-values.cjs",
"tests/corpus/net-paused-socket-exit.cjs",
"tests/corpus/net-server-socket-peer-close.cjs"
"tests/corpus/net-server-socket-peer-close.cjs",
"tests/corpus/net-socket-encoding-pipe.cjs"
]
},
"anchorSource": "exact"
@@ -74343,7 +74371,8 @@
"tests/corpus/net-socket-write-rejected.cjs",
"tests/corpus/net-socket-method-values.cjs",
"tests/corpus/net-paused-socket-exit.cjs",
"tests/corpus/net-server-socket-peer-close.cjs"
"tests/corpus/net-server-socket-peer-close.cjs",
"tests/corpus/net-socket-encoding-pipe.cjs"
]
},
"anchorSource": "exact"
@@ -74370,7 +74399,8 @@
"tests/corpus/net-socket-write-rejected.cjs",
"tests/corpus/net-socket-method-values.cjs",
"tests/corpus/net-paused-socket-exit.cjs",
"tests/corpus/net-server-socket-peer-close.cjs"
"tests/corpus/net-server-socket-peer-close.cjs",
"tests/corpus/net-socket-encoding-pipe.cjs"
]
},
"anchorSource": "exact"
@@ -74397,7 +74427,8 @@
"tests/corpus/net-socket-write-rejected.cjs",
"tests/corpus/net-socket-method-values.cjs",
"tests/corpus/net-paused-socket-exit.cjs",
"tests/corpus/net-server-socket-peer-close.cjs"
"tests/corpus/net-server-socket-peer-close.cjs",
"tests/corpus/net-socket-encoding-pipe.cjs"
]
},
"anchorSource": "exact"
@@ -74424,7 +74455,8 @@
"tests/corpus/net-socket-write-rejected.cjs",
"tests/corpus/net-socket-method-values.cjs",
"tests/corpus/net-paused-socket-exit.cjs",
"tests/corpus/net-server-socket-peer-close.cjs"
"tests/corpus/net-server-socket-peer-close.cjs",
"tests/corpus/net-socket-encoding-pipe.cjs"
]
},
"anchorSource": "exact"
@@ -74451,7 +74483,8 @@
"tests/corpus/net-socket-write-rejected.cjs",
"tests/corpus/net-socket-method-values.cjs",
"tests/corpus/net-paused-socket-exit.cjs",
"tests/corpus/net-server-socket-peer-close.cjs"
"tests/corpus/net-server-socket-peer-close.cjs",
"tests/corpus/net-socket-encoding-pipe.cjs"
]
},
"anchorSource": "exact"
@@ -74514,7 +74547,8 @@
"tests/corpus/net-socket-write-rejected.cjs",
"tests/corpus/net-socket-method-values.cjs",
"tests/corpus/net-paused-socket-exit.cjs",
"tests/corpus/net-server-socket-peer-close.cjs"
"tests/corpus/net-server-socket-peer-close.cjs",
"tests/corpus/net-socket-encoding-pipe.cjs"
]
},
"anchorSource": "exact"
@@ -74541,7 +74575,8 @@
"tests/corpus/net-socket-write-rejected.cjs",
"tests/corpus/net-socket-method-values.cjs",
"tests/corpus/net-paused-socket-exit.cjs",
"tests/corpus/net-server-socket-peer-close.cjs"
"tests/corpus/net-server-socket-peer-close.cjs",
"tests/corpus/net-socket-encoding-pipe.cjs"
]
},
"anchorSource": "exact"
@@ -76000,6 +76035,7 @@
"tests/corpus/6397-event-loop-metrics.ts",
"tests/corpus/net-paused-socket-exit.cjs",
"tests/corpus/net-server-socket-peer-close.cjs",
"tests/corpus/net-socket-encoding-pipe.cjs",
"tests/corpus/net-socket-method-values.cjs",
"tests/corpus/net-socket-set-encoding-names.ts",
"tests/corpus/net-socket-write-rejected.cjs",
@@ -76311,7 +76347,8 @@
"tests/corpus/net-socket-write-rejected.cjs",
"tests/corpus/net-socket-method-values.cjs",
"tests/corpus/net-paused-socket-exit.cjs",
"tests/corpus/net-server-socket-peer-close.cjs"
"tests/corpus/net-server-socket-peer-close.cjs",
"tests/corpus/net-socket-encoding-pipe.cjs"
]
},
"anchorSource": "exact"
@@ -96254,6 +96291,7 @@
"tests/corpus/7442-tls-server-contexts.mjs",
"tests/corpus/net-paused-socket-exit.cjs",
"tests/corpus/net-server-socket-peer-close.cjs",
"tests/corpus/net-socket-encoding-pipe.cjs",
"tests/corpus/net-socket-method-values.cjs",
"tests/corpus/net-socket-set-encoding-names.ts",
"tests/corpus/net-socket-write-rejected.cjs",
@@ -96666,7 +96704,8 @@
"tests/corpus/net-socket-write-rejected.cjs",
"tests/corpus/net-socket-method-values.cjs",
"tests/corpus/net-paused-socket-exit.cjs",
"tests/corpus/net-server-socket-peer-close.cjs"
"tests/corpus/net-server-socket-peer-close.cjs",
"tests/corpus/net-socket-encoding-pipe.cjs"
]
},
"anchorSource": "exact"
@@ -96698,7 +96737,8 @@
"tests/corpus/net-socket-write-rejected.cjs",
"tests/corpus/net-socket-method-values.cjs",
"tests/corpus/net-paused-socket-exit.cjs",
"tests/corpus/net-server-socket-peer-close.cjs"
"tests/corpus/net-server-socket-peer-close.cjs",
"tests/corpus/net-socket-encoding-pipe.cjs"
]
},
"anchorSource": "exact"
@@ -96753,7 +96793,8 @@
"tests/corpus/net-socket-write-rejected.cjs",
"tests/corpus/net-socket-method-values.cjs",
"tests/corpus/net-paused-socket-exit.cjs",
"tests/corpus/net-server-socket-peer-close.cjs"
"tests/corpus/net-server-socket-peer-close.cjs",
"tests/corpus/net-socket-encoding-pipe.cjs"
]
},
"anchorSource": "exact"
+1 -1
View File
@@ -479,7 +479,7 @@
{ "symbols": ["setImmediate", "setInterval", "setTimeout", "clearImmediate", "clearInterval", "clearTimeout", "timersPromises.setTimeout", "timersPromises.setImmediate", "timersPromises.setInterval", "immediate.hasRef", "immediate.ref", "immediate.unref", "timeout.hasRef", "timeout.ref", "timeout.unref", "timeout.refresh"], "status": "partial", "evidence": ["tests/corpus/1804-timers-module.ts", "tests/corpus/1805-timer-callback-args.ts", "tests/corpus/2093-timers-promises.ts", "tests/corpus/2852-timers-promises-interval.ts", "tests/corpus/5830-timers-promises-signal.ts"] },
{ "symbols": ["timersPromises.scheduler.wait", "timersPromises.scheduler.yield"], "status": "partial", "evidence": ["tests/corpus/5839-timers-promises-scheduler.ts", "tests/corpus/5889-timers-scheduler-signal.ts"] },
{ "symbols": ["stream.finished", "stream.pipeline", "stream.getDefaultHighWaterMark", "readable.push", "readable.unshift", "readable.read", "readable.pause", "readable.resume", "readable.isPaused", "readable.setEncoding", "readable.pipe", "readable.unpipe", "readable.destroy", "writable.write", "writable.end", "writable.cork", "writable.uncork", "writable.setDefaultEncoding"], "status": "partial", "evidence": ["tests/corpus/1685-stream-readable-basics.ts", "tests/corpus/1688-stream-writable-basics.ts", "tests/corpus/1814-stream-pipeline.cjs", "tests/corpus/5302-stream-promises-options.ts", "tests/corpus/5303-stream-finished-callback-opts.cjs", "tests/corpus/5425-pipeline-generator-stage.ts", "tests/corpus/5428-pipeline-generator-stages.cjs", "tests/corpus/5617-pipeline-function-ends.ts", "tests/corpus/5619-pipeline-function-ends.cjs", "tests/corpus/writable-error-callbacks.ts"] },
{ "symbols": ["net.createServer", "net.connect", "net.createConnection", "net.getDefaultAutoSelectFamilyAttemptTimeout", "net.setDefaultAutoSelectFamilyAttemptTimeout", "server.address", "server.close", "server.listen", "socket.destroy", "socket.end", "socket.pause", "socket.resume", "socket.setEncoding", "socket.setTimeout", "socket.write"], "status": "partial", "evidence": ["tests/corpus/2500-net-autosel-timeout.ts", "tests/corpus/2596-net-arg-ladders.cjs", "tests/corpus/net-socket-set-encoding-names.ts", "tests/corpus/net-socket-write-rejected.cjs", "tests/corpus/net-socket-method-values.cjs", "tests/corpus/net-paused-socket-exit.cjs", "tests/corpus/net-server-socket-peer-close.cjs"] },
{ "symbols": ["net.createServer", "net.connect", "net.createConnection", "net.getDefaultAutoSelectFamilyAttemptTimeout", "net.setDefaultAutoSelectFamilyAttemptTimeout", "server.address", "server.close", "server.listen", "socket.destroy", "socket.end", "socket.pause", "socket.resume", "socket.setEncoding", "socket.setTimeout", "socket.write"], "status": "partial", "evidence": ["tests/corpus/2500-net-autosel-timeout.ts", "tests/corpus/2596-net-arg-ladders.cjs", "tests/corpus/net-socket-set-encoding-names.ts", "tests/corpus/net-socket-write-rejected.cjs", "tests/corpus/net-socket-method-values.cjs", "tests/corpus/net-paused-socket-exit.cjs", "tests/corpus/net-server-socket-peer-close.cjs", "tests/corpus/net-socket-encoding-pipe.cjs"] },
{ "symbols": ["dgram.createSocket", "socket.address", "socket.bind", "socket.close", "socket.connect", "socket.ref", "socket.remoteAddress", "socket.send", "socket.unref"], "status": "partial", "evidence": ["tests/corpus/2597-dgram-send-ladders.cjs"] },
{ "symbols": ["net.SocketAddress", "net.BlockList"], "status": "partial", "evidence": ["tests/corpus/5659-net-blocklist-socketaddress.ts", "tests/fixtures/node-types/net-blocklist.ts"] },
{ "symbols": ["SocketAddress.parse", "BlockList.isBlockList", "blockList.addAddress", "blockList.addAddresses", "blockList.addCIDR", "blockList.addCIDRs", "blockList.addRange", "blockList.addSubnet", "blockList.check", "blockList.clear", "blockList.fromJSON", "blockList.removeAddress", "blockList.removeCIDR", "blockList.removeRange", "blockList.removeSubnet", "blockList.toJSON"], "status": "supported", "evidence": ["tests/corpus/5659-net-blocklist-socketaddress.ts", "tests/fixtures/node-types/net-blocklist.ts"] },
@@ -0,0 +1,6 @@
{
"order": [
"<repo>/tests/corpus/net-socket-encoding-pipe.cjs"
],
"diags": []
}
+36 -18
View File
@@ -1562,6 +1562,19 @@ static void scr_net_sock_fire_data(ScrNetSocket *s, ScrBytes *chunk, ScrStr *tex
scr_bytes_release(empty);
}
/* One decoded 'data' string after setEncoding: the pipe destination
* writes it, as Node's pipe writes the string chunk (UTF-8), and the
* 'data' listeners receive it. */
static void scr_net_sock_emit_text(ScrNetSocket *s, ScrStr *text) {
if (s->pipe_dst) {
char *owned;
const char *bytes = scr_str_utf8(text, &owned);
scr_net_sock_write_raw(s->pipe_dst, bytes, text->len);
scr_str_utf8_end(owned);
}
if (s->data_ls.n > 0) scr_net_sock_fire_data(s, NULL, text);
}
/* EOF: 'end' fires now (directly — Node's poll-phase emit), then the
* write half ends (allowHalfOpen false), and the fd closes once the FIN
* is out. 'close' waits for the sweep. */
@@ -1573,6 +1586,15 @@ static void scr_net_sock_eof(ScrNetSocket *s) {
s->native_eof(s->native_ctx);
if (scr_exc_pending()) return;
}
if (s->encoding != NULL && (s->data_ls.n > 0 || s->pipe_dst != NULL)) {
/* the decoder's end(): a held partial sequence is the last 'data',
* and the pipe destination receives it before its end() */
ScrStr *tail = scr_strdec_end(s->encoding, s->dec_pending);
s->dec_pending = 0;
if (tail->len > 0) scr_net_sock_emit_text(s, tail);
scr_str_release(tail);
if (scr_exc_pending()) return;
}
if (s->pipe_dst) {
/* pipe's end-the-destination default */
ScrNetSocket *dst = s->pipe_dst;
@@ -1581,14 +1603,6 @@ static void scr_net_sock_eof(ScrNetSocket *s) {
scr_net_sock_maybe_finish_write(dst);
}
}
if (s->encoding != NULL && s->data_ls.n > 0) {
/* the decoder's end(): a held partial sequence is the last 'data' */
ScrStr *tail = scr_strdec_end(s->encoding, s->dec_pending);
s->dec_pending = 0;
if (tail->len > 0) scr_net_sock_fire_data(s, NULL, tail);
scr_str_release(tail);
if (scr_exc_pending()) return;
}
scr_net_fire0_this(&s->end_ls, s, SCR_DYNH_NET_SOCKET);
if (scr_exc_pending()) return;
if (!s->wr_ending) {
@@ -1611,21 +1625,25 @@ static bool scr_net_sock_deliver(ScrNetSocket *s, const char *buf, size_t n) {
* next chunk takes the listener path */
return true;
}
if (s->encoding != NULL && (s->pipe_dst != NULL || s->data_ls.n > 0)) {
/* the decoder answers the complete characters; a partial sequence
* waits for the next chunk, and an empty answer emits nothing */
ScrBytes *chunk = scr_bytes_new(SCR_BYTES_U8, (double)n);
chunk->is_buffer = true;
memcpy(chunk->data, buf, n);
ScrStr *text = scr_strdec_write(s->encoding, s->dec_pending, chunk);
s->dec_pending = scr_strdec_next(s->encoding, s->dec_pending, chunk);
scr_bytes_release(chunk);
if (text->len > 0) scr_net_sock_emit_text(s, text);
scr_str_release(text);
return !scr_exc_pending();
}
if (s->pipe_dst) scr_net_sock_write_raw(s->pipe_dst, buf, n);
if (s->data_ls.n > 0) {
ScrBytes *chunk = scr_bytes_new(SCR_BYTES_U8, (double)n);
chunk->is_buffer = true; /* Node delivers a Buffer */
memcpy(chunk->data, buf, n);
if (s->encoding != NULL) {
/* the decoder answers the complete characters; a partial sequence
* waits for the next chunk, and an empty answer emits nothing */
ScrStr *text = scr_strdec_write(s->encoding, s->dec_pending, chunk);
s->dec_pending = scr_strdec_next(s->encoding, s->dec_pending, chunk);
if (text->len > 0) scr_net_sock_fire_data(s, NULL, text);
scr_str_release(text);
} else {
scr_net_sock_fire_data(s, chunk, NULL);
}
scr_net_sock_fire_data(s, chunk, NULL);
scr_bytes_release(chunk);
if (scr_exc_pending()) return false;
}
+44
View File
@@ -0,0 +1,44 @@
// socket.pipe(destination) after socket.setEncoding(enc) writes the
// decoded strings to the destination, as Node's pipe writes each string
// chunk: the destination receives their UTF-8 bytes, a split character
// arrives whole, and a partial character held at EOF is written before the
// destination ends.
"use strict";
const net = require("net");
const source = net.createServer((socket) => {
socket.on("error", () => {});
socket.write(Buffer.from([0x61, 0xc3]));
setTimeout(() => socket.end(Buffer.from([0xa9, 0x62, 0xe2, 0x82])), 50);
});
const received = new Map();
const collector = net.createServer((socket) => {
const chunks = [];
let label = null;
socket.on("data", (chunk) => chunks.push(chunk));
socket.on("end", () => {
const all = Buffer.concat(chunks);
const newline = all.indexOf(0x0a);
label = all.subarray(0, newline).toString();
received.set(label, all.subarray(newline + 1).toString("hex"));
if (received.size === encodings.length) {
for (const name of encodings) console.log(name, received.get(name));
source.close();
collector.close();
}
});
});
const encodings = ["utf8", "hex", "base64", "latin1", "ucs2"];
source.listen(0, "127.0.0.1", () => {
collector.listen(0, "127.0.0.1", () => {
for (const encoding of encodings) {
const destination = net.connect(collector.address().port, "127.0.0.1");
destination.write(encoding + "\n");
const client = net.connect(source.address().port, "127.0.0.1");
client.setEncoding(encoding);
client.pipe(destination);
}
});
});
@@ -0,0 +1 @@
{ "plain": 2100, "san": 3200 }
@@ -59,3 +59,50 @@ test("a relative --node path links the checkout's fixtures and common helpers in
);
expect(existsSync(join(out, "tree", "test", "common", "tmpdir.js"))).toBe(true);
});
test("concurrent files get their own test/common tmpdir", () => {
const checkout = join(scratch, "node-tmpdir");
mkdirSync(join(checkout, "test", "parallel"), { recursive: true });
mkdirSync(join(checkout, "test", "fixtures"), { recursive: true });
mkdirSync(join(checkout, "test", "common"), { recursive: true });
for (const helper of ["fixtures.js", "dns.js", "internet.js"])
writeFileSync(join(checkout, "test", "common", helper), "module.exports = {};\n");
// Each file refreshes the tmpdir, writes a marker and reads it back after
// the other file has refreshed its own: with a shared directory the
// marker is gone and the file exits with 1.
const body = `const fs = require("fs");
const tmpdir = require("../common/tmpdir");
tmpdir.refresh();
fs.writeFileSync(tmpdir.resolve("marker"), __filename);
setTimeout(() => {
process.exit(fs.existsSync(tmpdir.resolve("marker")) ? 0 : 1);
}, 500);
`;
for (const name of ["test-tmp-a.js", "test-tmp-b.js"])
writeFileSync(join(checkout, "test", "parallel", name), body);
const failingCli = join(scratch, "failing-cli.mjs");
writeFileSync(failingCli, "process.exit(1);\n");
const out = join(scratch, "out-tmpdir");
const result = spawnSync(
process.execPath,
[
join(repo, "tests/node-parallel/run.mjs"),
"--node",
checkout,
"--pattern",
"^test-tmp-",
"--out",
out,
"--cli",
failingCli,
"--jobs",
"2",
],
{ cwd: scratch, encoding: "utf8" },
);
expect(result.status, result.stderr).toBe(0);
const results = JSON.parse(readFileSync(join(out, "results.json"), "utf8")) as {
nodeExit: number;
}[];
expect(results.map((r) => r.nodeExit)).toEqual([0, 0]);
});
+1 -1
View File
@@ -18,6 +18,6 @@ Options:
- `--cli`: the scriptc CLI entry (default `packages/cli/dist/main.js`).
- `--jobs`: concurrent files (default 4).
Node runs each file with its `// Flags:` line. Results are written to `<out>/results.json` and `<out>/results.md`.
Node runs each file with its `// Flags:` line. Each job runs its files with its own `TEST_THREAD_ID`, as Node's test runner does, so `test/common/tmpdir` gives concurrent files different directories. Results are written to `<out>/results.json` and `<out>/results.md`.
Before a lane relies on the minimal common, run its files under Node in `<out>/tree/test/parallel`: they should all pass there.
+8 -5
View File
@@ -89,11 +89,14 @@ const firstCause = (text) =>
.trim()
.slice(0, 300);
async function one(file) {
// Each job runs its files with its own TEST_THREAD_ID, as Node's test runner
// does, so test/common/tmpdir gives concurrent files different directories.
async function one(file, job) {
const env = { ...process.env, TEST_THREAD_ID: String(job) };
const dir = join(testRoot, "parallel");
const source = readFileSync(join(dir, file), "utf8");
const flags = (/^\/\/ Flags: (.*)$/m.exec(source)?.[1] ?? "").split(/\s+/).filter(Boolean);
const node = await run(process.execPath, [...flags, file], { cwd: dir, timeout: 120_000 });
const node = await run(process.execPath, [...flags, file], { cwd: dir, env, timeout: 120_000 });
const exe = join(out, "bin", `${file}.exe`);
mkdirSync(join(out, "bin"), { recursive: true });
const build = await run(process.execPath, [values.cli, "build", file, "-o", exe], {
@@ -106,7 +109,7 @@ async function one(file) {
result.cause = firstCause(build.stdout + build.stderr);
return result;
}
const native = await run(exe, [], { cwd: dir, timeout: 120_000 });
const native = await run(exe, [], { cwd: dir, env, timeout: 120_000 });
result.exit = termination(native);
result.verdict = sameTermination(node, native) ? "pass" : "fail";
if (result.verdict !== "pass") result.cause = firstCause(native.stderr + native.stdout);
@@ -116,9 +119,9 @@ async function one(file) {
const results = [];
const queue = [...files];
await Promise.all(
Array.from({ length: Number(values.jobs) }, async () => {
Array.from({ length: Number(values.jobs) }, async (_, job) => {
for (let file = queue.shift(); file !== undefined; file = queue.shift()) {
const result = await one(file);
const result = await one(file, job);
results.push(result);
console.log(`${result.verdict.padEnd(8)} ${file}${result.cause ? ` ${result.cause}` : ""}`);
}