Fix issue with exit callback in Bun.spawn() never firing

This commit is contained in:
Jarred Sumner
2022-10-10 20:57:38 -07:00
parent ef2c9c330c
commit 3cc61f8e30
5 changed files with 115 additions and 13 deletions

View File

@@ -4017,6 +4017,20 @@ pub const Strong = struct {
return result;
}
pub fn has(this: *Strong) bool {
var ref = this.ref orelse return false;
return ref.get() != .zero;
}
pub fn trySwap(this: *Strong) ?JSValue {
const result = this.swap();
if (result == .zero) {
return null;
}
return result;
}
pub fn set(this: *Strong, globalThis: *JSC.JSGlobalObject, value: JSValue) void {
var ref: *JSC.napi.Ref = this.ref orelse {
if (value == .zero) return;

View File

@@ -0,0 +1,8 @@
#!/usr/bin/env bash
echoerr() { echo "$@" 1>&2; }
echoerr "bun-streams-test-fifo.sh: starting"
echo -e "$FIFO_TEST" >>${@: -1}
echoerr "bun-streams-test-fifo.sh: ending"
exit 0

22
test/bun.js/mkfifo.ts Normal file
View File

@@ -0,0 +1,22 @@
import { dlopen, ptr } from "bun:ffi";
var lazyMkfifo;
export function mkfifo(path: string, permissions: number = 0o666): void {
if (!lazyMkfifo) {
const suffix = process.platform === "darwin" ? "dylib" : "so.6";
lazyMkfifo = dlopen(`libc.${suffix}`, {
mkfifo: {
args: ["ptr", "i32"],
returns: "i32",
},
}).symbols.mkfifo;
}
const buf = new Uint8Array(Buffer.byteLength(path) + 1);
new TextEncoder().encodeInto(path, buf);
const rc = lazyMkfifo(ptr(buf), permissions);
if (rc < 0) {
throw new Error(`mkfifo failed`);
}
}

View File

@@ -1,20 +1,18 @@
import { test, expect, it, describe } from "bun:test";
import { readableStreamToText, spawn } from "bun";
import { describe, expect, it } from "bun:test";
describe("spawn", () => {
const hugeString = "hello".repeat(100000).slice();
it("stdin can write", async () => {
const { stdin, stdout } = spawn({
cmd: ["cat"],
stdin: "pipe",
it("stdout can be read", async () => {
await Bun.write("/tmp/out.txt", hugeString);
const { stdout } = spawn({
cmd: ["cat", "/tmp/out.txt"],
stdout: "pipe",
});
await stdin.write(hugeString);
stdin.end();
return readableStreamToText(stdout).then((text) => {
expect(text).toBe(hugeString);
});
const text = await readableStreamToText(stdout);
expect(text).toBe(hugeString);
});
describe("pipe", () => {

View File

@@ -1,11 +1,72 @@
import { file, readableStreamToArrayBuffer, readableStreamToArray } from "bun";
import {
file,
readableStreamToArrayBuffer,
readableStreamToArray,
readableStreamToText,
} from "bun";
import { expect, it, beforeEach, afterEach } from "bun:test";
import { writeFileSync } from "node:fs";
import { mkfifo } from "mkfifo";
import { unlinkSync, writeFileSync } from "node:fs";
import { join } from "node:path";
import { gc } from "./gc";
new Uint8Array();
beforeEach(() => gc());
afterEach(() => gc());
it("Bun.file() read text from pipe", async () => {
try {
unlinkSync("/tmp/fifo");
} catch (e) {}
mkfifo("/tmp/fifo", 0o666);
const large = "HELLO!".repeat((((1024 * 512) / "HELLO!".length) | 0) + 1);
const chunks = [];
var out = Bun.file("/tmp/fifo").stream();
const proc = Bun.spawn({
cmd: [
"bash",
join(import.meta.dir + "/", "bun-streams-test-fifo.sh"),
"/tmp/fifo",
],
stderr: "inherit",
env: {
FIFO_TEST: large,
},
});
const exited = proc.exited;
proc.ref();
var prom = new Promise((resolve, reject) => {
setTimeout(() => {
(async function () {
var reader = out.getReader();
while (true) {
const chunk = await reader.read();
if (chunk.done) {
if (chunks.length == 0) {
out = Bun.file("/tmp/fifo").stream();
reader = out.getReader();
continue;
}
const output = new TextDecoder()
.decode(new Uint8Array(Buffer.concat(chunks)))
.trim();
resolve(output);
break;
}
chunks.push(chunk.value);
}
})();
});
});
const [status, output] = await Promise.all([exited, prom]);
expect(output.length).toBe(large.length);
expect(output).toBe(large);
expect(status).toBe(0);
});
it("exists globally", () => {
expect(typeof ReadableStream).toBe("function");
@@ -191,7 +252,6 @@ it("ReadableStream for Blob", async () => {
console.error(e);
console.error(e.stack);
}
if (chunk.done) break;
chunks.push(new TextDecoder().decode(chunk.value));
}