From b4cb661906f6a717c9f96fd24fe7173d3770e8c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Ccaneryy=E2=80=9D?= Date: Mon, 29 Jun 2026 20:24:29 +0300 Subject: [PATCH 1/2] test(stream): cover COMPLETED status and StreamEvent unique dedup --- .../integration/stream-lifecycle.test.ts | 65 +++++++++++++++++++ backend/tests/stream.repository.test.ts | 8 +++ 2 files changed, 73 insertions(+) diff --git a/backend/tests/integration/stream-lifecycle.test.ts b/backend/tests/integration/stream-lifecycle.test.ts index ff1a5f18..116524d8 100644 --- a/backend/tests/integration/stream-lifecycle.test.ts +++ b/backend/tests/integration/stream-lifecycle.test.ts @@ -557,6 +557,71 @@ describe("Stream Lifecycle Integration Tests", () => { }); }); + describe("StreamEvent @@unique([transactionHash, eventType]) deduplication", () => { + it("rejects a duplicate (transactionHash, eventType) insert at the database level", async () => { + const streamId = 11; + const txHash = "unique-constraint-tx-hash"; + + await testPrisma.stream.create({ + data: { + streamId, + sender: SENDER, + recipient: RECIPIENT, + tokenAddress: TOKEN, + ratePerSecond: "10", + depositedAmount: "86400", + withdrawnAmount: "0", + startTime: 1700000000, + endTime: 1700000000 + 8640, + lastUpdateTime: 1700000000, + isActive: true, + isPaused: false, + }, + }); + + const eventData = { + streamId, + eventType: "CREATED", + transactionHash: txHash, + ledgerSequence: 12345, + timestamp: 1700000000, + }; + + await testPrisma.streamEvent.create({ data: eventData }); + + await expect( + testPrisma.streamEvent.create({ + data: { + ...eventData, + ledgerSequence: 12346, + timestamp: 1700000001, + }, + }), + ).rejects.toMatchObject({ code: "P2002" }); + + const count = await testPrisma.streamEvent.count({ + where: { transactionHash: txHash, eventType: "CREATED" }, + }); + expect(count).toBe(1); + }); + + it("dedupes worker replay of the same event without creating a second row", async () => { + const streamId = 12; + const event = createStreamCreatedEvent(streamId); + + await worker.processEvent(event); + await worker.processEvent(event); + + const count = await testPrisma.streamEvent.count({ + where: { + transactionHash: event.txHash, + eventType: "CREATED", + }, + }); + expect(count).toBe(1); + }); + }); + describe("SSE client receives broadcast for each stream event", () => { let eventSource: EventSource; diff --git a/backend/tests/stream.repository.test.ts b/backend/tests/stream.repository.test.ts index a6297c02..86996616 100644 --- a/backend/tests/stream.repository.test.ts +++ b/backend/tests/stream.repository.test.ts @@ -23,6 +23,14 @@ describe('Stream Repository', () => { }); }); + it('should update isActive to false for COMPLETED', async () => { + await updateStatus(123, 'COMPLETED'); + expect(prisma.stream.update).toHaveBeenCalledWith({ + where: { streamId: 123 }, + data: { isActive: false }, + }); + }); + it('should update isActive to true for ACTIVE', async () => { await updateStatus(123, 'ACTIVE'); expect(prisma.stream.update).toHaveBeenCalledWith({ From 9dac2e310d2f0dd56a5dcde771bf496104055c96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Ccaneryy=E2=80=9D?= Date: Mon, 29 Jun 2026 21:10:16 +0300 Subject: [PATCH 2/2] test(stream): use unique txHash and assert replay resolves Co-authored-by: Cursor --- backend/tests/integration/stream-lifecycle.test.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/backend/tests/integration/stream-lifecycle.test.ts b/backend/tests/integration/stream-lifecycle.test.ts index 116524d8..9bde6ec9 100644 --- a/backend/tests/integration/stream-lifecycle.test.ts +++ b/backend/tests/integration/stream-lifecycle.test.ts @@ -607,10 +607,11 @@ describe("Stream Lifecycle Integration Tests", () => { it("dedupes worker replay of the same event without creating a second row", async () => { const streamId = 12; - const event = createStreamCreatedEvent(streamId); + const txHash = "worker-replay-dedup-tx-hash"; + const event = { ...createStreamCreatedEvent(streamId), txHash }; await worker.processEvent(event); - await worker.processEvent(event); + await expect(worker.processEvent(event)).resolves.toBeUndefined(); const count = await testPrisma.streamEvent.count({ where: {