Show provisioning status during server creation

This commit is contained in:
2026-09-19 22:53:24 -04:00
parent 5985959882
commit 44b6415821
12 changed files with 72 additions and 12 deletions
+28
View File
@@ -30,6 +30,34 @@ async function setup() {
}
describe('database fleet and container readiness', () => {
it.each(['queued', 'running', 'awaiting-health'])('shows provisioning during %s creation and resumes health reporting afterward', async (state) => {
const { db, inspect, rcon, fanoutStatus } = await setup();
const { GET } = await import('../../src/routes/api/servers/+server.js');
const { subscribe } = await import('../../src/lib/server/pipeline/bus.js');
db.prepare(`INSERT INTO server_deployments (id, server, action, state, stage, started_at, triggered_by)
VALUES ('creation', 'managed', 'create', ?, 'Creating', ?, 'test')`).run(state, new Date().toISOString());
const snapshot = async () => (await (await GET()).json()).servers[0];
expect(await snapshot()).toMatchObject({ health: 'provisioning', last_error: null, last_players: null });
const events: unknown[] = [];
const unsubscribe = subscribe(event => events.push(event));
try { await fanoutStatus(); } finally { unsubscribe(); }
expect(inspect).not.toHaveBeenCalled();
expect(rcon).not.toHaveBeenCalled();
expect(events).toContainEqual(expect.objectContaining({ type: 'server-status', entries: [expect.objectContaining({
health: 'provisioning', lastError: null, reason: null, replySnippet: null
})] }));
db.prepare("UPDATE server_deployments SET state = 'failed' WHERE id = 'creation'").run();
inspect.mockResolvedValue({ ok: true, state: 'running' });
rcon.mockResolvedValue({ ok: false, endpoint: null, reason: 'timeout', detail: 'no reply' });
await fanoutStatus();
expect(await snapshot()).toMatchObject({ health: 'offline', last_error: 'timeout:no reply' });
db.prepare("UPDATE server_deployments SET state = 'done' WHERE id = 'creation'").run();
rcon.mockResolvedValue({ ok: true, endpoint: { host: 'localhost', port: 28960 }, rawReply: 'status',
status: { players: 0, map: 'zombie_theater', gametype: 'zom', roster: [] } });
await fanoutStatus();
expect(await snapshot()).toMatchObject({ health: 'online', last_error: null });
});
it('keeps game_end through occupied polls until game_start or an empty lobby', async () => {
const { inspect, rcon, fanoutStatus, getServer } = await setup();
inspect.mockResolvedValue({ ok: true, state: 'running' });