chore(P14-8): 完成运营化与验收收口
这个提交包含在:
@@ -0,0 +1,83 @@
|
||||
|
||||
const outbox = require("../../../../src/services/integrations/outbox");
|
||||
|
||||
describe("Integration Outbox", () => {
|
||||
it("enqueues new event", async () => {
|
||||
const mockPrisma = {
|
||||
integrationOutbox: {
|
||||
findUnique: vi.fn().mockResolvedValue(null),
|
||||
create: vi.fn().mockResolvedValue({ id: 1, status: "pending" }),
|
||||
},
|
||||
};
|
||||
const result = await outbox.enqueueIntegrationEvent(mockPrisma, { eventType: "test" });
|
||||
expect(result.id).toBe(1);
|
||||
expect(result.duplicated).toBe(false);
|
||||
});
|
||||
|
||||
it("detects duplicated event", async () => {
|
||||
const mockPrisma = {
|
||||
integrationOutbox: {
|
||||
findUnique: vi.fn().mockResolvedValue({ id: 2, status: "pending" }),
|
||||
},
|
||||
};
|
||||
const result = await outbox.enqueueIntegrationEvent(mockPrisma, { eventType: "test", dedupeKey: "key" });
|
||||
expect(result.id).toBe(2);
|
||||
expect(result.duplicated).toBe(true);
|
||||
});
|
||||
|
||||
it("marks as processing", async () => {
|
||||
const mockPrisma = {
|
||||
integrationOutbox: {
|
||||
update: vi.fn().mockResolvedValue({ id: 1, status: "processing" }),
|
||||
},
|
||||
};
|
||||
const res = await outbox.markOutboxProcessing(mockPrisma, 1, "actor");
|
||||
expect(res.status).toBe("processing");
|
||||
});
|
||||
|
||||
it("fetches pending events", async () => {
|
||||
const mockPrisma = {
|
||||
integrationOutbox: {
|
||||
findMany: vi.fn().mockResolvedValue([{ id: 1 }]),
|
||||
},
|
||||
};
|
||||
const items = await outbox.fetchPendingOutboxEvents(mockPrisma, { batchSize: 5 });
|
||||
expect(items.length).toBe(1);
|
||||
});
|
||||
|
||||
it("marks outbox succeeded", async () => {
|
||||
const mockPrisma = {
|
||||
integrationOutbox: {
|
||||
update: vi.fn().mockResolvedValue({ id: 1, status: "succeeded" }),
|
||||
},
|
||||
};
|
||||
const res = await outbox.markOutboxSucceeded(mockPrisma, 1, "actor");
|
||||
expect(res.status).toBe("succeeded");
|
||||
});
|
||||
|
||||
it("handles failed outbox and schedules retry", async () => {
|
||||
const mockPrisma = {
|
||||
integrationOutbox: {
|
||||
update: vi.fn().mockImplementation(async ({ data }) => {
|
||||
return { status: data.status, retry: data.next_retry_at };
|
||||
}),
|
||||
},
|
||||
};
|
||||
const res = await outbox.markOutboxFailed(mockPrisma, {}, { id: 1, attempts: 0 }, { retryable: true }, "actor");
|
||||
expect(res.status).toBe("failed");
|
||||
expect(res.retry).toBeInstanceOf(Date);
|
||||
});
|
||||
|
||||
it("moves to dead_letter if max attempts reached", async () => {
|
||||
const mockPrisma = {
|
||||
integrationOutbox: {
|
||||
update: vi.fn().mockImplementation(async ({ data }) => {
|
||||
return { status: data.status, retry: data.next_retry_at };
|
||||
}),
|
||||
},
|
||||
};
|
||||
const res = await outbox.markOutboxFailed(mockPrisma, {}, { id: 1, attempts: 5, max_attempts: 5 }, { retryable: true }, "actor");
|
||||
expect(res.status).toBe("dead_letter");
|
||||
expect(res.retry).toBeNull();
|
||||
});
|
||||
});
|
||||
在新工单中引用
屏蔽一个用户