Show configured metrics retention (Refs #141)

This commit is contained in:
2026-10-10 17:57:02 -04:00
parent 528ed7f37a
commit d6041e40ef
8 changed files with 62 additions and 3 deletions
+12
View File
@@ -12,6 +12,7 @@ const emptyMatches = {
};
const report = (days: number) => ({
days,
metricsKeepDays: 31,
now: 1000,
since: 0,
summary: totals,
@@ -80,6 +81,13 @@ function setup(fetcher: typeof fetch) {
}
describe('metrics background refresh', () => {
it.each([90, 1, 0])('accepts configured retention of %i days', async (metricsKeepDays) => {
const value = { ...report(7), metricsKeepDays };
const refresh = setup(vi.fn().mockResolvedValue(Response.json(value)));
await refresh.refresh();
expect(refresh.onData).toHaveBeenLastCalledWith(value);
});
it.each([
null,
{ ...report(7).autoscaling, added: -1 },
@@ -297,6 +305,10 @@ describe('metrics background refresh', () => {
maps: [{ ...value.maps[0], running: { average: 1, peak: 1, capturedHours: null } }]
},
{ ...value, autoscalingPaused: undefined },
...[undefined, null, '90', -1, 1.5].map((metricsKeepDays) => ({
...value,
metricsKeepDays
})),
{ ...value, running: undefined },
{ ...value, previous: { ...value.previous, running: undefined } },
{ ...value, maps: [{ ...value.maps[0], policy: { id: 'moon' } }] },
+17
View File
@@ -439,6 +439,23 @@ describe('historical metrics', () => {
expect(result.summary.playerHours * 3600).toBeCloseTo(30);
});
it('updates retention in page loads and refreshes without new samples or cache expiry', async () => {
const { fleetSettings, saveFleetSettings } =
await import('../../src/lib/server/settings.js');
const { GET } = await import('../../src/routes/api/metrics/+server.js');
const { load } = await import('../../src/routes/metrics/+page.server.js');
vi.spyOn(Date, 'now').mockReturnValue(Date.UTC(2026, 9, 10, 12));
const url = new URL('http://localhost/metrics?days=7');
const pageData = () => load({ url } as Parameters<typeof load>[0]);
expect(await pageData()).toMatchObject({ metricsKeepDays: 31 });
for (const metricsKeepDays of [90, 0, 1]) {
saveFleetSettings({ ...fleetSettings(), metricsKeepDays });
const payload = await (await GET({ url })).json();
expect(payload.metricsKeepDays).toBe(metricsKeepDays);
expect(payload).toEqual(await pageData());
}
});
it('shares the range parser and response contract between SSR and the uncached refresh endpoint', async () => {
const { recordMetrics } = await import('../../src/lib/server/fleet/metrics.js');
const { GET } = await import('../../src/routes/api/metrics/+server.js');
+20
View File
@@ -54,6 +54,7 @@ function report(): MetricsData {
const summary = { observed: 10, active: 5, idle: 5, unknown: 2, playerHours: 20 };
return {
days: 7,
metricsKeepDays: 31,
since: now - 7 * 86400000,
now,
firstRetainedSampleAt: now - 14 * 86400000,
@@ -116,6 +117,25 @@ function scope(search: string, stateSearch?: string) {
}
beforeEach(() => scope(''));
it.each([
[31, 'for 31 days'],
[90, 'for 90 days'],
[1, 'for 1 day'],
[0, 'indefinitely']
] as const)(
'shows configured occupancy retention of %i days in About this report',
(metricsKeepDays, expected) => {
const body = render(MetricsPage, {
props: { data: { ...report(), metricsKeepDays, user: null, setupRequired: false } }
})
.body.replace(/<!--[\s\S]*?-->/g, '')
.replace(/\s+/g, ' ');
const about = body.slice(body.indexOf('About this report'));
expect(about).toContain(`Occupancy history is retained ${expected};`);
expect(about).toContain('saved match retention is configured separately');
}
);
it('shows Provisioning outcomes and readiness with a policy link, even without occupancy', () => {
const data = report();
const section = render(MetricsAutoscaling, { props: { metrics: data.autoscaling } }).body;