182 lines
5.4 KiB
TypeScript
182 lines
5.4 KiB
TypeScript
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);
|
|
});
|
|
});
|