Queue native collection launches before async placement
This commit is contained in:
@@ -243,6 +243,68 @@ describe('automatic host preparation', () => {
|
||||
expect(libraries.requireReadyLibrary(id, old.id).id).toBe(old.id);
|
||||
});
|
||||
|
||||
it.each([false, true])('prepares queued runtime and library versions after newer publication (automatic placement: %s)', async automatic => {
|
||||
const old = await publish();
|
||||
const id = enroll({ runtimeImages: [runtime] });
|
||||
const other = enroll({ runtimeImages: [runtime] });
|
||||
const image = 'ghcr.io/example/plutainer:queued-version';
|
||||
const { queueNativeCreation } = await import('../../src/lib/server/provisioning/native.js');
|
||||
for (let index = 0; index < 2; index++) {
|
||||
expect(queueNativeCreation({ game: 't5', gameMode: 'zombie', mapSlug: 'theater', libraryId: old.id,
|
||||
hostId: automatic ? undefined : id, image, plutoKey: 'saved-key' }).ok).toBe(true);
|
||||
}
|
||||
const latest = await publish();
|
||||
const status = preparation.hostPreparationStatus(hosts.getHost(id)!);
|
||||
expect(status.items.filter(item => item.label === image)).toHaveLength(1);
|
||||
expect(status.items.filter(item => item.label.includes('Queued version'))).toHaveLength(1);
|
||||
const otherStatus = preparation.hostPreparationStatus(hosts.getHost(other)!);
|
||||
expect(otherStatus.items.some(item => item.label === image)).toBe(automatic);
|
||||
expect(otherStatus.items.some(item => item.label.includes('Queued version'))).toBe(automatic);
|
||||
expect(operations(id)).toEqual([]);
|
||||
|
||||
preparation.reconcileHostPreparation(id);
|
||||
const pull = operations(id)[0];
|
||||
expect(pull).toMatchObject({ kind: 'runtime.pull', payload: { image } });
|
||||
vi.setSystemTime(Date.now() + 1);
|
||||
hosts.reportHostOperation(id, pull.id, { state: 'completed' });
|
||||
heartbeat(id, { runtimeImages: [runtime, image] });
|
||||
preparation.reconcileHostPreparation(id);
|
||||
const download = operations(id)[0];
|
||||
expect(download).toMatchObject({ kind: 'library.download', payload: { libraryVersionId: old.id, automatic: true } });
|
||||
preparation.reconcileHostPreparation(id);
|
||||
expect(hosts.getHostOperation(download.id)?.state).toBe('pending');
|
||||
expect(operations(id)).toHaveLength(2);
|
||||
|
||||
verified(id, old);
|
||||
vi.setSystemTime(Date.now() + 1);
|
||||
hosts.reportHostOperation(id, download.id, { state: 'completed' });
|
||||
heartbeat(id, { runtimeImages: [runtime, image], libraries: [{ id: old.id, state: 'ready' }] });
|
||||
preparation.reconcileHostPreparation(id);
|
||||
expect(operations(id)[0]).toMatchObject({ kind: 'library.download', payload: { libraryVersionId: latest.id } });
|
||||
});
|
||||
|
||||
it('retains an undelivered library download for an accepted intent until that intent is cancelled', async () => {
|
||||
const old = await publish();
|
||||
const id = enroll({ runtimeImages: [runtime] });
|
||||
preparation.reconcileHostPreparation(id);
|
||||
const download = operations(id)[0];
|
||||
const { queueNativeCreation } = await import('../../src/lib/server/provisioning/native.js');
|
||||
const launch = queueNativeCreation({ game: 't5', gameMode: 'zombie', mapSlug: 'theater', libraryId: old.id,
|
||||
hostId: id, image: runtime, plutoKey: 'saved-key' });
|
||||
expect(launch.ok).toBe(true);
|
||||
if (!launch.ok) throw new Error(launch.message);
|
||||
const latest = await publish();
|
||||
preparation.reconcileHostPreparation(id);
|
||||
expect(hosts.getHostOperation(download.id)?.state).toBe('pending');
|
||||
expect(operations(id)).toHaveLength(1);
|
||||
|
||||
const { cancelCreation } = await import('../../src/lib/server/provisioning/cancel-creation.js');
|
||||
expect(cancelCreation(launch.deploymentId)).toEqual(expect.any(String));
|
||||
preparation.reconcileHostPreparation(id);
|
||||
expect(hosts.getHostOperation(download.id)).toMatchObject({ state: 'failed', error: expect.stringContaining('Superseded') });
|
||||
expect(operations(id)[0]).toMatchObject({ kind: 'library.download', payload: { libraryVersionId: latest.id } });
|
||||
});
|
||||
|
||||
it('finishes a delivered download before following a newer upload under a new operation ID', async () => {
|
||||
const old = await publish();
|
||||
const id = enroll({ runtimeImages: [runtime] });
|
||||
|
||||
Reference in New Issue
Block a user