You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

62 lines
1.8 KiB

import { describe, expect, it, vi, beforeEach } from "vitest";
import { noteImportContention, emitResilience } from "@/lib/resilience-metrics";
import { extractMailMeta } from "@/services/imap/snapshot";
import { computeRawHash, sha256 } from "@/utils/hash";
vi.mock("@/lib/logger", () => ({
logger: {
info: vi.fn(),
warn: vi.fn(),
error: vi.fn(),
debug: vi.fn(),
},
}));
import { logger } from "@/lib/logger";
describe("resilience metrics helpers", () => {
beforeEach(() => {
vi.clearAllMocks();
});
it("emitResilience writes stable metric name", () => {
emitResilience("idempotency.hash_collision", "error", { a: 1 });
expect(logger.error).toHaveBeenCalledWith(
expect.objectContaining({ metric: "idempotency.hash_collision", a: 1 }),
"idempotency.hash_collision",
);
});
it("noteImportContention fires on 4th hit", () => {
const id = `mail-${Date.now()}`;
for (let i = 0; i < 3; i++) noteImportContention(id);
expect(logger.warn).not.toHaveBeenCalled();
noteImportContention(id);
expect(logger.warn).toHaveBeenCalledWith(
expect.objectContaining({
metric: "import.contention",
mailId: id,
count: 4,
}),
"import.contention",
);
});
it("subject missing marked when empty subject", () => {
const meta = extractMailMeta({ subject: " " } as never);
expect(meta.subject).toBe("(无主题)");
expect(meta.subjectMissing).toBe(true);
});
it("hash collision salt differs from base raw_hash", () => {
const base = computeRawHash({
date: "2026-01-01T00:00:00.000Z",
from: "a@b.com",
subject: "x",
filenames: ["a.xlsx"],
});
const forked = sha256(`${base}|acc|INBOX|99`);
expect(forked).not.toEqual(base);
});
});