Preserve fleet match timing across empty telemetry
CI / checks (push) Successful in 4m46s

This commit is contained in:
2026-10-09 19:41:55 -04:00
parent d1f581d6a8
commit ce6dba17e6
12 changed files with 171 additions and 53 deletions
+39
View File
@@ -18,6 +18,45 @@ afterEach(async () => fixture.cleanup());
const payload = gameEvent('round_change', 17);
it.each(['game_end', 'round reset', 'map change'])(
'drops the previous match timing when game_start is missed after %s',
async (boundary) => {
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-10-09T12:00:00Z') + seconds * 1000).toISOString();
saveTelemetry({ ...gameEvent('game_start', 0, 1), receivedAt: at(0) });
const previous = saveTelemetry({ ...gameEvent('heartbeat', 7, 1), receivedAt: at(30) });
if (boundary === 'game_end') {
const ended = saveTelemetry({ ...gameEvent('game_end', 7, 0), receivedAt: at(31) });
expect(ended.timing?.server?.gameEndedAt).toBe(at(31));
}
const next = saveTelemetry({
...gameEvent('heartbeat', boundary === 'map change' ? 8 : 1, 1),
...(boundary === 'map change' ? { map: 'zombie_moon' } : {}),
receivedAt: at(60)
});
expect(next.timing?.matchId).not.toBe(previous.timing?.matchId);
expect(next.timing?.server).toMatchObject({ gameStartedAt: null, gameEndedAt: null });
expect(getServer(payload.server)).toMatchObject({
game_started_at: null,
game_ended_at: null
});
}
);
it('repairs a previously discarded start from an observed match without inventing one', async () => {
const { saveTelemetry } = await import('../../src/lib/server/fleet/telemetry.js');
const { db } = await import('../../src/lib/server/db/index.js');
const at = (seconds: number) =>
new Date(Date.parse('2026-10-09T12:00:00Z') + seconds * 1000).toISOString();
saveTelemetry({ ...gameEvent('game_start', 0, 0), receivedAt: at(0) });
// Simulate the old ingestion behavior for an empty start.
db().prepare('UPDATE servers SET game_started_at = NULL WHERE name = ?').run(payload.server);
const report = saveTelemetry({ ...gameEvent('heartbeat', 4, 1), receivedAt: at(120) });
expect(report.timing?.server?.gameStartedAt).toBe(at(0));
});
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');