Recover presence connections after temporary database failures
This commit is contained in:
+32
-2
@@ -4,12 +4,13 @@ import { createServer } from 'node:http';
|
||||
import { Server } from 'socket.io';
|
||||
import { io as client, type Socket } from 'socket.io-client';
|
||||
import { registerPresence } from '../src/server/presence.js';
|
||||
import type { GameSessionStore } from '../src/server/game-session-store.js';
|
||||
import { ApiError, type GameSessionStore } from '../src/server/game-session-store.js';
|
||||
import { PRESENCE_AUTH_REFRESH_MS } from '../constants/presence.js';
|
||||
|
||||
test('presence counts authenticated players once across tabs and removes disconnected players', async () => {
|
||||
const http = createServer(), io = new Server(http);
|
||||
registerPresence(io, { async get(auth: { token: string; gameSessionId: string }) {
|
||||
if (auth.token !== 'valid') throw new Error('INVALID_SESSION');
|
||||
if (auth.token !== 'valid') throw new ApiError(401, 'INVALID_SESSION');
|
||||
return { playerId: auth.gameSessionId.startsWith('a') ? 'a' : 'b' };
|
||||
} } as unknown as GameSessionStore);
|
||||
await new Promise<void>(resolve => http.listen(0, '127.0.0.1', resolve));
|
||||
@@ -33,3 +34,32 @@ test('presence counts authenticated players once across tabs and removes disconn
|
||||
const lastA = next(secondTab); a.disconnect(); b.disconnect(); assert.equal(await lastA, 1);
|
||||
} finally { for (const socket of sockets) socket.disconnect(); await new Promise<void>(resolve => io.close(() => resolve())); }
|
||||
});
|
||||
|
||||
test('temporary revalidation errors allow reconnect, invalid sessions remain disconnected', async t => {
|
||||
let revalidate!: () => void;
|
||||
const interval = globalThis.setInterval;
|
||||
t.mock.method(globalThis, 'setInterval', ((fn: () => void, ms: number) => {
|
||||
if (ms !== PRESENCE_AUTH_REFRESH_MS) return interval(fn, ms);
|
||||
revalidate = fn;
|
||||
return { unref() {} };
|
||||
}) as typeof setInterval);
|
||||
let failure: 'temporary' | 'invalid' | undefined;
|
||||
const http = createServer(), io = new Server(http);
|
||||
registerPresence(io, { async get() {
|
||||
if (failure === 'invalid') throw new ApiError(401, 'INVALID_SESSION');
|
||||
if (failure === 'temporary') { failure = undefined; throw new Error('DB_UNAVAILABLE'); }
|
||||
return { playerId: 'one' };
|
||||
} } as unknown as GameSessionStore);
|
||||
await new Promise<void>(resolve => http.listen(0, '127.0.0.1', resolve));
|
||||
const socket = client(`http://127.0.0.1:${(http.address() as { port: number }).port}/presence`, { autoConnect: false, reconnectionDelay: 10 });
|
||||
const connected = () => new Promise<void>(resolve => socket.once('connect', () => resolve()));
|
||||
try {
|
||||
const first = connected(); socket.connect(); await first;
|
||||
const next = connected(); failure = 'temporary'; revalidate(); await next;
|
||||
assert.equal(socket.connected, true);
|
||||
const disconnected = new Promise<string>(resolve => socket.once('disconnect', resolve));
|
||||
failure = 'invalid'; revalidate();
|
||||
assert.equal(await disconnected, 'io server disconnect');
|
||||
assert.equal(socket.active, false);
|
||||
} finally { socket.disconnect(); await new Promise<void>(resolve => io.close(() => resolve())); }
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user