Files
elizaos--eliza/packages/scripts/test-cloud-run-flush.self-test.mjs
wehub-resource-sync 426e9eeabd
Voice Workbench / headless workbench (mocked backends) (push) Has been cancelled
Voice Workbench / real acoustic lane (nightly, provisioned only) (push) Has been cancelled
ci / test (push) Has been cancelled
ci / lint-and-format (push) Has been cancelled
ci / build (push) Has been cancelled
ci / dev-startup (push) Has been cancelled
gitleaks / gitleaks (push) Has been cancelled
Markdown Links / Relative Markdown Links (push) Has been cancelled
Quality (Extended) / Homepage Build (PR smoke) (push) Has been cancelled
Quality (Extended) / Comment-only diff guard (push) Has been cancelled
Quality (Extended) / Format + Type Safety Ratchet (push) Has been cancelled
Quality (Extended) / Develop Gate (secret scan + UI determinism) (push) Has been cancelled
Quality (Extended) / Develop Gate (lint) (push) Has been cancelled
Chat shell gestures / Chat shell gesture + parity e2e (push) Has been cancelled
Cloud Gateway Discord / Test (push) Has been cancelled
Benchmark Bridge Tests / benchmark (bunx @biomejs/biome check packages/lifeops-bench/src, benchmark-lint) (push) Has been cancelled
Benchmark Bridge Tests / benchmark (bunx vitest run --config packages/lifeops-bench/vitest.config.ts --root packages/lifeops-bench --passWithNoTests, benchmark-tests) (push) Has been cancelled
Build Agent Image / build-and-push (push) Has been cancelled
Dev Smoke / bun run dev onboarding chat (push) Has been cancelled
Dev Smoke / Vite HMR dependency-level smoke (push) Has been cancelled
Electrobun Submodule Guard / electrobun gitlink is fetchable (push) Has been cancelled
Publish @elizaos/example-code / check_npm (push) Has been cancelled
Publish @elizaos/example-code / publish_npm (push) Has been cancelled
Publish @elizaos/plugin-elizacloud / verify_version (push) Has been cancelled
Publish @elizaos/plugin-elizacloud / publish_npm (push) Has been cancelled
Sandbox Live Smoke / Sandbox live smoke (push) Has been cancelled
Snap Build & Test / Build Snap (amd64) (push) Has been cancelled
Snap Build & Test / Build Snap (arm64) (push) Has been cancelled
Test Packaging / elizaos CLI global-install smoke (node + bun) (push) Has been cancelled
Cloud Gateway Webhook / Test (push) Has been cancelled
Cloud Tests / lint-and-types (push) Has been cancelled
Cloud Tests / unit-tests (push) Has been cancelled
Cloud Tests / integration-tests (push) Has been cancelled
Cloud Tests / e2e-tests (push) Has been cancelled
CodeQL Advanced / Analyze (javascript-typescript) (push) Has been cancelled
Deploy Apps Worker (Product 2) / Determine environment (push) Has been cancelled
Deploy Apps Worker (Product 2) / Deploy apps worker to apps-control host (${{ needs.determine-env.outputs.environment }}) (push) Has been cancelled
Deploy Eliza Provisioning Worker / Determine environment (push) Has been cancelled
Deploy Eliza Provisioning Worker / Deploy worker to Hetzner host (${{ needs.determine-env.outputs.environment }} @ ${{ needs.determine-env.outputs.deployment_sha }}) (push) Has been cancelled
Dev Smoke / Classify changed paths (push) Has been cancelled
supply-chain / sbom (push) Has been cancelled
supply-chain / vulnerability-scan (push) Has been cancelled
Build, Push & Deploy to Phala Cloud / build-and-push (push) Has been cancelled
Test Packaging / Validate Packaging Configs (push) Has been cancelled
Test Packaging / Build & Test PyPI Package (push) Has been cancelled
Test Packaging / PyPI on Python ${{ matrix.python }} (push) Has been cancelled
Test Packaging / Pack & Test JS Tarballs (push) Has been cancelled
UI Fixture E2E / ui-fixture-e2e (push) Has been cancelled
UI Fixture E2E / fixture-e2e (push) Has been cancelled
UI Story Gate / story-gate (push) Has been cancelled
vault-ci / test (macos-latest) (push) Has been cancelled
vault-ci / test (ubuntu-latest) (push) Has been cancelled
vault-ci / test (windows-latest) (push) Has been cancelled
vault-ci / app-core wiring tests (push) Has been cancelled
verify-patches / verify patches/CHECKSUMS.sha256 (push) Has been cancelled
Voice Benchmark Smoke / voice-emotion fixture smoke (push) Has been cancelled
Voice Benchmark Smoke / voiceagentbench fixture smoke (push) Has been cancelled
Voice Benchmark Smoke / voicebench-quality unit smoke (push) Has been cancelled
Voice Benchmark Smoke / voicebench TypeScript unit (no audio) (push) Has been cancelled
Voice Benchmark Smoke / voice bench smoke summary (push) Has been cancelled
Windows CI / windows ([bun run --cwd packages/app-core test bun run --cwd packages/elizaos test bun run --cwd packages/cloud/shared test], app-and-cli) (push) Has been cancelled
Windows CI / windows ([bun run --cwd packages/scenario-runner test bun run --cwd packages/vault test bun run --cwd packages/security test bun run --cwd plugins/plugin-coding-tools test], framework-packages) (push) Has been cancelled
Windows CI / windows ([bun run --cwd plugins/plugin-elizacloud test bun run --cwd plugins/plugin-discord test bun run --cwd plugins/plugin-anthropic test bun run --cwd plugins/plugin-openai test bun run --cwd plugins/plugin-app-control test bun run --cwd plugins/pl… (push) Has been cancelled
Windows CI / windows ([node packages/scripts/run-turbo.mjs run build --filter=@elizaos/core --filter=@elizaos/shared --filter=@elizaos/agent --concurrency=4 node packages/scripts/run-bash-linux-only.mjs scripts/verify-riscv64-buildpaths.sh node packages/scripts/run… (push) Has been cancelled
Windows CI / windows ([node packages/scripts/run-turbo.mjs run typecheck --filter=@elizaos/core --filter=@elizaos/shared --filter=@elizaos/cloud-shared --concurrency=4 bun run --cwd packages/core test bun run --cwd packages/shared test], core-runtime, 75) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:43:05 +08:00

115 lines
4.1 KiB
JavaScript

#!/usr/bin/env node
// Regression proof for the "Cloud Tests / unit-tests silently exits 1 with no
// surfaced failure" bug on PR #16062.
//
// Root cause: the batch runner (test-cloud-run.mjs) printed each `bun test`
// dump with `process.stdout.write` and then ended with `process.exit(1)`. When
// stdout is a back-pressured pipe (the GitHub Actions log collector), those
// writes queue in Node's internal stream buffer; the synchronous spawnSync loop
// never yields to drain them, and `process.exit()` tears the process down
// before the flush. The final batch's failure diagnostic AND earlier batches'
// summaries were discarded, so CI showed a bare `exited with code 1` with no
// failing test — a false "silent" failure that hid the real reason.
//
// Fix: write batch output straight to the fd via `fs.writeSync` (blocks until
// the bytes land, cannot be truncated by exit) and end with `process.exitCode`
// instead of `process.exit()`.
//
// This self-test reproduces the exact truncation mechanism: a child writes a
// large tail-marked payload then terminates, its stdout drained by a
// deliberately slow reader to force pipe back-pressure. The buggy pattern loses
// the tail; the fixed pattern preserves it. No repo build required.
import assert from "node:assert/strict";
import { spawn } from "node:child_process";
const TAIL = "===DIAGNOSTIC-TAIL-MUST-SURVIVE===";
// Large enough to overflow the pipe + Node stream high-water mark so the write
// cannot complete synchronously under back-pressure.
const PAYLOAD_BYTES = 4 * 1024 * 1024;
const BUGGY_CHILD = `
const big = "x".repeat(${PAYLOAD_BYTES});
process.stdout.write(big);
process.stdout.write("${TAIL}\\n");
process.exit(1);
`;
const FIXED_CHILD = `
import { writeSync } from "node:fs";
function writeSyncAll(fd, text) {
const buffer = Buffer.from(text, "utf8");
let offset = 0;
while (offset < buffer.length) {
try {
offset += writeSync(fd, buffer, offset, buffer.length - offset);
} catch (error) {
if (error && error.code === "EAGAIN") continue;
throw error;
}
}
}
const big = "x".repeat(${PAYLOAD_BYTES});
writeSyncAll(1, big);
writeSyncAll(1, "${TAIL}\\n");
process.exitCode = 1;
`;
// Drain the child's stdout slowly so the OS pipe buffer fills and the child's
// async writes back-pressure — the condition that makes process.exit() drop
// buffered output. A synchronous fd write is immune.
function runChild(source, { slowReader }) {
return new Promise((resolve, reject) => {
const child = spawn(
process.execPath,
["--input-type=module", "-e", source],
{
stdio: ["ignore", "pipe", "inherit"],
},
);
const chunks = [];
let paused = false;
child.stdout.on("data", (chunk) => {
chunks.push(chunk);
if (slowReader && !paused) {
paused = true;
child.stdout.pause();
setTimeout(() => {
paused = false;
child.stdout.resume();
}, 25);
}
});
child.on("error", reject);
child.on("close", (code) => {
resolve({ code, output: Buffer.concat(chunks).toString("utf8") });
});
});
}
// 1. Reproduce the bug: buggy pattern under back-pressure drops the tail.
const buggy = await runChild(BUGGY_CHILD, { slowReader: true });
assert.equal(buggy.code, 1, "buggy child should still exit non-zero");
assert.ok(
!buggy.output.includes(TAIL),
"expected the buggy process.exit() pattern to truncate the diagnostic tail " +
"under pipe back-pressure (the #16062 silent-exit repro); if this ever " +
"passes the tail through, the repro is no longer valid on this Node.",
);
// 2. Prove the fix: synchronous writes + exitCode preserve the tail AND the code.
const fixed = await runChild(FIXED_CHILD, { slowReader: true });
assert.equal(fixed.code, 1, "fixed child must still exit non-zero");
assert.ok(
fixed.output.includes(TAIL),
"fixed writeSync + process.exitCode pattern must preserve the diagnostic tail",
);
assert.equal(
fixed.output.length,
PAYLOAD_BYTES + TAIL.length + 1,
"fixed pattern must emit the full payload with no truncation",
);
console.log("[test-cloud-run-flush] self-test passed");