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
115 lines
4.1 KiB
JavaScript
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");
|