From 5ed197ca34c0bedd8df8fc78f9710ba5bf34f34c Mon Sep 17 00:00:00 2001 From: Don Isaac Date: Fri, 6 Dec 2024 17:51:50 -0800 Subject: [PATCH] more test cases --- test/js/node/readline/fixtures/empty.txt | 0 test/js/node/readline/fixtures/not-empty.txt | 1 + .../readline-empty-file-immediate-close.ts | 12 +++++ .../readline-nonempty-file-immediate-close.ts | 12 +++++ test/js/node/readline/readline.node.test.ts | 54 ++++++++++++------- 5 files changed, 59 insertions(+), 20 deletions(-) create mode 100644 test/js/node/readline/fixtures/empty.txt create mode 100644 test/js/node/readline/fixtures/not-empty.txt create mode 100644 test/js/node/readline/fixtures/readline-empty-file-immediate-close.ts create mode 100644 test/js/node/readline/fixtures/readline-nonempty-file-immediate-close.ts diff --git a/test/js/node/readline/fixtures/empty.txt b/test/js/node/readline/fixtures/empty.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/js/node/readline/fixtures/not-empty.txt b/test/js/node/readline/fixtures/not-empty.txt new file mode 100644 index 0000000000..257cc5642c --- /dev/null +++ b/test/js/node/readline/fixtures/not-empty.txt @@ -0,0 +1 @@ +foo diff --git a/test/js/node/readline/fixtures/readline-empty-file-immediate-close.ts b/test/js/node/readline/fixtures/readline-empty-file-immediate-close.ts new file mode 100644 index 0000000000..76beba311d --- /dev/null +++ b/test/js/node/readline/fixtures/readline-empty-file-immediate-close.ts @@ -0,0 +1,12 @@ +import readline from "readline"; +import fs from "fs"; +import path from "path"; + +const emptyFile = fs.createReadStream(path.resolve(__dirname, "empty.txt"), "utf8"); + +const rl1 = readline.createInterface({ + input: emptyFile, + output: process.stdout, +}); + +rl1.close(); diff --git a/test/js/node/readline/fixtures/readline-nonempty-file-immediate-close.ts b/test/js/node/readline/fixtures/readline-nonempty-file-immediate-close.ts new file mode 100644 index 0000000000..8fa5faa102 --- /dev/null +++ b/test/js/node/readline/fixtures/readline-nonempty-file-immediate-close.ts @@ -0,0 +1,12 @@ +import readline from "readline"; +import fs from "fs"; +import path from "path"; + +const nonEmptyFile = fs.createReadStream(path.resolve(__dirname, "not-empty.txt"), "utf8"); + +const rl1 = readline.createInterface({ + input: nonEmptyFile, + output: process.stdout, +}); + +rl1.close(); diff --git a/test/js/node/readline/readline.node.test.ts b/test/js/node/readline/readline.node.test.ts index faf7aa05bd..dc4a9d8640 100644 --- a/test/js/node/readline/readline.node.test.ts +++ b/test/js/node/readline/readline.node.test.ts @@ -1330,28 +1330,42 @@ describe("readline.Interface", () => { assert.strictEqual(getStringWidth("\u0301\u200D\u200E"), 0); }); - it("should not hang when stdint is closed", done => { - // const subprocess = Bun.spawn(["bun", "run", fixture("readline-stdin-immediate-close.ts")]); - var timeout: Timer | undefined; - const subprocess = Bun.spawn(["bun", "run", fixture("readline-stdin-immediate-close.ts")]); - // const subprocess = Bun.spawn(["bun", "run", "./fixtures/readline-stdin-immediate-close.ts"]); + const testForEventLoopHangs = (fixtureName: string) => async () => { + // race a timeout and the subprocess promise + const subprocess = Bun.spawn({ + cmd: ["bun", "run", fixture(fixtureName)], + }); - timeout = setTimeout(() => { - const error = new Error("readline did not close after 2.5s. This means stdint is keeping the event loop alive."); - subprocess.kill(); - done(error); - }, 2_500); + const timeoutAfter = 2_500; + var _timer: Timer | undefined; + const timeout = new Promise((_, reject) => { + _timer = setTimeout(() => { + _timer = undefined; + resolve(); // we're gonna race these + }, timeoutAfter); + }); - subprocess.exited - .then(() => { - clearTimeout(timeout); - done(); - }) - .catch(e => { - clearTimeout(timeout); - done(e); - }); - }); + await Promise.race([subprocess.exited, timeout]); + if (_timer) clearTimeout(_timer); + if (subprocess.exitCode == null) { + throw new Error("readline did not close after 2.5s. This means stdint is keeping the event loop alive."); + } else if (subprocess.exitCode !== 0) { + throw new Error(`subprocess exited with a non-zero code: ${subprocess.exitCode}`); + } + }; + + it( + "should not hang when stdin is immediately and synchronously closed", + testForEventLoopHangs("readline-stdin-immediate-close.ts"), + ); + it( + "should not hang when an empty file is immediately and synchronously closed", + testForEventLoopHangs("readline-empty-file-immediate-close.ts"), + ); + it( + "should not hang when a non-empty file is immediately and synchronously closed", + testForEventLoopHangs("readline-nonempty-file-immediate-close.ts"), + ); // // Check if vt control chars are stripped // assert.strictEqual(stripVTControlCharacters('\u001b[31m> \u001b[39m'), '> ');