Rebuild beta and campaign file activations

This commit is contained in:
2026-10-12 22:52:58 -04:00
parent fa0baa8db5
commit 537b9841a7
22 changed files with 533 additions and 94 deletions
+24 -6
View File
@@ -36,7 +36,7 @@ beforeEach(async () => {
storageAvailable: 100_000_000_000,
preparedRuntimeImages: ['plutainer:test'],
libraries: [{ id: 'published-game-version', state: 'ready' }],
capabilities: ['instance.safety-override']
capabilities: ['instance.safety-override', 'instance.rebuild-files']
});
const { db } = await import('../../src/lib/server/db/index.js');
instanceId = randomUUID();
@@ -105,6 +105,22 @@ async function stageCampaign() {
"INSERT INTO deployment_servers(deployment_id,server,files_changed,restart_state) VALUES('campaign-race',?,1,'pending')"
)
.run(server);
const { createLibraryImport, updateHostLibraryCaches } =
await import('../../src/lib/server/game-files/index.js');
const library = createLibraryImport({ hostId, game: 't5' });
db()
.prepare(
"UPDATE game_file_versions SET state='ready',manifest='[]',manifest_sha256=?,size_bytes=1,published_at=? WHERE id=?"
)
.run('a'.repeat(64), new Date().toISOString(), library.id);
updateHostLibraryCaches(hostId, [
{ libraryVersionId: library.id, status: 'ready', manifestSha256: 'a'.repeat(64) }
]);
db().prepare('UPDATE native_instances SET library_id=? WHERE server=?').run(library.id, server);
const { reserveServerKey } = await import('../../src/lib/server/fleet/server-keys.js');
reserveServerKey(server, 't5', 'saved-key');
const backend = await import('../../src/lib/server/backends/native.js');
vi.spyOn(backend, 'runtimePasswordForServer').mockReturnValue('saved-password');
const { queueFileChange } = await import('../../src/lib/server/fleet/staged-files.js');
queueFileChange({
sourceKind: 'campaign',
@@ -413,7 +429,7 @@ describe('provisioning admin override', () => {
});
});
it('overrides a waiting campaign restart while keeping its staged changes attached', async () => {
it('overrides a waiting campaign rebuild while keeping its staged changes attached', async () => {
const id = await stageCampaign();
const status = await import('../../src/lib/server/fleet/status-evidence.js');
vi.spyOn(status, 'probePlayerEvidence').mockResolvedValue({
@@ -426,9 +442,11 @@ describe('provisioning admin override', () => {
await confirm(id);
await advance();
const { getHostOperation } = await import('../../src/lib/server/hosts/index.js');
expect(getHostOperation((await operationId(id))!)?.payload).toMatchObject({
stageId: id,
safetyOverride: true
const { getDeployment } = await import('../../src/lib/server/provisioning/history.js');
expect(getDeployment(id)?.deployment).toMatchObject({ state: 'running', error: null });
expect(getHostOperation((await operationId(id))!)).toMatchObject({
kind: 'instance.rebuild',
payload: { stageId: id, safetyOverride: true }
});
const { db } = await import('../../src/lib/server/db/index.js');
expect(
@@ -518,7 +536,7 @@ describe('native scheduler ownership', () => {
).toHaveLength(2);
});
it('holds a paused campaign and cancels withdrawn work before delivering a restart', async () => {
it('holds a paused campaign and cancels withdrawn work before delivering a rebuild', async () => {
const id = await stageCampaign();
const { db } = await import('../../src/lib/server/db/index.js');
db()