Show match demand in metrics (Refs #138)
CI / checks (push) Successful in 4m44s

This commit is contained in:
2026-10-10 16:26:32 -04:00
parent ea932ec563
commit 616b1937ed
15 changed files with 775 additions and 42 deletions
+64
View File
@@ -35,6 +35,70 @@ it('runs reports off the request thread and invalidates cached history after wri
expect(changed.summary.playerHours).toBeCloseTo((await first).summary.playerHours * 3);
});
it('refreshes cached match metrics after active matches and recorded participants change without new samples', async () => {
const { db } = await import('../../src/lib/server/db/index.js');
const { readMetrics } = await import('../../src/lib/server/fleet/metrics.js');
const { metricsReport } = await import('../../src/lib/server/reports/index.js');
const now = Date.UTC(2026, 9, 4, 12);
vi.spyOn(Date, 'now').mockReturnValue(now);
const at = new Date(now - 30_000).toISOString();
const query = parseMetricsQuery(new URLSearchParams('days=1'));
const report = async () => {
const result = await metricsReport(query);
expect(result).toEqual(readMetrics(query, now));
return result;
};
expect((await report()).matches.started).toBe(0);
const match = db().prepare(`INSERT INTO leaderboard_matches
(id, server, game, map, map_key, map_name, started_at, last_received_at,
status, last_event, last_fingerprint)
VALUES (?, 'removed-server', 't5', 'zombie_moon', 't5:moon', 'Moon', ?, ?, 'active', 'game_start', 'test')`);
match.run(1, at, at);
expect((await report()).matches).toEqual({
started: 1,
withRecordedPlayers: 0,
averageGroupSize: null,
solo: 0,
soloShare: null
});
const player = db().prepare(`INSERT INTO leaderboard_match_players
(match_id, guid, first_seen_at, last_seen_at) VALUES (1, ?, ?, ?)`);
player.run('one', at, at);
expect((await report()).matches).toMatchObject({ averageGroupSize: 1, soloShare: 100 });
player.run('two', at, at);
expect((await report()).matches).toMatchObject({ averageGroupSize: 2, soloShare: 0 });
match.run(2, at, at);
expect((await report()).matches).toMatchObject({ started: 2, withRecordedPlayers: 1 });
db().prepare("UPDATE leaderboard_match_players SET match_id=2 WHERE guid='two'").run();
expect((await report()).matches).toMatchObject({
withRecordedPlayers: 2,
averageGroupSize: 1,
solo: 2,
soloShare: 100
});
db().prepare("DELETE FROM leaderboard_match_players WHERE guid='one'").run();
expect((await report()).matches).toMatchObject({ withRecordedPlayers: 1, solo: 1 });
db().prepare('DELETE FROM leaderboard_matches WHERE id=2').run();
expect((await report()).matches).toMatchObject({
started: 1,
withRecordedPlayers: 0,
averageGroupSize: null
});
db().prepare("UPDATE leaderboard_matches SET map_name='Town Survival', game='t6'").run();
expect((await report()).maps.map((map) => [map.game, map.map])).toEqual([
['t6', 'Town Survival']
]);
db()
.prepare('UPDATE leaderboard_matches SET started_at=?')
.run(new Date(now - 2 * 86400_000).toISOString());
const outsideWindow = await report();
expect(outsideWindow.matches.started).toBe(0);
expect(outsideWindow.maps).toEqual([]);
expect(outsideWindow.scopeOptions.maps).toEqual([{ game: 't6', map: 'Town Survival' }]);
db().prepare('DELETE FROM leaderboard_matches').run();
expect((await report()).scopeOptions).toEqual({ games: [], maps: [] });
});
it('refreshes policy signals after policy edits and global pauses without new samples', async () => {
const { db } = await import('../../src/lib/server/db/index.js');
const { recordMetrics } = await import('../../src/lib/server/fleet/metrics.js');