|
| 1 | +import { spawn } from "node:child_process"; |
| 2 | +import { mkdtempSync, writeFileSync } from "node:fs"; |
| 3 | +import { tmpdir } from "node:os"; |
| 4 | +import { join } from "node:path"; |
| 5 | +import puppeteer from "puppeteer-core"; |
| 6 | +import { it } from "vitest"; |
| 7 | + |
| 8 | +const exe = process.env.HYPERFRAMES_BROWSER_PATH!; |
| 9 | +const SCRIPT = `import puppeteer from "puppeteer-core"; |
| 10 | +const start = Date.now(); |
| 11 | +const pipe = process.argv[2] === "pipe"; |
| 12 | +try { |
| 13 | + const b = await puppeteer.launch({ executablePath: ${JSON.stringify(exe)}, headless: true, pipe, args: ["--no-sandbox"], timeout: 30000 }); |
| 14 | + await (await b.newPage()).evaluate(() => 1); |
| 15 | + console.log("OK " + (Date.now() - start)); await b.close(); |
| 16 | +} catch (e) { console.log("FAIL " + (Date.now() - start) + " " + e.message.split("\\n")[0]); } |
| 17 | +process.exit(0);`; |
| 18 | + |
| 19 | +async function inWorker(pipe: boolean) { |
| 20 | + const start = Date.now(); |
| 21 | + try { |
| 22 | + const b = await puppeteer.launch({ executablePath: exe, headless: true, pipe, args: ["--no-sandbox"], timeout: 30000 }); |
| 23 | + await (await b.newPage()).evaluate(() => 1); |
| 24 | + await b.close(); |
| 25 | + return `OK ${Date.now() - start}`; |
| 26 | + } catch (e) { |
| 27 | + return `FAIL ${Date.now() - start} ${(e as Error).message.split("\n")[0]}`; |
| 28 | + } |
| 29 | +} |
| 30 | + |
| 31 | +function child(mode: string, extra: { detached?: boolean; tsx?: boolean; stdio?: "pipe" | "ignore" }) { |
| 32 | + const dir = mkdtempSync(join(process.cwd(), ".winpipe-")); |
| 33 | + const file = join(dir, "launch.mjs"); |
| 34 | + writeFileSync(file, SCRIPT); |
| 35 | + return new Promise<string>((resolve) => { |
| 36 | + const c = spawn(process.execPath, [...(extra.tsx ? ["--import", "tsx"] : []), file, mode], { |
| 37 | + stdio: ["ignore", "pipe", extra.stdio === "ignore" ? "ignore" : "pipe"], detached: extra.detached ?? false, |
| 38 | + }); |
| 39 | + let out = ""; |
| 40 | + c.stdout.on("data", (d: Buffer) => (out += d)); |
| 41 | + c.stderr?.on("data", () => {}); |
| 42 | + c.on("close", () => resolve(out.trim())); |
| 43 | + }); |
| 44 | +} |
| 45 | + |
| 46 | +it("pipe launches by host", async () => { |
| 47 | + console.error(`WINPIPE exe=${exe}`); |
| 48 | + for (const pipe of [true, false]) console.error(`WINPIPE worker pipe=${pipe}: ${await inWorker(pipe)}`); |
| 49 | + for (const mode of ["pipe", "port"]) { |
| 50 | + console.error(`WINPIPE child ${mode}: ${await child(mode, {})}`); |
| 51 | + console.error(`WINPIPE child+tsx ${mode}: ${await child(mode, { tsx: true })}`); |
| 52 | + console.error(`WINPIPE child detached ${mode}: ${await child(mode, { detached: true })}`); |
| 53 | + console.error(`WINPIPE child stderr-ignored ${mode}: ${await child(mode, { stdio: "ignore" })}`); |
| 54 | + } |
| 55 | +}, 900_000); |
0 commit comments