test(compression): assert idle eviction terminates at the resource level (#13371)

Merged as the credit vehicle for #12542. Reverse-TDD verified on the tip: 8/8 with the fix, 7/8 with `terminate()` disabled.
This commit is contained in:
Diego Rodrigues de Sa e Souza
2026-09-11 17:46:22 -03:00
committed by GitHub
parent 16c68bad49
commit 3f62e43696
2 changed files with 36 additions and 0 deletions

View File

@@ -0,0 +1 @@
- **test(compression):** cover idle worker eviction at the resource level — the pool must call `terminate()` and must not retain the worker's `MessagePort`, complementing the `exit`-event assertion added with the fix

View File

@@ -1,5 +1,6 @@
import assert from "node:assert/strict";
import { after, describe, it } from "node:test";
import { Worker } from "node:worker_threads";
import {
isCompressionWorkerEligible,
isStrictlySerializable,
@@ -136,6 +137,40 @@ describe("compression worker execution", () => {
}
});
it("terminates an idle worker instead of only dropping it from the pool", async () => {
const spawned = new Set<Worker>();
const terminated: Promise<number>[] = [];
const originalPostMessage = Worker.prototype.postMessage;
const originalTerminate = Worker.prototype.terminate;
Worker.prototype.postMessage = function (this: Worker, ...args) {
spawned.add(this);
return originalPostMessage.apply(this, args);
};
Worker.prototype.terminate = function (this: Worker) {
const exit = originalTerminate.call(this);
terminated.push(exit);
return exit;
};
const messagePorts = () =>
process.getActiveResourcesInfo().filter((resource) => resource === "MessagePort").length;
const portsBefore = messagePorts();
const pool = new CompressionWorkerPool({ size: 1, idleMs: 50 });
try {
await pool.run(body, "stacked", { config });
await new Promise((resolve) => setTimeout(resolve, 300));
assert.equal(spawned.size, 1);
assert.equal(terminated.length, 1, "idle eviction must terminate the worker thread");
await Promise.all(terminated);
assert.ok(messagePorts() <= portsBefore, "idle eviction must not retain the worker's port");
} finally {
Worker.prototype.postMessage = originalPostMessage;
Worker.prototype.terminate = originalTerminate;
await pool.close();
// Reap anything the pool forgot so a regression fails instead of hanging the runner.
await Promise.all([...spawned].map((worker) => worker.terminate().catch(() => undefined)));
}
});
it("keeps the parent event loop responsive while two workers overlap", async () => {
const largeBody = {
messages: Array.from({ length: 400 }, (_, index) => ({