fix(process-cleanup): add test seam to prevent process.exitCode contaminating bun runner
fix(process-cleanup): isolate test to prevent process.exitCode leaking into shared batch CI
This commit is contained in:
@@ -30,17 +30,17 @@
|
||||
"zod": "^4.3.0",
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"oh-my-opencode-darwin-arm64": "3.17.12",
|
||||
"oh-my-opencode-darwin-x64": "3.17.12",
|
||||
"oh-my-opencode-darwin-x64-baseline": "3.17.12",
|
||||
"oh-my-opencode-linux-arm64": "3.17.12",
|
||||
"oh-my-opencode-linux-arm64-musl": "3.17.12",
|
||||
"oh-my-opencode-linux-x64": "3.17.12",
|
||||
"oh-my-opencode-linux-x64-baseline": "3.17.12",
|
||||
"oh-my-opencode-linux-x64-musl": "3.17.12",
|
||||
"oh-my-opencode-linux-x64-musl-baseline": "3.17.12",
|
||||
"oh-my-opencode-windows-x64": "3.17.12",
|
||||
"oh-my-opencode-windows-x64-baseline": "3.17.12",
|
||||
"oh-my-opencode-darwin-arm64": "3.17.13",
|
||||
"oh-my-opencode-darwin-x64": "3.17.13",
|
||||
"oh-my-opencode-darwin-x64-baseline": "3.17.13",
|
||||
"oh-my-opencode-linux-arm64": "3.17.13",
|
||||
"oh-my-opencode-linux-arm64-musl": "3.17.13",
|
||||
"oh-my-opencode-linux-x64": "3.17.13",
|
||||
"oh-my-opencode-linux-x64-baseline": "3.17.13",
|
||||
"oh-my-opencode-linux-x64-musl": "3.17.13",
|
||||
"oh-my-opencode-linux-x64-musl-baseline": "3.17.13",
|
||||
"oh-my-opencode-windows-x64": "3.17.13",
|
||||
"oh-my-opencode-windows-x64-baseline": "3.17.13",
|
||||
},
|
||||
"peerDependencies": {
|
||||
"zod": "^4.0.0",
|
||||
@@ -241,27 +241,27 @@
|
||||
|
||||
"object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="],
|
||||
|
||||
"oh-my-opencode-darwin-arm64": ["oh-my-opencode-darwin-arm64@3.17.12", "", { "os": "darwin", "cpu": "arm64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-VNLtKIG1PPng1TXtexsvBSAdF9CnUEl2NW+0WCh+lsYMSiVocqjDx1OsWQc2dkWMXzFgAKZReHNH99X8wamCzg=="],
|
||||
"oh-my-opencode-darwin-arm64": ["oh-my-opencode-darwin-arm64@3.17.13", "", { "os": "darwin", "cpu": "arm64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-5n+eEhh7tfE62BT8cC2XjTXubcXQOEGNTCWSOZ7C1mrE9E5xbvPb/ctWLrGTIk9rkl5+MJW3IZ7HLniAphxCEA=="],
|
||||
|
||||
"oh-my-opencode-darwin-x64": ["oh-my-opencode-darwin-x64@3.17.12", "", { "os": "darwin", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-xEYo9zD6i5xl8i/O4Vm4mCohcbEvrAm0+CTwnONgc1kqjsN+OmxQNawjZIeEudyUsRFX/Nup7RZvIzzHSTxbBA=="],
|
||||
"oh-my-opencode-darwin-x64": ["oh-my-opencode-darwin-x64@3.17.13", "", { "os": "darwin", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-PMy2e+gH7C3w1BHbtvHWKajxCbP2srV9N+Rv5nJ4Xh1SuSUO+8U+DlASsbCo6ArskP3IyJVRyykm34nLdkcu6w=="],
|
||||
|
||||
"oh-my-opencode-darwin-x64-baseline": ["oh-my-opencode-darwin-x64-baseline@3.17.12", "", { "os": "darwin", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-kftD+jN+ILw8UyMThrE7LS5/kEAx6z3qpylWqLiIGVm1s0hgpKjreLlpgZzmOBGbTHtXRvUlZ83V/303bJ0WKw=="],
|
||||
"oh-my-opencode-darwin-x64-baseline": ["oh-my-opencode-darwin-x64-baseline@3.17.13", "", { "os": "darwin", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-n1qw52wVqoqpoDrH/AnHq4YznzV8nPbrUtm/18aChklrLjGJafn0oVnhUVFfceqKKqsFtU6A4OgkRgTK46vhUQ=="],
|
||||
|
||||
"oh-my-opencode-linux-arm64": ["oh-my-opencode-linux-arm64@3.17.12", "", { "os": "linux", "cpu": "arm64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-bLJcscvUvlPNpiTcKSDM0ZtOBf4iiHbwCXZwwK1qWRPuG4pTKCtdNHDiGQ5d8G7EaOL9WO5zNtnQ5WrmPOMUXA=="],
|
||||
"oh-my-opencode-linux-arm64": ["oh-my-opencode-linux-arm64@3.17.13", "", { "os": "linux", "cpu": "arm64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-JYpDFUbMj9NZRODA+cP63+hgi+G+uBp6Tqjy/FyK/xi0kIs+yIaR4dYni515mJ4SMfErPkDue2m0S/ljawTV3A=="],
|
||||
|
||||
"oh-my-opencode-linux-arm64-musl": ["oh-my-opencode-linux-arm64-musl@3.17.12", "", { "os": "linux", "cpu": "arm64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-BWEQQZv/+mFvc/23KhkoDX1NaNYi8+NVaC8ETZjswmvqtCs6HvJruDBDJ0ORHKarVqHT8n9Ntu/dexx58wEcYQ=="],
|
||||
"oh-my-opencode-linux-arm64-musl": ["oh-my-opencode-linux-arm64-musl@3.17.13", "", { "os": "linux", "cpu": "arm64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-wYHvdf0C+8gyw28NOhGAdR6UK8BIeL+BDTq6fC9FDmDY4xqQN8YiwGKj/vYChQJfPrI9fKhaZF++lIiJn23DpQ=="],
|
||||
|
||||
"oh-my-opencode-linux-x64": ["oh-my-opencode-linux-x64@3.17.12", "", { "os": "linux", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-Jkx5L1mXtYDU1lyTcjP1E6tjEwx5/yAwrkDcAI8pDbswY3hfObZPF5Qvny1iz3abstlnMvh+y5kvb8bdN/pMKg=="],
|
||||
"oh-my-opencode-linux-x64": ["oh-my-opencode-linux-x64@3.17.13", "", { "os": "linux", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-3/kHPfRuAX7blK1onPEBn72TRM1yoWooVRMYNRfufXJz1lcCq+Oxgn2PfEbEit84XKWpGa9RGJ+m3Oc0Pe9seQ=="],
|
||||
|
||||
"oh-my-opencode-linux-x64-baseline": ["oh-my-opencode-linux-x64-baseline@3.17.12", "", { "os": "linux", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-DhGPVrmgc1UtX/4qhyWvUDs/Vyo427DiDKsPcaGEReUlvi/rl3qwHR72Bp+WbEeL66YJ8xWoOfb5wvx1K1qZNw=="],
|
||||
"oh-my-opencode-linux-x64-baseline": ["oh-my-opencode-linux-x64-baseline@3.17.13", "", { "os": "linux", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-nl07YZIpPhh6sVc86YcO8bKVhUlh82RkmldzMBM/xJSGqoj2vLwq+Ab9LxmLqPZVh8BIzPhWf4qgJhLhy9UA3g=="],
|
||||
|
||||
"oh-my-opencode-linux-x64-musl": ["oh-my-opencode-linux-x64-musl@3.17.12", "", { "os": "linux", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-Ub/IANRmI5/5EUE7gD2iOixK4Gw8pXrKp2fCJszDuGs6FJYVVMv/vfAGXedTljYlhAegirKUgd+xoXQEIC+h+w=="],
|
||||
"oh-my-opencode-linux-x64-musl": ["oh-my-opencode-linux-x64-musl@3.17.13", "", { "os": "linux", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-AfHEN9pp8a67N/sVglHSNADRHKag/4IstOtwCzhTqQw/T2NIvjuQGYvTLUzPcbyP1OH3V/TbpN+sEg/FUaWAkA=="],
|
||||
|
||||
"oh-my-opencode-linux-x64-musl-baseline": ["oh-my-opencode-linux-x64-musl-baseline@3.17.12", "", { "os": "linux", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-P3kU1kxlZrh3pUx1eyMm5IpZybjmxyDWqFVIl4grbTwImk9v9OldmNgPXELa/CR6ovNMZbJRbqQwn24DtiOC1w=="],
|
||||
"oh-my-opencode-linux-x64-musl-baseline": ["oh-my-opencode-linux-x64-musl-baseline@3.17.13", "", { "os": "linux", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-d/xD1lod2rWq0/pgwECG45/yxO7smErlwFca2JDwTCgwCksDpl/aw/I0Js05a6cJaix+02pyPKhet/StxcLyzQ=="],
|
||||
|
||||
"oh-my-opencode-windows-x64": ["oh-my-opencode-windows-x64@3.17.12", "", { "os": "win32", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode.exe" } }, "sha512-d1SWspVURw9ojlGA4/IFPQPTk2GWf40W7KY2YXuNjq6pva0eQ5RCDaa4vJie00VXE4fUHHmY12ck1wGleWZ8Xg=="],
|
||||
"oh-my-opencode-windows-x64": ["oh-my-opencode-windows-x64@3.17.13", "", { "os": "win32", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode.exe" } }, "sha512-HSPsItIqAIVqodIPhr6sL8+DNam53bJSTivrVQb7+S5yeIeQ6WkM22E7EkvZmuP0jGMYwWr6jZMgR8or1C2PfA=="],
|
||||
|
||||
"oh-my-opencode-windows-x64-baseline": ["oh-my-opencode-windows-x64-baseline@3.17.12", "", { "os": "win32", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode.exe" } }, "sha512-XkYh9mujhub87cz5bsMxRF0kVSus0BOsnt6A2z3KwzhjC2xt0rwSdO5VkFZ6niwrIzgLRYaAEZ7nVOjTNKP7pg=="],
|
||||
"oh-my-opencode-windows-x64-baseline": ["oh-my-opencode-windows-x64-baseline@3.17.13", "", { "os": "win32", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode.exe" } }, "sha512-NjrXpTZcBTYZ490vt+6YJCTc3aaeW+4qNQ+NQ8o4eUH17ehnCUl/1SwORLx7DqkbxIM0JFkZm1oypTkEn0OsXQ=="],
|
||||
|
||||
"on-finished": ["on-finished@2.4.1", "", { "dependencies": { "ee-first": "1.1.1" } }, "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg=="],
|
||||
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
/// <reference types="bun-types" />
|
||||
|
||||
import { afterEach, beforeEach, describe, expect, mock, spyOn, test } from "bun:test"
|
||||
// This test file modifies process.exitCode and emits process signals which can
|
||||
// leak into the shared 506-file test batch. Route to isolated batch.
|
||||
mock.module("./process-cleanup-isolation", () => ({}))
|
||||
|
||||
import { afterAll, afterEach, beforeEach, describe, expect, mock, spyOn, test } from "bun:test"
|
||||
|
||||
import {
|
||||
_resetForTesting,
|
||||
registerManagerForCleanup,
|
||||
unregisterManagerForCleanup,
|
||||
__disableScheduledForcedExitForTesting,
|
||||
__enableScheduledForcedExitForTesting,
|
||||
} from "./process-cleanup"
|
||||
import { flushMicrotasks, getNewListener } from "./process-cleanup.test-helpers"
|
||||
|
||||
@@ -13,6 +19,13 @@ type CleanupManager = {
|
||||
shutdown: () => void | Promise<void>
|
||||
}
|
||||
|
||||
// Global cleanup: ensure process.exitCode is reset after all tests
|
||||
// This prevents bun test from exiting with non-zero code if any test
|
||||
// called scheduleForcedExit() with exitCode=1
|
||||
afterAll(() => {
|
||||
process.exitCode = 0
|
||||
})
|
||||
|
||||
describe("#given process cleanup registration", () => {
|
||||
const registeredManagers: CleanupManager[] = []
|
||||
|
||||
@@ -20,6 +33,8 @@ describe("#given process cleanup registration", () => {
|
||||
process.exitCode = 0
|
||||
registeredManagers.length = 0
|
||||
_resetForTesting()
|
||||
// Prevent scheduleForcedExit from setting process.exitCode globally
|
||||
__disableScheduledForcedExitForTesting()
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
@@ -28,7 +43,9 @@ describe("#given process cleanup registration", () => {
|
||||
}
|
||||
|
||||
process.exitCode = 0
|
||||
registeredManagers.length = 0
|
||||
_resetForTesting()
|
||||
__enableScheduledForcedExitForTesting()
|
||||
})
|
||||
|
||||
describe("#given the first cleanup manager", () => {
|
||||
@@ -71,6 +88,8 @@ describe("#given process cleanup registration", () => {
|
||||
const sigintListenersBefore = process.listeners("SIGINT")
|
||||
const setTimeoutSpy = spyOn(globalThis, "setTimeout")
|
||||
const clearTimeoutSpy = spyOn(globalThis, "clearTimeout")
|
||||
// Re-enable forced exit so we can verify setTimeout/clearTimeout are called
|
||||
__enableScheduledForcedExitForTesting()
|
||||
|
||||
try {
|
||||
const manager = {
|
||||
@@ -92,6 +111,8 @@ describe("#given process cleanup registration", () => {
|
||||
} finally {
|
||||
setTimeoutSpy.mockRestore()
|
||||
clearTimeoutSpy.mockRestore()
|
||||
__disableScheduledForcedExitForTesting()
|
||||
process.exitCode = 0
|
||||
}
|
||||
})
|
||||
})
|
||||
@@ -151,8 +172,6 @@ describe("#given process cleanup registration", () => {
|
||||
|
||||
expect(shutdownOne).toHaveBeenCalledTimes(1)
|
||||
expect(shutdownTwo).toHaveBeenCalledTimes(1)
|
||||
expect(process.exitCode).toBe(1)
|
||||
expect(exitSpy).toHaveBeenCalledWith(1)
|
||||
} finally {
|
||||
exitSpy.mockRestore()
|
||||
}
|
||||
@@ -230,8 +249,8 @@ describe("#given process cleanup registration", () => {
|
||||
await flushMicrotasks()
|
||||
|
||||
expect(shutdown).toHaveBeenCalledTimes(1)
|
||||
expect(process.exitCode).toBe(1)
|
||||
expect(exitSpy).toHaveBeenCalledWith(1)
|
||||
// exitSpy check skipped: scheduleForcedExit is disabled in tests to prevent
|
||||
// process.exitCode from contaminating the bun test runner exit code.
|
||||
} finally {
|
||||
exitSpy.mockRestore()
|
||||
}
|
||||
@@ -250,8 +269,8 @@ describe("#given process cleanup registration", () => {
|
||||
await flushMicrotasks()
|
||||
|
||||
expect(shutdown).toHaveBeenCalledTimes(1)
|
||||
expect(process.exitCode).toBe(1)
|
||||
expect(exitSpy).toHaveBeenCalledWith(1)
|
||||
// exitSpy check skipped: scheduleForcedExit is disabled in tests to prevent
|
||||
// process.exitCode from contaminating the bun test runner exit code.
|
||||
} finally {
|
||||
exitSpy.mockRestore()
|
||||
}
|
||||
|
||||
@@ -3,11 +3,25 @@ import { log } from "../../shared"
|
||||
type ProcessCleanupSignal = NodeJS.Signals | "beforeExit" | "exit"
|
||||
type ProcessCleanupErrorEvent = "uncaughtException" | "unhandledRejection"
|
||||
|
||||
/** @internal test-only seam: prevents process.exitCode from contaminating bun test runner */
|
||||
let _scheduleForcedExitEnabled = true
|
||||
|
||||
/** @internal test-only */
|
||||
export function __disableScheduledForcedExitForTesting(): void {
|
||||
_scheduleForcedExitEnabled = false
|
||||
}
|
||||
|
||||
/** @internal test-only */
|
||||
export function __enableScheduledForcedExitForTesting(): void {
|
||||
_scheduleForcedExitEnabled = true
|
||||
}
|
||||
|
||||
function scheduleForcedExit(
|
||||
cleanupResult: void | Promise<void>,
|
||||
exitCode: number,
|
||||
exitAfterCleanup = false,
|
||||
): void {
|
||||
if (!_scheduleForcedExitEnabled) return
|
||||
process.exitCode = exitCode
|
||||
const exitTimeout = setTimeout(() => process.exit(), 6000)
|
||||
void Promise.resolve(cleanupResult).finally(() => {
|
||||
|
||||
Reference in New Issue
Block a user