Store cumulative player scores alongside balances
CI / checks (push) Successful in 6m27s

This commit is contained in:
2026-10-12 13:57:34 -04:00
parent 76325b99ad
commit 6059ebf2a5
12 changed files with 181 additions and 5 deletions
+53
View File
@@ -18,6 +18,59 @@ afterEach(async () => fixture.cleanup());
const payload = gameEvent('round_change', 17);
it.each(['round_change', 'heartbeat', 'game_end'] as const)(
'accepts and stores score_total separately from the balance for %s',
async (event) => {
const body = gameEvent(event, 17, 1);
const response = await post({
...body,
players: [{ ...body.players[0], score: 28000, score_total: 63000 }]
});
expect(response.status).toBe(200);
expect((await response.json()).telemetry.players[0]).toMatchObject({
score: 28000,
score_total: 63000
});
const { listTelemetry } = await import('../../src/lib/server/fleet/telemetry.js');
expect(listTelemetry()[0].players[0]).toMatchObject({ score: 28000, score_total: 63000 });
const { db } = await import('../../src/lib/server/db/index.js');
expect(
db().prepare('SELECT best_score, score_total FROM leaderboard_match_players').get()
).toEqual({ best_score: 28000, score_total: 63000 });
}
);
it.each([0, Number.MAX_SAFE_INTEGER])(
'accepts cumulative score boundary %s',
async (score_total) => {
const { parseGameEvent } = await import('../../src/lib/telemetry.js');
expect(
parseGameEvent({ ...payload, players: [{ ...roster(1)[0], score_total }] }).players[0]
).toMatchObject({ score_total });
}
);
it.each([null, -1, 1.5, '63000', true, Number.MAX_SAFE_INTEGER + 1])(
'rejects invalid score_total without saving it: %j',
async (score_total) => {
expect(
(await post({ ...payload, players: [{ ...roster(1)[0], score_total }] })).status
).toBe(400);
const { listTelemetry } = await import('../../src/lib/server/fleet/telemetry.js');
expect(listTelemetry()).toEqual([]);
}
);
it('accepts older reporters without fabricating a cumulative score', async () => {
const response = await post(gameEvent('game_end', 17, 1));
expect(response.status).toBe(200);
expect((await response.json()).telemetry.players[0]).not.toHaveProperty('score_total');
const { db } = await import('../../src/lib/server/db/index.js');
expect(db().prepare('SELECT score_total FROM leaderboard_match_players').get()).toEqual({
score_total: null
});
});
it.each(['game_start', 'round_change', 'heartbeat', 'game_end'] as const)(
'preserves optional reporter identity and sequence for %s',
async (event) => {