import { afterEach, beforeEach, expect, it, vi } from 'vitest'; import { newFixture, type Fixture } from '../helpers/fixture.js'; import { prepareNativeHost } from '../helpers/native-host.js'; import { scalingSettings, type ScalingPolicy } from '../../src/lib/autoscaling.js'; let fixture: Fixture; beforeEach(async () => { vi.resetModules(); fixture = await newFixture([]); }); afterEach(async () => { await fixture.cleanup(); }); const town = 't6_zombie_town_1', farm = 't6_zombie_farm_1'; const policy: ScalingPolicy = { ...scalingSettings({ game: 't6', mapSlug: 'town', maximum: 4, mode: 'dry-run' }), id: 'policy', revision: 1, nextActionAt: 0, pausedReason: null, updatedAt: '' }; it('separates variants, deduplicates pending identities, and initializes additive schema', async () => { await prepareNativeHost([town, farm]); const { db } = await import('../../src/lib/server/db/index.js'); const { scalingSnapshot } = await import('../../src/lib/server/autoscaling/snapshot.js'); const { ensureAutoscalingSchema } = await import('../../src/lib/server/autoscaling/schema.js'); ensureAutoscalingSchema(db()); ensureAutoscalingSchema(db()); const at = new Date().toISOString(); for (const server of [town, farm]) db().prepare(`INSERT INTO servers(name,container_state,container_checked_at,last_seen_at,last_checked_at,last_players) VALUES(?,'running',?,?,?,0)`).run(server, at, at, at); expect(scalingSnapshot(policy).members.map(m => [m.name, m.state])).toEqual([[town, 'empty']]); db().prepare(`INSERT INTO server_deployments(id,server,action,state,stage,started_at,triggered_by) VALUES('create',?,'create','queued','Awaiting placement',?,'test')`).run(town, at); db().prepare(`INSERT INTO server_creation_jobs(deployment_id,server,game_mode,map_slug,expected_map) VALUES('create',?,'zombie','town','zm_transit')`).run(town); const snapshot = scalingSnapshot(policy); expect(snapshot.members).toHaveLength(1); expect(snapshot.members[0].state).toBe('creating'); expect(snapshot.reservedNames).toEqual([town]); }); it('does not create schema mutations or host work when planning an empty map', async () => { const { db } = await import('../../src/lib/server/db/index.js'); const { scalingSnapshot } = await import('../../src/lib/server/autoscaling/snapshot.js'); const { planScaling } = await import('../../src/lib/server/autoscaling/planner.js'); db().prepare('INSERT INTO server_keys(server_id,pluto_key) VALUES(?,?)').run('t6_zombie_town_8', 'private-key'); expect(planScaling(policy, scalingSnapshot(policy), Date.now()).server).toBe('t6_zombie_town_8'); expect(db().prepare('SELECT COUNT(*) AS n FROM server_deployments').get()).toEqual({ n: 0 }); });