Fix active and match timer drift between status polls
Persist occupancy transitions with telemetry and carry timer anchors through live updates. Cover delayed polling, lobby rejoining, and lifecycle boundaries with regression tests. Fixes #47
This commit is contained in:
@@ -13,6 +13,30 @@ afterEach(async () => fixture.cleanup());
|
||||
|
||||
const payload = gameEvent('round_change', 17);
|
||||
|
||||
it('does not let a request received before a lifecycle submission restore cleared timers', async () => {
|
||||
const { db } = await import('../../src/lib/server/db/index.js');
|
||||
const { saveTelemetry } = await import('../../src/lib/server/fleet/telemetry.js');
|
||||
const { getServer } = await import('../../src/lib/server/fleet/servers.js');
|
||||
const at = (seconds: number) => new Date(Date.parse('2026-09-20T12:00:00Z') + seconds * 1000).toISOString();
|
||||
db().prepare('INSERT INTO restart_rollout (server, requested_at) VALUES (?, ?)').run(payload.server, at(10));
|
||||
for (const seconds of [9, 10]) {
|
||||
saveTelemetry({ ...gameEvent('game_start'), receivedAt: at(seconds) });
|
||||
expect(getServer(payload.server)).toMatchObject({ active_since: null, game_started_at: null });
|
||||
}
|
||||
const current = saveTelemetry({ ...gameEvent('heartbeat', 2), receivedAt: at(11) });
|
||||
expect(current.timing?.server).toEqual({ activeSince: at(11), inactiveSince: null, gameStartedAt: null, gameEndedAt: null });
|
||||
});
|
||||
|
||||
it('generates timer anchors on the server instead of accepting client-supplied timing', async () => {
|
||||
const response = await post({ ...gameEvent('game_start'), receivedAt: '2000-01-01T00:00:00Z',
|
||||
timing: { server: { activeSince: '2000-01-01T00:00:00Z' } } });
|
||||
const { telemetry } = await response.json();
|
||||
expect(response.status).toBe(200);
|
||||
expect(telemetry.receivedAt).not.toBe('2000-01-01T00:00:00Z');
|
||||
expect(telemetry.timing.server).toEqual({ activeSince: telemetry.receivedAt, inactiveSince: null,
|
||||
gameStartedAt: telemetry.receivedAt, gameEndedAt: null });
|
||||
});
|
||||
|
||||
it('persists player timing across matches and resets after absence or a telemetry gap', async () => {
|
||||
const { saveTelemetry, listTelemetry } = await import('../../src/lib/server/fleet/telemetry.js');
|
||||
const { closeDb } = await import('../../src/lib/server/db/index.js');
|
||||
|
||||
Reference in New Issue
Block a user