Pace collection startups and clarify deployment queue progress
This commit is contained in:
@@ -34,6 +34,13 @@ beforeEach(async () => {
|
||||
vi.stubEnv('KOMODO_API_SECRET', 'test');
|
||||
vi.stubEnv('KOMODO_TARGET_SERVER', 'test-host');
|
||||
vi.stubEnv('RCON_PASSWORD', 'test-rcon');
|
||||
const { komodoInspectHealthy } = await import('../../src/lib/server/integrations/komodo.js');
|
||||
const { rconStatusResult, rconGetPlayerCount } = await import('../../src/lib/server/integrations/rcon.js');
|
||||
vi.mocked(komodoInspectHealthy).mockReset().mockResolvedValue({ ok: true, state: 'running' });
|
||||
vi.mocked(rconStatusResult).mockReset().mockResolvedValue({ ok: true,
|
||||
endpoint: { host: 'localhost', port: 27016 }, rawReply: '',
|
||||
status: { players: 0, map: 'zombie_cosmodrome', gametype: null, roster: [] } });
|
||||
vi.mocked(rconGetPlayerCount).mockReset().mockResolvedValue(0);
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
@@ -48,7 +55,10 @@ describe('destruction cleanup recovery', () => {
|
||||
const { db } = await import('../../src/lib/server/db/index.js');
|
||||
const { getDeployment } = await import('../../src/lib/server/fleet/deployments.js');
|
||||
const { komodoInspectHealthy } = await import('../../src/lib/server/integrations/komodo.js');
|
||||
vi.mocked(komodoInspectHealthy).mockResolvedValue({ ok: false, reason: 'gone' });
|
||||
const { rconStatusResult } = await import('../../src/lib/server/integrations/rcon.js');
|
||||
vi.mocked(rconStatusResult).mockResolvedValueOnce({ ok: true,
|
||||
endpoint: { host: 'localhost', port: 28960 }, rawReply: '',
|
||||
status: { players: 0, map: 'zm_transit', gametype: null, roster: [] } });
|
||||
const name = 't6_zombie_town_1';
|
||||
expect(await createServer({ ...input, game: 't6', mapSlug: 'town' })).toMatchObject({ ok: true, name });
|
||||
expect(await createServer(input)).toMatchObject({ ok: true });
|
||||
@@ -61,6 +71,7 @@ describe('destruction cleanup recovery', () => {
|
||||
db().prepare("INSERT INTO beta_file_changes (beta_id, server, rel_path) VALUES (?, ?, 'test.gsc')").run(beta, server);
|
||||
}
|
||||
const queued = destroyServer(name);
|
||||
vi.mocked(komodoInspectHealthy).mockResolvedValue({ ok: false, reason: 'gone' });
|
||||
await processDestructions();
|
||||
expect(getDeployment(queued.deploymentId!)?.deployment).toMatchObject({ state: 'done', server_exists: 0 });
|
||||
for (const table of ['beta_test_runs', 'beta_test_coverage', 'beta_file_changes']) {
|
||||
@@ -269,6 +280,12 @@ describe('T6 Zombies provisioning', () => {
|
||||
vi.mocked(rconStatusResult).mockImplementation(async (server) => ({ ok: true, endpoint: { host: 'localhost', port: 28960 }, rawReply: '',
|
||||
status: { players: 0, map: server.startsWith('t6_') ? 'zm_transit' : 'zombie_cosmodrome', gametype: null, roster: [] } }));
|
||||
await processCreations();
|
||||
expect(getDeployment(t5.deploymentId)?.deployment).toMatchObject({ state: 'awaiting-health' });
|
||||
expect(getDeployment(t6.deploymentId)?.deployment).toMatchObject({ state: 'queued' });
|
||||
await processCreations();
|
||||
expect(getDeployment(t5.deploymentId)?.deployment).toMatchObject({ state: 'done' });
|
||||
expect(getDeployment(t6.deploymentId)?.deployment).toMatchObject({ state: 'awaiting-health' });
|
||||
await processCreations();
|
||||
expect(getDeployment(t6.deploymentId)?.deployment).toMatchObject({ state: 'done' });
|
||||
const content = await readFile(join(fixture.t6, t6.name, 'configs/electric_cherry_map.cfg'), 'utf8');
|
||||
expect(content).toContain('execgts zm_standard_town.cfg map zm_transit');
|
||||
@@ -340,10 +357,13 @@ describe('server creation map selection', () => {
|
||||
closeDb();
|
||||
interruptDeployments();
|
||||
expect(getDeployment(body.deploymentId)?.deployment).toMatchObject({ state: 'queued' });
|
||||
vi.mocked(komodoInspectHealthy).mockResolvedValueOnce({ ok: false, reason: 'starting' }).mockResolvedValueOnce({ ok: false, reason: 'starting' });
|
||||
await Promise.all([processCreations(), processCreations()]);
|
||||
expect(komodoCreateDeployment).toHaveBeenCalledTimes(2);
|
||||
expect(komodoCreateDeployment).toHaveBeenCalledTimes(1);
|
||||
expect(getDeployment(body.deploymentId)?.deployment).toMatchObject({ state: 'awaiting-health', finished_at: null });
|
||||
if (second.ok) expect(getDeployment(second.deploymentId)?.deployment).toMatchObject({ state: 'queued' });
|
||||
vi.mocked(komodoInspectHealthy).mockResolvedValueOnce({ ok: false, reason: 'starting' });
|
||||
await processCreations();
|
||||
expect(komodoCreateDeployment).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('completes creation only when Komodo, RCON, and the selected map all pass', async () => {
|
||||
@@ -469,7 +489,8 @@ describe('server creation map selection', () => {
|
||||
expect(listDeployments()).toContainEqual(expect.objectContaining({ state: 'failed', error: 'Deploy: test failure' }));
|
||||
vi.mocked(komodoDeploy).mockRejectedValueOnce(new Error('connection lost'));
|
||||
await expect(createServer(input)).rejects.toThrow('connection lost');
|
||||
expect(listDeployments()).toContainEqual(expect.objectContaining({ state: 'failed', error: 'connection lost' }));
|
||||
expect(listDeployments()).toContainEqual(expect.objectContaining({ state: 'awaiting-health',
|
||||
stage: 'Verifying existing server after interrupted startup', finished_at: null }));
|
||||
const id = beginDeployment('interrupted-server', 'destroy');
|
||||
interruptDeployments();
|
||||
expect(listDeployments()).toContainEqual(expect.objectContaining({ id, state: 'interrupted', finished_at: expect.any(String) }));
|
||||
@@ -587,12 +608,12 @@ describe('persistent server keys', () => {
|
||||
const { createServer, destroyServer, processDestructions } = await import('../../src/lib/server/fleet/create.js');
|
||||
const { getServerKey, listServerKeys } = await import('../../src/lib/server/fleet/server-keys.js');
|
||||
const { komodoCreateDeployment, komodoInspectHealthy } = await import('../../src/lib/server/integrations/komodo.js');
|
||||
vi.mocked(komodoInspectHealthy).mockResolvedValue({ ok: false, kind: 'not-found', message: 'gone' } as never);
|
||||
const name = 't5_zombie_cosmodrome_2';
|
||||
expect(await createServer(input)).toMatchObject({ ok: true, name: serverName });
|
||||
expect(await createServer(input)).toMatchObject({ ok: true, name });
|
||||
expect(getServerKey(name)).toBe('test-key');
|
||||
expect(await destroyServer(name)).toMatchObject({ ok: true });
|
||||
vi.mocked(komodoInspectHealthy).mockResolvedValue({ ok: false, reason: 'gone' });
|
||||
await processDestructions();
|
||||
expect(listServerKeys()).toContainEqual(expect.objectContaining({ server_id: name, deployed: 0 }));
|
||||
expect(JSON.stringify(listServerKeys())).not.toContain('test-key');
|
||||
@@ -621,10 +642,10 @@ describe('persistent server keys', () => {
|
||||
const { createServer, destroyServer, processDestructions } = await import('../../src/lib/server/fleet/create.js');
|
||||
const { getServerKey } = await import('../../src/lib/server/fleet/server-keys.js');
|
||||
const { komodoCreateDeployment, komodoInspectHealthy } = await import('../../src/lib/server/integrations/komodo.js');
|
||||
vi.mocked(komodoInspectHealthy).mockResolvedValue({ ok: false } as never);
|
||||
expect(await createServer(input)).toMatchObject({ ok: true, name: serverName });
|
||||
expect(await createServer(input)).toMatchObject({ ok: true, name: 't5_zombie_cosmodrome_2' });
|
||||
await destroyServer(serverName);
|
||||
vi.mocked(komodoInspectHealthy).mockResolvedValue({ ok: false, reason: 'gone' });
|
||||
await processDestructions();
|
||||
expect(await createServer({ ...input, plutoKey: 'wrong-key', expectedName: 't5_zombie_cosmodrome_3' }))
|
||||
.toMatchObject({ ok: false, kind: 'no-slot' });
|
||||
|
||||
Reference in New Issue
Block a user