Support multi-game betas with automatic server selection

This commit is contained in:
2026-10-07 09:41:17 -04:00
parent a6dee8c5e2
commit c6352d86b4
17 changed files with 881 additions and 173 deletions
+81
View File
@@ -0,0 +1,81 @@
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { newFixture, type Fixture } from '../helpers/fixture.js';
let fixture: Fixture;
beforeEach(async () => {
vi.resetModules();
fixture = await newFixture([]);
});
afterEach(async () => { await fixture.cleanup(); vi.restoreAllMocks(); });
async function seedBeta(multiple: boolean) {
const { db, closeDb } = await import('../../src/lib/server/db/index.js');
const { createScript, getLatestVersion } = await import('../../src/lib/server/fleet/scripts.js');
const games = multiple ? ['t5', 't6'] : ['t5'];
const scripts = games.map(game => {
const { script } = createScript({ name: `${game} test`, targetRelPath: `${game}.gsc`,
scopeType: 'game', scopeValue: game, content: Buffer.from(`${game} version`) });
return { ...script, versionId: getLatestVersion(script.id)!.id };
});
const betaId = Number(db().prepare(`INSERT INTO betas (script_id, script_version_id, trigger_kind, state)
VALUES (?, ?, 'bundle', 'running')`).run(scripts[0].id, scripts[0].versionId).lastInsertRowid);
for (const script of scripts) db().prepare('INSERT INTO beta_scripts (beta_id, script_id, script_version_id) VALUES (?, ?, ?)')
.run(betaId, script.id, script.versionId);
for (const [name, game] of [['first', 't5'], ['second', multiple ? 't6' : 't5']]) {
db().prepare('INSERT INTO servers (name, game) VALUES (?, ?)').run(name, game);
db().prepare(`INSERT INTO beta_servers (beta_id, server, had_original, prior_version_id, stage)
VALUES (?, ?, 1, ?, 'awaiting-empty')`).run(betaId, name, scripts[0].versionId);
}
const assign = (server: string, scriptId: number) => db().prepare(`INSERT INTO beta_server_scripts
(beta_id, server, script_id, had_original) VALUES (?, ?, ?, 0)`).run(betaId, server, scriptId);
const memberships = () => db().prepare(`SELECT server, script_id, had_original, prior_version_id
FROM beta_server_scripts WHERE beta_id = ? ORDER BY server, script_id`).all(betaId);
return { betaId, scripts, assign, memberships, db, closeDb };
}
describe('per-server beta membership', () => {
it('shows only each game’s held files in fleet and server snapshots', async () => {
const x = await seedBeta(true);
x.assign('first', x.scripts[0].id);
x.assign('second', x.scripts[1].id);
const { fleetSnapshot } = await import('../../src/lib/server/fleet/snapshot.js');
const expected = [
{ name: 'first', held: [{ target: 't5.gsc', betaId: x.betaId }] },
{ name: 'second', held: [{ target: 't6.gsc', betaId: x.betaId }] }
];
expect(fleetSnapshot().servers.map(({ name, held }) => ({ name, held }))).toEqual(expected);
expect(fleetSnapshot('second').servers.map(({ name, held }) => ({ name, held }))).toEqual([expected[1]]);
});
it('preserves game-specific membership when the database reopens', async () => {
const x = await seedBeta(true);
x.assign('first', x.scripts[0].id);
x.assign('second', x.scripts[1].id);
const expected = x.memberships();
x.closeDb();
expect(x.memberships()).toEqual(expected);
x.closeDb();
expect(x.memberships()).toEqual(expected);
});
it('does not infer missing bundle membership from the primary script', async () => {
const x = await seedBeta(true);
x.assign('first', x.scripts[0].id);
const expected = x.memberships();
x.closeDb();
expect(x.memberships()).toEqual(expected);
});
it('still backfills legacy single-script servers while retaining existing snapshots', async () => {
const x = await seedBeta(false);
x.assign('first', x.scripts[0].id);
x.db().prepare('DELETE FROM beta_scripts WHERE beta_id = ?').run(x.betaId);
x.closeDb();
expect(x.memberships()).toEqual([
{ server: 'first', script_id: x.scripts[0].id, had_original: 0, prior_version_id: null },
{ server: 'second', script_id: x.scripts[0].id, had_original: 1, prior_version_id: x.scripts[0].versionId }
]);
expect(x.db().prepare('SELECT script_id, script_version_id FROM beta_scripts WHERE beta_id = ?').all(x.betaId))
.toEqual([{ script_id: x.scripts[0].id, script_version_id: x.scripts[0].versionId }]);
});
});