From 86ec39f7d21b8570244da7fa210bcb40be5c131c Mon Sep 17 00:00:00 2001 From: nav Date: Tue, 12 May 2026 12:51:00 +0000 Subject: [PATCH] test(guild): add concurrent message write verification and fix duplicate messageId index --- .../src/entities/message.entity.ts | 1 - .../src/health.integration.spec.ts | 34 +++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/Fabric.Backend.Guild/src/entities/message.entity.ts b/Fabric.Backend.Guild/src/entities/message.entity.ts index 65eaa4a..2695f86 100644 --- a/Fabric.Backend.Guild/src/entities/message.entity.ts +++ b/Fabric.Backend.Guild/src/entities/message.entity.ts @@ -9,7 +9,6 @@ export class Message { @PrimaryGeneratedColumn('uuid') id!: string; - @Index() @Column({ type: 'varchar', length: 80, unique: true }) messageId!: string; diff --git a/Fabric.Backend.Guild/src/health.integration.spec.ts b/Fabric.Backend.Guild/src/health.integration.spec.ts index 5c130b6..149c748 100644 --- a/Fabric.Backend.Guild/src/health.integration.spec.ts +++ b/Fabric.Backend.Guild/src/health.integration.spec.ts @@ -2,6 +2,8 @@ import { INestApplication } from '@nestjs/common'; import { Test } from '@nestjs/testing'; import request from 'supertest'; import { afterAll, beforeAll, describe, expect, it } from 'vitest'; +import { DataSource } from 'typeorm'; +import { Channel } from './entities/channel.entity'; process.env.DB_HOST = '127.0.0.1'; process.env.DB_PORT = '3308'; @@ -13,6 +15,7 @@ process.env.FABRIC_API_KEY = 'test-api-key'; describe('guild integration (mysql + api)', () => { let app: INestApplication; + let dataSource: DataSource; beforeAll(async () => { const { AppModule } = await import('./app.module'); @@ -23,6 +26,9 @@ describe('guild integration (mysql + api)', () => { app = moduleRef.createNestApplication(); app.setGlobalPrefix('api'); await app.init(); + dataSource = app.get(DataSource); + await dataSource.dropDatabase(); + await dataSource.synchronize(); }, 30000); afterAll(async () => { @@ -40,4 +46,32 @@ describe('guild integration (mysql + api)', () => { const res = await request(app.getHttpServer()).get('/api/channels/non-exist/messages'); expect(res.status).toBe(401); }); + + it('supports concurrent message writes with continuous seq', async () => { + const channelRepo = dataSource.getRepository(Channel); + const channel = await channelRepo.save( + channelRepo.create({ + guildId: 'test-guild', + name: `concurrency-${Date.now()}`, + kind: 'text', + isPrivate: false, + lastSeq: 0, + }), + ); + + const concurrent = 10; + const tasks = Array.from({ length: concurrent }, (_, i) => + request(app.getHttpServer()) + .post(`/api/channels/${channel.id}/messages`) + .set('x-api-key', 'test-api-key') + .send({ content: `hello-${i + 1}`, authorUserId: 'u1' }), + ); + + const responses = await Promise.all(tasks); + const seqs = responses.map((r) => r.body.seq).sort((a, b) => a - b); + + expect(responses.every((r) => r.status === 201)).toBe(true); + expect(new Set(seqs).size).toBe(concurrent); + expect(seqs).toEqual(Array.from({ length: concurrent }, (_, i) => i + 1)); + }); });