Files
EpicNext-Cms/src/features/housekeeping/foundation/commands/audit-envelope.test.ts
T

165 lines
4.5 KiB
TypeScript

import { describe, expect, it, vi } from "vitest";
import type { AuditEntry, HousekeepingAuditWriter } from "@/lib/services/audit";
import {
runWithAuditIntent,
writeIntent,
writeOutcome,
} from "./audit-envelope";
const auditEntry: AuditEntry = {
userId: 7,
action: "maintenance.run",
target: "system",
correlationId: "corr-command-7",
domain: "system",
reason: "Scheduled maintenance",
};
function createWriter(): HousekeepingAuditWriter {
return { write: vi.fn().mockResolvedValue(undefined) };
}
describe("audit command envelope", () => {
it("writes an intent with the original correlation evidence", async () => {
const writer = createWriter();
await writeIntent(writer, auditEntry);
expect(writer.write).toHaveBeenCalledWith(
{ ...auditEntry, outcome: "intent" },
undefined,
);
});
it("writes denied and failure outcomes as durable evidence", async () => {
const writer = createWriter();
await writeOutcome(writer, auditEntry, "denied");
await writeOutcome(writer, auditEntry, "failure");
expect(writer.write).toHaveBeenNthCalledWith(
1,
{ ...auditEntry, outcome: "denied" },
undefined,
);
expect(writer.write).toHaveBeenNthCalledWith(
2,
{ ...auditEntry, outcome: "failure" },
undefined,
);
});
it("blocks the operation when intent persistence fails", async () => {
const writer: HousekeepingAuditWriter = {
write: vi.fn().mockRejectedValue(new Error("audit unavailable")),
};
const operation = vi.fn().mockResolvedValue("external operation result");
await expect(
runWithAuditIntent(writer, auditEntry, operation),
).rejects.toThrow("audit unavailable");
expect(operation).not.toHaveBeenCalled();
});
it("writes a success outcome after the operation completes", async () => {
const writer = createWriter();
await expect(
runWithAuditIntent(writer, auditEntry, () => Promise.resolve("done")),
).resolves.toBe("done");
expect(writer.write).toHaveBeenNthCalledWith(
1,
{ ...auditEntry, outcome: "intent" },
undefined,
);
expect(writer.write).toHaveBeenNthCalledWith(
2,
{ ...auditEntry, outcome: "success" },
undefined,
);
});
it("writes a failure outcome before rethrowing an operation failure", async () => {
const writer = createWriter();
await expect(
runWithAuditIntent(writer, auditEntry, () =>
Promise.reject(new Error("operation failed")),
),
).rejects.toThrow("operation failed");
expect(writer.write).toHaveBeenNthCalledWith(
2,
{ ...auditEntry, outcome: "failure" },
undefined,
);
});
it("preserves the original operation error when failure evidence rejects", async () => {
const original = new Error("operation failed");
const auditFailure = new Error("audit failure");
const writer: HousekeepingAuditWriter = {
write: vi
.fn()
.mockResolvedValueOnce(undefined)
.mockRejectedValueOnce(auditFailure),
};
await expect(
runWithAuditIntent(writer, auditEntry, () => Promise.reject(original)),
).rejects.toBe(original);
expect(
(original as Error & { auditOutcomeError?: unknown }).auditOutcomeError,
).toBe(auditFailure);
});
it("throws a completed-operation error when success evidence rejects", async () => {
const auditFailure = new Error("audit failure");
const writer: HousekeepingAuditWriter = {
write: vi
.fn()
.mockResolvedValueOnce(undefined)
.mockRejectedValueOnce(auditFailure),
};
await expect(
runWithAuditIntent(writer, auditEntry, () => Promise.resolve("done")),
).rejects.toMatchObject({
operationCompleted: true,
operationResult: "done",
auditOutcomeError: auditFailure,
});
});
it("preserves a frozen operation error when failure evidence rejects", async () => {
const original = Object.freeze(new Error("operation failed"));
const writer: HousekeepingAuditWriter = {
write: vi
.fn()
.mockResolvedValueOnce(undefined)
.mockRejectedValueOnce(new Error("audit failure")),
};
await expect(
runWithAuditIntent(writer, auditEntry, () => Promise.reject(original)),
).rejects.toBe(original);
});
it("preserves a pathological rejection when failure evidence rejects", async () => {
const { proxy, revoke } = Proxy.revocable(
new Error("operation failed"),
{},
);
revoke();
const writer: HousekeepingAuditWriter = {
write: vi
.fn()
.mockResolvedValueOnce(undefined)
.mockRejectedValueOnce(new Error("audit failure")),
};
let rejected: unknown;
try {
await runWithAuditIntent(writer, auditEntry, () => Promise.reject(proxy));
} catch (error) {
rejected = error;
}
expect(rejected === proxy).toBe(true);
});
});