mirror of
https://github.com/morluto/rea.git
synced 2026-11-14 18:52:48 +00:00
inspect-byte-entropy passed a hard-coded "rea-byte-entropy" to the shared command finalizer, so a failed descriptor close named a provider that differs from the Evidence provider ("byte-entropy"). Use BYTE_ENTROPY_PROVIDER.id so both come from one owner.
Fixes #7279
Co-Authored-By: gensokyo-dev <gensokyo-dev@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
104 lines
3.0 KiB
TypeScript
104 lines
3.0 KiB
TypeScript
import { writeFile } from "node:fs/promises";
|
|
import { join } from "node:path";
|
|
import { afterEach, expect, it, vi } from "vitest";
|
|
|
|
const closeState = vi.hoisted(() => ({
|
|
path: "",
|
|
failures: 0,
|
|
attempts: 0,
|
|
release: [] as Array<() => Promise<void>>,
|
|
}));
|
|
|
|
vi.mock("node:fs/promises", async (importOriginal) => {
|
|
const fs = await importOriginal<typeof import("node:fs/promises")>();
|
|
return {
|
|
...fs,
|
|
open: async (...args: Parameters<typeof fs.open>) => {
|
|
const handle = await fs.open(...args);
|
|
if (args[0] !== closeState.path) return handle;
|
|
const close = handle.close.bind(handle);
|
|
closeState.release.push(close);
|
|
handle.close = async () => {
|
|
closeState.attempts++;
|
|
if (closeState.failures > 0) {
|
|
closeState.failures--;
|
|
throw Object.assign(new Error("injected descriptor close failure"), {
|
|
code: "EIO",
|
|
});
|
|
}
|
|
await close();
|
|
};
|
|
return handle;
|
|
},
|
|
};
|
|
});
|
|
|
|
import { createCli } from "../../src/cli.js";
|
|
import { CLI_COMMANDS } from "../../src/cliCommandNames.js";
|
|
import { BYTE_ENTROPY_PROVIDER } from "../../src/domain/investigationProviders.js";
|
|
import { createTestTempDirectory } from "../fixtures/temporaryDirectory.js";
|
|
|
|
const exitCode = process.exitCode;
|
|
afterEach(async () => {
|
|
closeState.path = "";
|
|
closeState.failures = 0;
|
|
closeState.attempts = 0;
|
|
process.exitCode = exitCode;
|
|
// Injected failures leave the real descriptor open; release it before the
|
|
// fixture directory is removed.
|
|
await Promise.all(closeState.release.splice(0).map((close) => close()));
|
|
});
|
|
|
|
const inspect = async (path: string): Promise<unknown> => {
|
|
let stdout = "";
|
|
await createCli({}).serve(
|
|
[CLI_COMMANDS.inspectByteEntropy, path, "--format", "json"],
|
|
{
|
|
env: {},
|
|
stdout: (text) => {
|
|
stdout += text;
|
|
},
|
|
exit: () => undefined,
|
|
},
|
|
);
|
|
return JSON.parse(stdout);
|
|
};
|
|
|
|
it.each([
|
|
{ closeFails: true, attempts: 2 },
|
|
{ closeFails: false, attempts: 1 },
|
|
])(
|
|
"names the Evidence provider in cleanup diagnostics (close fails: $closeFails)",
|
|
async ({ closeFails, attempts }) => {
|
|
const directory = await createTestTempDirectory("rea-entropy-cleanup-cli-");
|
|
const path = join(directory, "entropy-input.bin");
|
|
await writeFile(path, "entropy fixture\n".repeat(32));
|
|
closeState.path = path;
|
|
closeState.failures = closeFails ? Number.MAX_SAFE_INTEGER : 0;
|
|
|
|
const output = await inspect(path);
|
|
|
|
expect(closeState.attempts).toBe(attempts);
|
|
if (!closeFails) {
|
|
expect(output).toMatchObject({
|
|
provider: { id: BYTE_ENTROPY_PROVIDER.id },
|
|
});
|
|
expect(output).not.toHaveProperty("code");
|
|
return;
|
|
}
|
|
expect(output).toMatchObject({
|
|
code: "cleanup_incomplete",
|
|
details: {
|
|
cleanup: "incomplete",
|
|
diagnostics: {
|
|
cleanup_error: {
|
|
code: "cleanup_incomplete",
|
|
details: { provider_id: BYTE_ENTROPY_PROVIDER.id },
|
|
},
|
|
},
|
|
},
|
|
});
|
|
expect(process.exitCode).toBe(1);
|
|
},
|
|
);
|