Add autoscaling outcomes to Metrics (Refs #140)

This commit is contained in:
2026-10-10 17:51:31 -04:00
parent 0bfda267ec
commit 528ed7f37a
15 changed files with 612 additions and 6 deletions
+54
View File
@@ -3,6 +3,7 @@ import { render } from 'svelte/server';
import type { MetricsData, MapMetrics, MatchMetrics } from '../../src/lib/metrics.js';
import MetricsPage from '../../src/routes/metrics/+page.svelte';
import MetricsSummary from '../../src/lib/ui/components/metrics/MetricsSummary.svelte';
import MetricsAutoscaling from '../../src/lib/ui/components/metrics/MetricsAutoscaling.svelte';
import MetricsTables from '../../src/lib/ui/components/metrics/MetricsTables.svelte';
import MetricsExplore from '../../src/lib/ui/components/metrics/MetricsExplore.svelte';
import MetricsChart from '../../src/lib/ui/components/metrics/MetricsChart.svelte';
@@ -64,6 +65,15 @@ function report(): MetricsData {
scopeFirstSampleAt: now - 14 * 86400000,
scopeLatestSampleAt: now,
matches: matches(),
autoscaling: {
added: 73,
removed: 48,
failed: 1,
cancelled: 2,
readinessSamples: 73,
readinessMeanSeconds: 72,
readinessMaxSeconds: 168
},
summary,
running: { average: 12, peak: 24, capturedHours: 1 },
maps: Array.from({ length: 24 }, (_, i) => map(i + 1)),
@@ -106,6 +116,50 @@ function scope(search: string, stateSearch?: string) {
}
beforeEach(() => scope(''));
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;
for (const label of [
'Lobbies added',
'Lobbies removed',
'Failed operations',
'Cancelled operations'
])
expect(section).toContain(label);
for (const value of [73, 48, 1, 2]) expect(section).toContain(`>${value}<`);
expect(section).toContain('72 s');
expect(section).toContain('168 s');
expect(section).toContain('href="/autoscaling"');
expect(section.replace(/\s+/g, ' ')).toContain('73 completed creates with recorded timing');
data.summary = { observed: 0, active: 0, idle: 0, unknown: 0, playerHours: 0 };
data.latestSampleAt = null;
const body = render(MetricsPage, {
props: { data: { ...data, user: null, setupRequired: false } }
}).body;
expect(body).toContain('No retained observations yet');
expect(body).toContain('Lobbies added');
expect(body).toContain('72 s');
});
it('distinguishes no autoscaling outcomes from unavailable readiness', () => {
const body = render(MetricsAutoscaling, {
props: {
metrics: {
added: 0,
removed: 0,
failed: 0,
cancelled: 0,
readinessSamples: 0,
readinessMeanSeconds: null,
readinessMaxSeconds: null
}
}
}).body.replace(/\s+/g, ' ');
expect(body).toContain('No completed, failed or cancelled autoscaling operations recorded');
expect(body).toContain('Request-to-ready time is unavailable');
expect(body).not.toContain('0 s');
});
it.each([
[0, 'No captured time in this scope'],
[1, 'Waiting for observed time']