Files

43 lines
3.1 KiB
TypeScript

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<any>('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(); } }
});