import { describe, it, expect, beforeAll, afterAll } from 'vitest'; import { buildApp } from '@/app'; import { prismaClient } from '@/infrastructure/database'; import { FastifyInstance } from 'fastify'; import { encryptCredential, generateCredentialSecret, issueIntegrationToken, } from '@/modules/catalog/products'; import { ticketsRepository } from '@/modules/ticketing/tickets'; /** * specs/016-load-concurrency-testing User Story 4 / FR-004 / SC-004: proves โ€” rather than * assumes โ€” that 003-ticketing's own optimistic-concurrency guarantee * (TicketsRepository.updateStatus's atomic `updateMany({where:{id, version: expectedVersion}})`) * actually holds under genuinely concurrent requests, not just the sequential checks that * existed before this feature. research.md ยง4: no implementation change is expected here โ€” this * is a real Postgres, real concurrency proof of an already-sound mechanism. */ describe('Ticket status optimistic concurrency (User Story 4)', () => { let app: FastifyInstance; const externalProductId = `TEST_TICKET_STATUS_RACE_PROD_${Date.now()}`; let productId: string; let secret: string; const createdTicketIds: string[] = []; async function createTicket(): Promise { const token = issueIntegrationToken(secret, { externalProductId, tenantId: 'tenant-1', userId: 'user-1', }); const created = await app.inject({ method: 'POST', url: '/v1/support/requests', headers: { authorization: `Bearer ${token}` }, payload: { productId: externalProductId, tenantId: 'tenant-1', userId: 'user-1', source: 'test', problem: `Ticket status race test ${Date.now()}-${Math.random()}`, }, }); expect(created.statusCode).toBe(202); const ticketId = created.json().data.ticketId as string; createdTicketIds.push(ticketId); return ticketId; } beforeAll(async () => { app = await buildApp(); const product = await prismaClient.product.create({ data: { externalProductId, name: 'Ticket Status Race Test Product', status: 'active' }, }); productId = product.id; secret = generateCredentialSecret(); await prismaClient.productIntegration.create({ data: { productId, credentialRef: encryptCredential(secret), authMechanism: 'signed_token', allowedScope: { tenantIds: ['tenant-1'] }, status: 'active', rateLimitPerMinute: 1000, rateLimitPerUserPerMinute: 1000, }, }); }); afterAll(async () => { await prismaClient.ticketMessage.deleteMany({ where: { ticketId: { in: createdTicketIds } } }); await prismaClient.ticket.deleteMany({ where: { id: { in: createdTicketIds } } }); await prismaClient.problem.deleteMany({ where: { productId } }); await prismaClient.productIntegration.deleteMany({ where: { productId } }); await prismaClient.product.deleteMany({ where: { id: productId } }); await app.close(); }); it('exactly one of 20 concurrent status updates from the same version succeeds', async () => { const ticketId = await createTicket(); const original = await prismaClient.ticket.findUniqueOrThrow({ where: { id: ticketId } }); expect(original.status).toBe('NEW'); const attempts = 20; const results = await Promise.all( Array.from({ length: attempts }, () => ticketsRepository.updateStatus(ticketId, 'AI_ANALYZING', original.version), ), ); const successes = results.filter((r) => r !== null); const failures = results.filter((r) => r === null); expect(successes.length).toBe(1); expect(failures.length).toBe(attempts - 1); const finalTicket = await prismaClient.ticket.findUniqueOrThrow({ where: { id: ticketId } }); expect(finalTicket.status).toBe('AI_ANALYZING'); expect(finalTicket.version).toBe(original.version + 1); }); it( 'holds consistently across 10 repeated runs (SC-004)', async () => { for (let run = 0; run < 10; run++) { const ticketId = await createTicket(); const original = await prismaClient.ticket.findUniqueOrThrow({ where: { id: ticketId } }); const results = await Promise.all( Array.from({ length: 20 }, () => ticketsRepository.updateStatus(ticketId, 'AI_ANALYZING', original.version), ), ); expect(results.filter((r) => r !== null).length).toBe(1); } }, 60000, ); });