import { describe, expect, it } from "@suaveplan/testing/runner"; import { AuditEventType, AuditSeverity } from "../constants/index.js"; import { AuditActorSchema, AuditEventSchema, AuditEventTypeSchema, AuditQueryOptionsSchema, AuditRetentionPolicySchema, AuditSeveritySchema, AuditTargetSchema, ChainVerificationResultSchema, RetentionResultSchema, } from "./audit-logging.schemas.js"; describe("AuditSeveritySchema", () => { it("accepts valid values", { timeout: 5000 }, () => { for (const v of Object.values(AuditSeverity)) { expect(AuditSeveritySchema.parse(v)).toBe(v); } }); it("rejects invalid value", { timeout: 5000 }, () => { expect(() => AuditSeveritySchema.parse("trace")).toThrow(); }); }); describe("AuditEventTypeSchema", () => { it("accepts all built-in event types", { timeout: 5000 }, () => { for (const v of Object.values(AuditEventType)) { expect(AuditEventTypeSchema.parse(v)).toBe(v); } }); it("rejects unknown type", { timeout: 5000 }, () => { expect(() => AuditEventTypeSchema.parse("not_a_type")).toThrow(); }); }); describe("AuditActorSchema", () => { it("accepts empty object", { timeout: 5000 }, () => { expect(AuditActorSchema.parse({})).toEqual({}); }); it("accepts all fields", { timeout: 5000 }, () => { const actor = { userId: "u1", sessionId: "s1", apiKeyId: "k1", ipAddress: "1.2.3.4", userAgent: "Mozilla", tenantId: "t1", }; expect(AuditActorSchema.parse(actor)).toEqual(actor); }); }); describe("AuditTargetSchema", () => { it("accepts required fields", { timeout: 5000 }, () => { expect(AuditTargetSchema.parse({ type: "doc", id: "d1" })).toEqual({ type: "doc", id: "d1", }); }); it("accepts metadata", { timeout: 5000 }, () => { const t = { type: "doc", id: "d1", metadata: { version: 2 } }; expect(AuditTargetSchema.parse(t)).toEqual(t); }); it("rejects missing required fields", { timeout: 5000 }, () => { expect(() => AuditTargetSchema.parse({ type: "doc" })).toThrow(); }); }); describe("AuditEventSchema", () => { const base = { id: "evt-1", type: AuditEventType.AUTH_LOGIN, severity: AuditSeverity.INFO, actor: { userId: "u1" }, timestamp: new Date("2024-01-01"), hash: "deadbeef", }; it("accepts valid event", { timeout: 5000 }, () => { const result = AuditEventSchema.parse(base); expect(result.id).toBe("evt-1"); }); it("accepts custom event type string via union", { timeout: 5000 }, () => { const result = AuditEventSchema.parse({ ...base, type: "custom_event", }); expect(result.type).toBe("custom_event"); }); it("accepts all optional fields", { timeout: 5000 }, () => { const event = { ...base, target: { type: "doc", id: "d1" }, details: { key: "val" }, previousHash: "prev", tenantId: "t1", correlationId: "corr", }; expect(AuditEventSchema.parse(event)).toEqual(event); }); it("rejects missing required fields", { timeout: 5000 }, () => { expect(() => AuditEventSchema.parse({ ...base, id: undefined }) ).toThrow(); }); }); describe("AuditQueryOptionsSchema", () => { it("accepts empty object", { timeout: 5000 }, () => { expect(AuditQueryOptionsSchema.parse({})).toEqual({}); }); it("accepts severity as single value", { timeout: 5000 }, () => { const r = AuditQueryOptionsSchema.parse({ severity: AuditSeverity.ERROR, }); expect(r.severity).toBe(AuditSeverity.ERROR); }); it("accepts severity as array", { timeout: 5000 }, () => { const r = AuditQueryOptionsSchema.parse({ severity: [AuditSeverity.ERROR, AuditSeverity.CRITICAL], }); expect(Array.isArray(r.severity)).toBe(true); }); }); describe("AuditRetentionPolicySchema", () => { it("accepts valid policy", { timeout: 5000 }, () => { const p = { retentionDays: 90, archiveBeforeDelete: true, archiveLocation: "s3://bucket", }; expect(AuditRetentionPolicySchema.parse(p)).toEqual(p); }); it("rejects retentionDays = 0", { timeout: 5000 }, () => { expect(() => AuditRetentionPolicySchema.parse({ retentionDays: 0, archiveBeforeDelete: false, }) ).toThrow(); }); }); describe("ChainVerificationResultSchema", () => { it("accepts valid result", { timeout: 5000 }, () => { expect(ChainVerificationResultSchema.parse({ valid: true })).toEqual({ valid: true, }); expect( ChainVerificationResultSchema.parse({ valid: false, brokenAt: 3, reason: "mismatch", }) ).toBeDefined(); }); }); describe("RetentionResultSchema", () => { it("accepts valid result", { timeout: 5000 }, () => { const r = { eventsDeleted: 5, eventsArchived: 3, errors: ["some error"], }; expect(RetentionResultSchema.parse(r)).toEqual(r); }); });