Files
reverse-engineering-anything/tests/acceptance/setup/updateAliasCli.test.ts
morluto 01cdbbdc55 fix(update): bound package-manager output retention
Reuse supervised raw-byte capture with a 4 MiB aggregate budget. Drain package-manager output through physical close, reject oversized complete replies, and let verbose installs finish with explicitly bounded failure diagnostics. Preserve existing command resolution, selected environment/cwd, runtime prerequisites and signal policy.

Own human progress backpressure and final write acknowledgements without ending borrowed stderr. Continue draining after destination failures and observe outstanding write rejections through their error event.

Validation: 152 checks across 12 focused files, followed by a 44-check rerun including two additional no-deadline waiter controls; typecheck/lint, docs and discovery pass. The public oversized-metadata regression fails on 4f7b5fb60. Fixtures execute owned Node/fake npm/Bun commands; no actual package install or registry request. Native Windows/Linux and exhausting-output/OOM scenarios were not run.

Small completed CLI checks return identical replies and token estimates. Six sequential baseline/candidate tasks separate first-process and two warm repeats; no speedup, true-cold or large-install memory claim. Existing descendant cleanup and signal behavior is outside this output-bound fix.

Closes #4888.
2026-10-18 05:57:57 +08:00

129 lines
5.1 KiB
TypeScript

import { mkdir, readFile, writeFile } from "node:fs/promises";
import { delimiter, join } from "node:path";
import { expect } from "vitest";
import { PRODUCT_IDENTITY } from "../../../src/identity.js";
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
import { cliTest } from "../../support/cli/cliFixture.js";
cliTest(
"root update flag uses the verified workflow and preserves executable output policies",
async ({ cli }) => {
const home = await createTestTempDirectory("rea-update-alias-");
const bin = join(home, "bin");
const script = join(home, "npm-fixture.mjs");
const log = join(home, "commands.jsonl");
await mkdir(bin);
await writeFile(log, "");
await writeFile(
script,
`
import {appendFileSync} from 'node:fs';
import {join} from 'node:path';
const args=process.argv.slice(2);
appendFileSync(process.env.REA_TEST_NPM_LOG, JSON.stringify(args)+'\\n');
if(args[0]==='root') console.log(join(process.env.USERPROFILE,'unowned','node_modules'));
else if(args[0]==='prefix') console.log(join(process.env.USERPROFILE,'unowned'));
else if(args[0]==='view') {
if(process.env.REA_TEST_NPM_FAILURE==='1') {process.stderr.write('owned fake registry denied');process.exitCode=2;}
else if(process.env.REA_TEST_NPM_OVERSIZED==='1') process.stdout.write(JSON.stringify(${JSON.stringify(PRODUCT_IDENTITY.packageVersion)})+' '.repeat(4 * 1024 * 1024));
else console.log(JSON.stringify(${JSON.stringify(PRODUCT_IDENTITY.packageVersion)}));
} else {process.stderr.write('No installation or unexpected package-manager commands are allowed');process.exitCode=97;}
`,
);
await writeFile(
join(bin, process.platform === "win32" ? "npm.cmd" : "npm"),
process.platform === "win32"
? '@echo off\r\n"%REA_TEST_NODE%" "%REA_TEST_NPM_SCRIPT%" %*\r\n'
: '#!/bin/sh\nexec "$REA_TEST_NODE" "$REA_TEST_NPM_SCRIPT" "$@"\n',
{ mode: 0o700 },
);
const run = (
arguments_: readonly string[],
failure = false,
oversized = false,
) =>
cli.run({
arguments: arguments_,
cwd: home,
timeoutMs: 20_000,
environment: {
USERPROFILE: home,
PATH: [
bin,
...(process.platform === "win32"
? [join(process.env.SystemRoot ?? "C:\\Windows", "System32")]
: ["/usr/bin", "/bin"]),
].join(delimiter),
npm_config_prefix: join(home, "prefix"),
npm_config_cache: join(home, "cache"),
npm_config_user_agent: "npm/test",
REA_TEST_NODE: process.execPath,
REA_TEST_NPM_SCRIPT: script,
REA_TEST_NPM_LOG: log,
REA_TEST_NPM_FAILURE: failure ? "1" : "0",
REA_TEST_NPM_OVERSIZED: oversized ? "1" : "0",
CI: "1",
NO_UPDATE_NOTIFIER: "1",
},
});
const canonical = await run(["update", "--json"]);
expect(canonical.exitCode, canonical.stderr).toBe(0);
expect(canonical.json).toMatchObject({
status: "current",
currentVersion: PRODUCT_IDENTITY.packageVersion,
latestVersion: PRODUCT_IDENTITY.packageVersion,
});
const alias = await run(["--json", "--update"]);
expect(alias.exitCode, alias.stderr).toBe(0);
expect(alias.json).toEqual(canonical.json);
const filtered = await run([
"--update",
"--format=json",
"--full-output",
"--filter-output=status",
]);
expect(filtered.exitCode, filtered.stderr).toBe(0);
expect(filtered.json).toMatchObject({
ok: true,
data: "current",
meta: { command: expect.stringContaining("update") },
});
const failed = await run(["--update", "--json"], true);
expect(failed.exitCode).toBe(1);
expect(failed.json).toMatchObject({
status: "failed",
reason: "version-check",
remediation: expect.stringContaining("owned fake registry denied"),
});
const oversized = await run(["update", "--json"], false, true);
expect(oversized.exitCode).toBe(1);
expect(oversized.json).toMatchObject({
status: "failed",
reason: "version-check",
remediation: expect.stringContaining("complete-output retention budget"),
});
const before = await readFile(log, "utf8");
const ambiguous = await run(["providers", "--update", "--json"]);
expect(ambiguous.exitCode).toBe(1);
expect(ambiguous.json).toMatchObject({
code: "UPDATE_FAILED",
message: expect.stringContaining("rea update"),
});
expect(await readFile(log, "utf8")).toBe(before);
const help = await run(["--update", "--help"]);
expect(help.exitCode, help.stderr).toBe(0);
expect(help.stdout).toContain("update");
expect(await readFile(log, "utf8")).toBe(before);
const commands: unknown[] = before
.trim()
.split("\n")
.map((line) => JSON.parse(line));
expect(commands.length).toBeGreaterThan(0);
expect(commands).toEqual(
expect.arrayContaining([expect.arrayContaining(["view"])]),
);
for (const command of commands) expect(command).not.toContain("install");
},
);