Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,10 @@ import {
RUNTIME_HOST_REGISTRATION_SCHEMA_VERSION,
type HostRegistration,
} from '@maka/runtime-host/protocol';
import { runRuntimeHostInstalledUpdateActivator } from '../runtime-host-installed-update-activator.js';
import {
runRuntimeHostInstalledUpdateActivator,
settleTargetFromDurableAuthority,
} from '../runtime-host-installed-update-activator.js';

const ROOT_ID = 'a'.repeat(64);

Expand Down Expand Up @@ -176,13 +179,110 @@ test('fails closed through the authenticated connection when its coordinator cha
retirement = { hostEpoch: connection.hostEpoch, mode };
return { kind: 'prepared', pid: 84 };
},
readRecord: async () => undefined,
},
),
/lost its coordinator channel/u,
/lost its coordinator before ownership committed/u,
);
assert.deepEqual(retirement, { hostEpoch: 'target-host', mode: 'interrupt_active_work' });
});

test('durable committed ownership releases the launch barrier after an ambiguous record read', async () => {
const events: string[] = [];
let reads = 0;
const settlement = await settleTargetFromDurableAuthority(
{
connection: {} as never,
expectedRootId: ROOT_ID,
ownerInstallationId: 'npm-global:slot',
targetVersion: '2.0.0',
targetIntegrity: `sha512-${Buffer.alloc(64, 4).toString('base64')}`,
ownsCandidate: true,
launchBarrier: {
connect: async () => assert.fail('settlement must not connect'),
pause: () => events.push('pause'),
retireExcept: async () => {
events.push('retire');
},
resume: () => events.push('resume'),
release: () => events.push('release'),
},
retireTarget: async () => assert.fail('an owned committed target must not retire'),
readRecord: async () => {
reads += 1;
if (reads === 1) throw new Error('fsync confirmation unavailable');
return {
schemaVersion: 1,
rootId: ROOT_ID,
revision: '00000000-0000-4000-8000-000000000000',
state: {
kind: 'owned',
owner: { kind: 'cli', installationId: 'npm-global:slot' },
selected: {
kind: 'npm_registry',
version: '2.0.0',
integrity: `sha512-${Buffer.alloc(64, 4).toString('base64')}`,
},
},
};
},
},
async () => {
events.push('retry-read');
},
);

assert.equal(settlement, 'committed');
assert.equal(reads, 2);
assert.deepEqual(events, ['retry-read', 'release']);
});

test('a readable uncommitted handoff retires the guarded target', async () => {
const events: string[] = [];
const settlement = await settleTargetFromDurableAuthority({
connection: {} as never,
expectedRootId: ROOT_ID,
ownerInstallationId: 'npm-global:slot',
targetVersion: '2.0.0',
targetIntegrity: `sha512-${Buffer.alloc(64, 4).toString('base64')}`,
ownsCandidate: true,
launchBarrier: {
connect: async () => assert.fail('settlement must not connect'),
pause: () => events.push('pause'),
retireExcept: async () => {
events.push('retire');
},
resume: () => events.push('resume'),
release: () => events.push('release'),
},
retireTarget: async () => assert.fail('the launch barrier owns this candidate'),
readRecord: async () => ({
schemaVersion: 1,
rootId: ROOT_ID,
revision: '00000000-0000-4000-8000-000000000000',
state: {
kind: 'handoff',
transactionId: 'transaction',
from: { kind: 'cli', installationId: 'npm-global:slot' },
to: { kind: 'cli', installationId: 'npm-global:slot' },
selected: {
kind: 'npm_registry',
version: '1.0.0',
integrity: `sha512-${Buffer.alloc(64, 3).toString('base64')}`,
},
target: {
kind: 'npm_registry',
version: '2.0.0',
integrity: `sha512-${Buffer.alloc(64, 4).toString('base64')}`,
},
},
}),
});

assert.equal(settlement, 'retired');
assert.deepEqual(events, ['pause', 'retire']);
});

function registration(overrides: Partial<HostRegistration> = {}): HostRegistration {
return {
kind: 'maka-runtime-host',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,8 @@ test('retires with the current package, activates with the target, then switches
assert.deepEqual(input.target, target);
return {
kind: 'ready',
settle: async (outcome) => {
events.push(`settle-target:${outcome}`);
settle: async () => {
events.push('settle-target');
},
};
},
Expand Down Expand Up @@ -183,7 +183,7 @@ test('retires with the current package, activates with the target, then switches
'switch-global-package',
'verify-new-installation',
'commit-owner',
'settle-target:committed',
'settle-target',
]);
});

Expand Down Expand Up @@ -253,8 +253,8 @@ test('crash-retry observes its own staged target and never retires or re-activat
events.push('activate-target');
return {
kind: 'ready',
settle: async (outcome) => {
events.push(`settle-target:${outcome}`);
settle: async () => {
events.push('settle-target');
},
};
},
Expand Down Expand Up @@ -300,7 +300,7 @@ test('crash-retry observes its own staged target and never retires or re-activat
'activate-target',
'switch-global-package',
'commit-owner',
'settle-target:committed',
'settle-target',
]);
});

Expand Down Expand Up @@ -357,8 +357,8 @@ test('crash-retry with the global package already switched skips the second inst
events.push('activate-target');
return {
kind: 'ready',
settle: async (outcome) => {
events.push(`settle-target:${outcome}`);
settle: async () => {
events.push('settle-target');
},
};
},
Expand Down Expand Up @@ -399,11 +399,11 @@ test('crash-retry with the global package already switched skips the second inst
'close-observed-target',
'activate-target',
'commit-owner',
'settle-target:committed',
'settle-target',
]);
});

test('aborts the short-lived target activator when durable ownership cannot commit', async () => {
test('asks the target activator to adjudicate an uncertain durable commit', async () => {
const events: string[] = [];
const installation = {
owner: OWNER,
Expand Down Expand Up @@ -444,8 +444,8 @@ test('aborts the short-lived target activator when durable ownership cannot comm
connectExisting: async () => ({ kind: 'unavailable', reason: 'not_registered' }),
activateTarget: async () => ({
kind: 'ready',
settle: async (outcome) => {
events.push(`settle-target:${outcome}`);
settle: async () => {
events.push('settle-target');
},
}),
reconcile: (async (_request: unknown, lifecycle: RuntimeHostLocalProcessLifecycleAdapter) => {
Expand All @@ -468,7 +468,7 @@ test('aborts the short-lived target activator when durable ownership cannot comm
},
);
assert.equal(exitCode, 1);
assert.deepEqual(events, ['settle-target:abort']);
assert.deepEqual(events, ['settle-target']);
});

test('rejects extended tar headers before the final global npm switch can spawn', async (t) => {
Expand Down
Loading
Loading