From bfdad4446096490df85e5c2d64c846fba9eb41be Mon Sep 17 00:00:00 2001 From: Cameron Haley <42698419+camero2734@users.noreply.github.com> Date: Thu, 29 Feb 2024 04:03:08 +0100 Subject: [PATCH] Fix issue where process.stdin is ended too early (#9155) * Fix issue wherein process.stdin is ended too early * [autofix.ci] apply automated fixes * test: Generate prisma client on 'big' schema * Update test/js/third_party/prisma/helper.ts --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Jarred Sumner --- src/js/builtins/ProcessObjectInternals.ts | 13 ++++--- test/js/node/stream/node-stream.test.js | 37 +++++++++++++++++++ test/js/third_party/prisma/prisma.test.ts | 8 +++- .../prisma/prisma/postgres/schema.prisma | 30 ++++++++++++++- 4 files changed, 80 insertions(+), 8 deletions(-) diff --git a/src/js/builtins/ProcessObjectInternals.ts b/src/js/builtins/ProcessObjectInternals.ts index 572a075693..38c68893c2 100644 --- a/src/js/builtins/ProcessObjectInternals.ts +++ b/src/js/builtins/ProcessObjectInternals.ts @@ -132,6 +132,7 @@ export function getStdinStream(fd) { const originalOn = stream.on; let stream_destroyed = false; + let stream_endEmitted = false; stream.on = function (event, listener) { // Streams don't generally required to present any data when only // `readable` events are present, i.e. `readableFlowing === false` @@ -190,7 +191,10 @@ export function getStdinStream(fd) { if (shouldUnref) unref(); } else { - stream.emit("end"); + if (!stream_endEmitted) { + stream_endEmitted = true; + stream.emit("end"); + } if (!stream_destroyed) { stream_destroyed = true; stream.destroy(); @@ -204,10 +208,9 @@ export function getStdinStream(fd) { stream._read = function (size) { $debug("_read();", reader); - if (!reader) { - // TODO: this is wrong - this.push(null); - } else if (!shouldUnref) { + if (!reader) return; + + if (!shouldUnref) { internalRead(this); } }; diff --git a/test/js/node/stream/node-stream.test.js b/test/js/node/stream/node-stream.test.js index e2c3e51d38..00a42d1edc 100644 --- a/test/js/node/stream/node-stream.test.js +++ b/test/js/node/stream/node-stream.test.js @@ -5,6 +5,7 @@ import { join } from "path"; import { bunExe, bunEnv } from "harness"; import { tmpdir } from "node:os"; import { writeFileSync, mkdirSync } from "node:fs"; +import { spawn } from "node:child_process"; const isWindows = process.platform === "win32"; @@ -245,6 +246,42 @@ describe("PassThrough", () => { }); }); +const processStdInTest = ` +const { Transform } = require("node:stream"); + +let totalChunkSize = 0; +const transform = new Transform({ + transform(chunk, _encoding, callback) { + totalChunkSize += chunk.length; + callback(null, ""); + }, +}); + +process.stdin.pipe(transform).pipe(process.stdout); +process.stdin.on("end", () => console.log(totalChunkSize)); +`; +describe("process.stdin", () => { + it("should pipe correctly", done => { + mkdirSync(join(tmpdir(), "process-stdin-test"), { recursive: true }); + writeFileSync(join(tmpdir(), "process-stdin-test/process-stdin.test.js"), processStdInTest, {}); + + // A sufficiently large input to make at least four chunks + const ARRAY_SIZE = 8_388_628; + const typedArray = new Uint8Array(ARRAY_SIZE).fill(97); + + const { stdout, exitCode, stderr } = Bun.spawnSync({ + cmd: [bunExe(), "test", "process-stdin.test.js"], + cwd: join(tmpdir(), "process-stdin-test"), + env: bunEnv, + stdin: typedArray, + }); + + expect(exitCode).toBe(0); + expect(String(stdout)).toBe(`${ARRAY_SIZE}\n`); + done(); + }); +}); + const ttyStreamsTest = ` import tty from "tty"; import fs from "fs"; diff --git a/test/js/third_party/prisma/prisma.test.ts b/test/js/third_party/prisma/prisma.test.ts index af84875163..f902387a47 100644 --- a/test/js/third_party/prisma/prisma.test.ts +++ b/test/js/third_party/prisma/prisma.test.ts @@ -1,7 +1,7 @@ // @known-failing-on-windows: 1 failing -import { test as bunTest, expect, describe } from "bun:test"; -import { generateClient } from "./helper.ts"; +import { test as bunTest, it as bunIt, expect, describe } from "bun:test"; +import { generate, generateClient } from "./helper.ts"; import type { PrismaClient } from "./prisma/types.d.ts"; import { createCanvas } from "@napi-rs/canvas"; @@ -205,5 +205,9 @@ async function cleanTestId(prisma: PrismaClient, testId: number) { }, 20000, ); + + bunIt("generates client successfully", async () => { + generate(type); + }); }); }); diff --git a/test/js/third_party/prisma/prisma/postgres/schema.prisma b/test/js/third_party/prisma/prisma/postgres/schema.prisma index afbd6f39a6..483e026e8e 100644 --- a/test/js/third_party/prisma/prisma/postgres/schema.prisma +++ b/test/js/third_party/prisma/prisma/postgres/schema.prisma @@ -28,4 +28,32 @@ model Post { published Boolean @default(false) author User @relation(fields: [authorId], references: [id]) authorId Int -} \ No newline at end of file + + // Big schema to replicate + // https://github.com/oven-sh/bun/issues/5320 + option1 Int? + option2 Int? + option3 Int? + option4 Int? + option5 Int? + option6 Int? + option7 Int? + option8 Int? + option9 Int? + option10 Int? + option11 Int? + option12 Int? + option13 Int? + option14 Int? + option15 Int? + option16 Int? + option17 Int? + option18 Int? + option19 Int? + option20 Int? + option21 Int? + option22 Int? + option23 Int? + option24 Int? + option25 Int? +}