Relax freshness limits and tolerate transient RCON failures

This commit is contained in:
2026-10-05 16:36:23 -04:00
parent d8b972cfc3
commit b1b3e8b958
28 changed files with 221 additions and 58 deletions
+22 -4
View File
@@ -287,7 +287,7 @@ describe('Fleet report clock', () => {
expect(get(fleetServers)[0]).toMatchObject({ health: 'online', last_players: 3, status_source: 'telemetry' });
expect(get(fleetServers)[0].roster).toHaveLength(3);
expect(matchesFleet(get(fleetServers)[0], 'Player 3', 'occupied', '', [], [], get(uiNow))).toBe(true);
await vi.advanceTimersByTimeAsync(46_000);
await vi.advanceTimersByTimeAsync(91_000);
expect(freshServer(get(fleetServers)[0], get(uiNow))).toBe(false);
expect(matchesFleet(get(fleetServers)[0], '', 'occupied', '', [], [], get(uiNow))).toBe(false);
});
@@ -368,15 +368,33 @@ describe('Fleet report clock', () => {
it('keeps advancing through wall-clock changes and expires a report if updates stop', async () => {
const { fleetServers, uiNow } = await setup();
vi.setSystemTime(epoch - 120_000);
await vi.advanceTimersByTimeAsync(45_000);
expect(get(uiNow)).toBe(epoch + 45_000);
await vi.advanceTimersByTimeAsync(90_000);
expect(get(uiNow)).toBe(epoch + 90_000);
expect(freshServer(get(fleetServers)[0], get(uiNow))).toBe(true);
await vi.advanceTimersByTimeAsync(1000);
expect(get(uiNow)).toBe(epoch + 46_000);
expect(get(uiNow)).toBe(epoch + 91_000);
expect(freshServer(get(fleetServers)[0], get(uiNow))).toBe(false);
expect(matchesFleet(get(fleetServers)[0], '', 'attention', '', [], [], get(uiNow))).toBe(true);
});
it('applies the same RCON failure grace to HTTP snapshots and live updates', async () => {
const raw = { ...server(), last_error: 'timeout:no reply', rcon_failures: 1 };
snapshot.servers = [server(epoch, { rcon_status: raw })];
const { fleetServers, uiNow } = await setup();
expect(freshServer(get(fleetServers)[0], get(uiNow))).toBe(true);
expect(get(fleetServers)[0].rcon_status?.last_error).toBe('timeout:no reply');
await vi.advanceTimersByTimeAsync(30_000);
emit(epoch + 30_000, [status(epoch, { health: 'stale', lastError: 'timeout:no reply',
rconStatus: { ...raw, rcon_failures: 2 } })]);
expect(get(fleetServers)[0].health).toBe('stale');
expect(freshServer(get(fleetServers)[0], get(uiNow))).toBe(false);
await vi.advanceTimersByTimeAsync(30_000);
emit(epoch + 60_000, [status(epoch + 60_000, {
rconStatus: { ...raw, last_seen_at: new Date(epoch + 60_000).toISOString(), last_error: null, rcon_failures: 0 }
})]);
expect(freshServer(get(fleetServers)[0], get(uiNow))).toBe(true);
});
it('preserves actual RCON failures and stopped-container health', async () => {
const { fleetServers, uiNow } = await setup();
await vi.advanceTimersByTimeAsync(1000);