This commit is contained in:
@@ -608,7 +608,7 @@ describe('database fleet and container readiness', () => {
|
||||
}
|
||||
);
|
||||
|
||||
it('keeps game_end through occupied polls until game_start or an empty lobby', async () => {
|
||||
it('keeps game_end through RCON polls and recovers when telemetry observes a new match', async () => {
|
||||
const { inspect, rcon, fanoutStatus, getServer } = await setup();
|
||||
inspect.mockResolvedValue({ ok: true, state: 'running' });
|
||||
const reply = (players: number) => ({
|
||||
@@ -621,9 +621,11 @@ describe('database fleet and container readiness', () => {
|
||||
await postTelemetry(gameEvent('game_end', 10, 1, 'managed'));
|
||||
const ended = getServer('managed')?.game_ended_at;
|
||||
expect(ended).toEqual(expect.any(String));
|
||||
await postTelemetry(gameEvent('heartbeat', 10, 1, 'managed'));
|
||||
await fanoutStatus();
|
||||
expect(getServer('managed')?.game_ended_at).toBe(ended);
|
||||
await postTelemetry(gameEvent('heartbeat', 1, 1, 'managed'));
|
||||
await fanoutStatus();
|
||||
expect(getServer('managed')).toMatchObject({ game_started_at: null, game_ended_at: null });
|
||||
await postTelemetry(gameEvent('game_start', 0, 1, 'managed'));
|
||||
expect(getServer('managed')?.game_ended_at).toBeNull();
|
||||
await postTelemetry(gameEvent('game_end', 10, 1, 'managed'));
|
||||
@@ -638,6 +640,54 @@ describe('database fleet and container readiness', () => {
|
||||
expect(getServer('managed')?.game_ended_at).toBeNull();
|
||||
});
|
||||
|
||||
it.each([0, 1])(
|
||||
'preserves a match starting with %i players through empty reports, polls, a gap, and reload',
|
||||
async (startPlayers) => {
|
||||
const { inspect, rcon, fanoutStatus, getServer } = await setup();
|
||||
const { GET } = await import('../../src/routes/api/servers/+server.js');
|
||||
const { currentRound } = await import('../../src/lib/fleet-overview.js');
|
||||
const { closeDb } = await import('../../src/lib/server/db/index.js');
|
||||
const beginning = Date.parse('2026-10-09T12:00:00Z');
|
||||
const at = (seconds: number) => new Date(beginning + seconds * 1000).toISOString();
|
||||
vi.useFakeTimers({ toFake: ['Date'] });
|
||||
vi.setSystemTime(beginning);
|
||||
inspect.mockResolvedValue({ ok: true, state: 'running' });
|
||||
rcon.mockResolvedValue({
|
||||
ok: true,
|
||||
endpoint: { host: 'localhost', port: 28960 },
|
||||
status: { players: 0, map: 'zombie_theater', gametype: 'zom', roster: [] }
|
||||
});
|
||||
const start = await (
|
||||
await postTelemetry(gameEvent('game_start', 0, startPlayers, 'managed'))
|
||||
).json();
|
||||
expect(start.telemetry.timing.server.gameStartedAt).toBe(at(0));
|
||||
vi.setSystemTime(beginning + 1000);
|
||||
await postTelemetry(gameEvent('round_change', 1, 0, 'managed'));
|
||||
for (const seconds of [30, 121]) {
|
||||
vi.setSystemTime(beginning + seconds * 1000);
|
||||
await fanoutStatus();
|
||||
expect(getServer('managed')).toMatchObject({
|
||||
active_since: null,
|
||||
game_started_at: at(0),
|
||||
game_ended_at: null
|
||||
});
|
||||
}
|
||||
vi.setSystemTime(beginning + 180_000);
|
||||
await postTelemetry(gameEvent('heartbeat', 4, 1, 'managed'));
|
||||
await fanoutStatus();
|
||||
closeDb();
|
||||
const server = (await (await GET()).json()).servers[0];
|
||||
expect(server).toMatchObject({
|
||||
health: 'online',
|
||||
last_players: 1,
|
||||
active_since: at(180),
|
||||
game_started_at: at(0),
|
||||
game_ended_at: null
|
||||
});
|
||||
expect(currentRound(server, server.telemetry, Date.now())).toBe(4);
|
||||
}
|
||||
);
|
||||
|
||||
it('keeps the first occupied report as the active timer when more telemetry arrives before polling', async () => {
|
||||
const { inspect, rcon, fanoutStatus, getServer } = await setup();
|
||||
const { GET } = await import('../../src/routes/api/servers/+server.js');
|
||||
|
||||
Reference in New Issue
Block a user