Hide live capacity for inactive provisioning operations (Refs #85)
This commit is contained in:
@@ -70,21 +70,29 @@ describe('provisioning detail projection', () => {
|
||||
expect(getDeployment('legacy')!.warningMessages).toEqual(['Recorded warnings could not be read.']);
|
||||
});
|
||||
|
||||
it('correlates reservations by operation ID without assigning a later same-name slot to historical work', async () => {
|
||||
it.each(['create', 'rebuild', 'start', 'restart'] as const)('shows live capacity only for active %s operations, excluding historical work on the same server', async action => {
|
||||
const { db } = await import('../../src/lib/server/db/index.js');
|
||||
const { beginDeployment, getDeployment, finishDeployment } = await import('../../src/lib/server/provisioning/history.js');
|
||||
db().prepare("INSERT INTO servers (name) VALUES ('server')").run();
|
||||
const old = beginDeployment('server', 'restart');
|
||||
const old = beginDeployment('server', action);
|
||||
finishDeployment(old, { ok: false, message: 'Timeout' });
|
||||
const current = beginDeployment('server', 'restart');
|
||||
const current = beginDeployment('server', action);
|
||||
db().prepare("INSERT INTO restart_rollout (server,requested_at,operation_id) VALUES ('server','2026-01-01',?)").run(current);
|
||||
expect(getDeployment(old)!.capacity.pools[0]).toMatchObject({ kind: 'restart', used: 1, ownsSlot: false,
|
||||
holders: [{ id: current, server: 'server' }] });
|
||||
const kinds = action === 'create' ? ['startup'] : action === 'rebuild' ? ['startup', 'restart'] : ['restart'];
|
||||
expect(getDeployment(current)!.capacity.pools).toEqual(kinds.map(kind => expect.objectContaining({
|
||||
kind, used: 1, ownsSlot: true, holders: [{ id: current, server: 'server' }]
|
||||
})));
|
||||
for (const state of ['done', 'warning', 'failed', 'interrupted', 'cancelled']) {
|
||||
db().prepare('UPDATE server_deployments SET state = ? WHERE id = ?').run(state, old);
|
||||
expect(getDeployment(old)!.capacity.pools, state).toEqual([]);
|
||||
}
|
||||
expect(getDeployment(old)!.progress!.recovery).toBeNull();
|
||||
expect(getDeployment(current)!.capacity.pools[0].ownsSlot).toBe(true);
|
||||
db().prepare('UPDATE restart_rollout SET healthy_at = ?').run(new Date().toISOString());
|
||||
expect(getDeployment(old)!.capacity.pools[0].used).toBe(0);
|
||||
expect(getDeployment(old)!.deployment.state).toBe('failed');
|
||||
expect(getDeployment(old)!.capacity.pools).toEqual([]);
|
||||
for (const state of ['queued', 'waiting', 'running', 'awaiting-health']) {
|
||||
db().prepare('UPDATE server_deployments SET state = ? WHERE id = ?').run(state, current);
|
||||
expect(getDeployment(current)!.capacity.pools.map(pool => pool.kind), state).toEqual(kinds);
|
||||
}
|
||||
});
|
||||
|
||||
it('labels submission order independently of startup reservations and retains queued recipe status', async () => {
|
||||
@@ -113,10 +121,12 @@ describe('provisioning detail projection', () => {
|
||||
history.finishDeployment(id, { ok: false, message: 'Observation interrupted' });
|
||||
const failed = history.getDeployment(id)!;
|
||||
expect(failed.progress?.phase).toBe('verify-game');
|
||||
expect(failed.capacity.pools).toEqual([]);
|
||||
expect(history.resumeVerification(id)).toBe(true);
|
||||
const resumed = history.getDeployment(id)!;
|
||||
expect(resumed.deployment).toMatchObject({ id, state: 'awaiting-health', finished_at: null, error: null });
|
||||
expect(resumed.progress).toMatchObject({ phase: 'verify-container', checks: [], observedAt: null });
|
||||
expect(resumed.capacity.pools).toEqual([expect.objectContaining({ kind: 'startup', ownsSlot: true })]);
|
||||
const outcomes = resumed.events.filter(event => event.kind === 'outcome');
|
||||
expect(outcomes).toHaveLength(1);
|
||||
expect(JSON.parse(outcomes[0].details_json!)).toMatchObject({ state: 'failed', finishedAt: failed.deployment.finished_at,
|
||||
|
||||
Reference in New Issue
Block a user