import { test } from 'node:test'; import assert from 'node:assert/strict'; import { randomUUID } from 'node:crypto'; import { MongoClient } from 'mongodb'; import { createRoomStore } from '../src/server/rooms.js'; import { WAITING_ROOM_TTL_MS } from '../constants/session.js'; test('DB rooms atomically reserve the last seat, expire before TTL deletion and rematch once', { skip: !process.env.TEST_MONGODB_URI }, async () => { const client = await new MongoClient(process.env.TEST_MONGODB_URI!, { serverSelectionTimeoutMS: 5000 }).connect(); const db = client.db(`dragon_ball_test_rooms_${randomUUID().replaceAll('-', '')}`); try { let now = Date.now(); const rooms = await createRoomStore(db, () => now); const request = randomUUID(); const room = await rooms.create('host', request); assert.deepEqual(await rooms.create('host', request), room); await assert.rejects(rooms.join('host', room.code), /SELF_JOIN/); const entries = await Promise.allSettled(['guestA', 'guestB'].map(id => rooms.join(id, room.code))); assert.equal(entries.filter(r => r.status === 'fulfilled').length, 1); const guest = entries[0].status === 'fulfilled' ? 'guestA' : 'guestB'; const paired = await rooms.get(room.id, 'host'); assert.equal(paired.count, 2); assert.equal((await rooms.join(guest, room.code)).currentMatchId, paired.currentMatchId); await assert.rejects(rooms.get(room.id, 'stranger'), /ROOM_NOT_FOUND/); const next = await Promise.all([rooms.rematch(room.id, 'host', 1), rooms.rematch(room.id, guest, 1), rooms.rematch(room.id, guest, 1)]); const current = await rooms.get(room.id, 'host'); assert.equal(current.round, 2); assert.notEqual(current.currentMatchId, room.currentMatchId); for (const r of next.filter(r => r.round === 2)) assert.equal(r.currentMatchId, current.currentMatchId); assert.equal((await rooms.rematch(room.id, 'host', 1)).currentMatchId, current.currentMatchId); await rooms.leave(room.id, guest); assert.equal((await rooms.get(room.id, 'host')).status, 'closed'); const waiting = await rooms.create('host', randomUUID()); now += WAITING_ROOM_TTL_MS; assert.ok(await db.collection('rooms').findOne({ _id: waiting.id })); await assert.rejects(rooms.join('new', waiting.code), /ROOM_EXPIRED/); const fresh = await rooms.create('host', randomUUID()); assert.notEqual(fresh.id, waiting.id); } finally { try { await db.dropDatabase(); } finally { await client.close(); } } }); test('one session cannot occupy two open rooms even with concurrent creates', { skip: !process.env.TEST_MONGODB_URI }, async () => { const client = await new MongoClient(process.env.TEST_MONGODB_URI!, { serverSelectionTimeoutMS: 5000 }).connect(); const db = client.db(`dragon_ball_test_roomrace_${randomUUID().replaceAll('-', '')}`); try { const rooms = await createRoomStore(db); const results = await Promise.allSettled([rooms.create('host', randomUUID()), rooms.create('host', randomUUID())]); assert.equal(results.filter(r => r.status === 'fulfilled').length, 1); } finally { try { await db.dropDatabase(); } finally { await client.close(); } } });