Fix fleet stale-status flicker during polling
This commit is contained in:
@@ -30,14 +30,14 @@ describe('Fleet discovery and match freshness', () => {
|
||||
expect(fleetIdentity({ ...server, game_mode: 'mp' }).launch).toBeNull();
|
||||
});
|
||||
it('does not classify stale, missing, or starting occupancy as an empty lobby', () => {
|
||||
for (const change of [{ last_seen_at: iso(-31_000) }, { last_players: null }, { health: 'starting' as const }, { health: 'offline' as const }]) {
|
||||
for (const change of [{ last_seen_at: iso(-46_000) }, { last_players: null }, { health: 'starting' as const }, { health: 'offline' as const }]) {
|
||||
expect(matchesFleet({ ...server, last_players: 0, ...change }, '', 'empty', '', [], [], now)).toBe(false);
|
||||
}
|
||||
expect(matchesFleet({ ...server, last_players: 0 }, '', 'empty', '', [], [], now)).toBe(true);
|
||||
expect(matchesFleet(server, '', 'occupied', 't5', [], [], now)).toBe(false);
|
||||
});
|
||||
it('includes stale health and failed operations in attention without flagging normal startup', () => {
|
||||
expect(matchesFleet({ ...server, last_seen_at: iso(-31_000) }, '', 'attention', '', [], [], now)).toBe(true);
|
||||
expect(matchesFleet({ ...server, last_seen_at: iso(-46_000) }, '', 'attention', '', [], [], now)).toBe(true);
|
||||
expect(matchesFleet(server, '', 'attention', '', [], [{ ...operation, state: 'attention' }], now)).toBe(true);
|
||||
expect(matchesFleet({ ...server, health: 'starting' }, '', 'attention', '', [], [], now)).toBe(false);
|
||||
});
|
||||
@@ -59,7 +59,7 @@ describe('one-shot lobby watches', () => {
|
||||
expect(watchSatisfied(watch, { ...server, last_players: 0 }, [], now)).toBe(true);
|
||||
expect(watchSatisfied(watch, undefined, [], now)).toBe(false);
|
||||
expect(watchSatisfied(watch, { ...server, last_players: null }, [], now)).toBe(false);
|
||||
expect(watchSatisfied(watch, { ...server, last_players: 0, last_seen_at: iso(-31_000) }, [], now)).toBe(false);
|
||||
expect(watchSatisfied(watch, { ...server, last_players: 0, last_seen_at: iso(-46_000) }, [], now)).toBe(false);
|
||||
});
|
||||
it('only completes the watched operation on explicit success', () => {
|
||||
const watch = { id: 'op', server: server.name, kind: 'operation' as const, operationKey: operation.key, href: '/' };
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
import { afterEach, expect, it, vi } from 'vitest';
|
||||
import { freshStatusTimestamp, STATUS_REFRESH_MS } from '../../src/lib/server-freshness.js';
|
||||
import { classifyHealth } from '../../src/lib/server/fleet/health.js';
|
||||
import { freshServer, type FleetServer } from '../../src/lib/fleet-overview.js';
|
||||
|
||||
afterEach(() => vi.useRealTimers());
|
||||
|
||||
it('keeps healthy reports online across polling and delivery delays, then expires them', () => {
|
||||
vi.useFakeTimers();
|
||||
const reportAt = Date.parse('2026-09-18T12:00:00Z');
|
||||
const timestamp = new Date(reportAt).toISOString();
|
||||
for (const elapsed of [-999, 0, STATUS_REFRESH_MS, STATUS_REFRESH_MS + 4000, 45_000, 45_001]) {
|
||||
const now = reportAt + elapsed;
|
||||
vi.setSystemTime(now);
|
||||
const expected = elapsed <= 45_000;
|
||||
const health = classifyHealth(timestamp, null, 'running');
|
||||
expect(health).toBe(expected ? 'online' : 'stale');
|
||||
expect(freshServer({ health, last_seen_at: timestamp, last_error: null } as FleetServer, now)).toBe(expected);
|
||||
}
|
||||
vi.setSystemTime(reportAt + 120_001);
|
||||
expect(classifyHealth(timestamp, null, 'running')).toBe('offline');
|
||||
});
|
||||
|
||||
it('does not hide failures or accept missing, invalid, or far-future timestamps', () => {
|
||||
vi.useFakeTimers();
|
||||
const now = Date.parse('2026-09-18T12:00:00Z');
|
||||
vi.setSystemTime(now);
|
||||
const timestamp = new Date(now).toISOString();
|
||||
expect(classifyHealth(timestamp, 'timeout', 'running')).toBe('stale');
|
||||
expect(classifyHealth(timestamp, null, 'stopped')).toBe('offline');
|
||||
expect(classifyHealth(timestamp, null, 'restarting')).toBe('starting');
|
||||
expect(freshServer({ health: 'online', last_seen_at: timestamp, last_error: 'timeout' } as FleetServer, now)).toBe(false);
|
||||
for (const invalid of [null, 'invalid', new Date(now + 1001).toISOString()]) {
|
||||
expect(freshStatusTimestamp(invalid, now)).toBe(false);
|
||||
expect(classifyHealth(invalid, null, 'running')).toBe('offline');
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user