Skip to content

Commit 9f3e58f

Browse files
thymikeeclaude
andcommitted
test: build the scenario gateway on the daemon host's env and pin the host claims directory on a failed release
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
1 parent 870cf66 commit 9f3e58f

3 files changed

Lines changed: 47 additions & 1 deletion

File tree

‎packages/daemon/src/resources/device/__tests__/device-claim-admission.test.ts‎

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import {
22
ANDROID_EMULATOR,
33
deviceClaimFilePath,
44
createTestHostEnvironment,
5+
mkdtempForTestSync,
56
} from '@agent-device/test-kit';
67
import { expect, test, vi } from 'vitest';
78
import {
@@ -467,6 +468,49 @@ test('a failed release abandons the claim so the next command is not locked out'
467468
expect(inspectDeviceClaims({}, process.env)).toEqual([]);
468469
});
469470

471+
test("a failed release abandons the claim in the host's claims directory, not the process's", async () => {
472+
const { stateDir } = setup();
473+
const hostClaimsDir = mkdtempForTestSync('agent-device-host-claims-');
474+
const hostEnv = { ...process.env, AGENT_DEVICE_CLAIMS_DIR: hostClaimsDir };
475+
const admission = createDeviceClaimAdmission({
476+
env: hostEnv,
477+
policy: 'transient-exclusive',
478+
command: 'install',
479+
session: 'own-session',
480+
workspace: '/worktrees/current',
481+
callerCwd: '/worktrees/current',
482+
resolveScopeRoot: resolveCallerScopeRoot,
483+
stateDir,
484+
reconcileOrphanedDeviceClaim: retainOrphanedDeviceClaims,
485+
});
486+
await admission.admit(ANDROID_EMULATOR, localAndroid);
487+
const claimFiles = fs
488+
.readdirSync(hostClaimsDir, { recursive: true })
489+
.map((entry) => path.join(hostClaimsDir, String(entry)))
490+
.filter((entry) => fs.statSync(entry).isFile() && entry.endsWith('.json'));
491+
expect(claimFiles).toHaveLength(1);
492+
493+
const originalUnlink = fs.unlinkSync;
494+
const unlink = vi.spyOn(fs, 'unlinkSync').mockImplementation((target) => {
495+
if (String(target) === claimFiles[0]) {
496+
throw Object.assign(new Error('read-only file system'), { code: 'EROFS' });
497+
}
498+
return originalUnlink(target as Parameters<typeof fs.unlinkSync>[0]);
499+
});
500+
try {
501+
await admission[Symbol.asyncDispose]();
502+
} finally {
503+
unlink.mockRestore();
504+
}
505+
506+
// The abandon went to the host's directory, where the claim was written; the process's own
507+
// claims directory never held it.
508+
const survivor = inspectDeviceClaims({}, hostEnv);
509+
expect(survivor.map((entry) => entry.claim?.session)).toEqual(['transient:install']);
510+
expect(survivor[0]?.claim?.abandonedAtMs).toBeTypeOf('number');
511+
expect(inspectDeviceClaims({}, process.env)).toEqual([]);
512+
});
513+
470514
test("an abandoned claim becomes this command's own transient claim and is released", async () => {
471515
const { stateDir } = setup();
472516
const aborted = await acquireDeviceClaim({

‎test/integration/provider-scenarios/harness.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ export async function createProviderScenarioHarness(
148148
platformRuntime?.providerModules ??
149149
createProviderPlatformRuntimeRegistrations(configuredRuntimes);
150150
const defaultDeviceRuntimeGateway = createPlatformRuntimeGateway({
151-
env: process.env,
151+
env: input.host.env,
152152
assertShutdownAllowed: input.assertShutdownAllowed,
153153
providerRuntimes: configuredRuntimes,
154154
providerModules,

‎test/integration/provider-scenarios/ios-record-trace.test.ts‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,8 @@ test('iOS simulator recording reports host contention and recovers through the f
112112
appleSimulatorScreenRecordingTransport: () => recordingTransport,
113113
deviceInventoryProvider: async () => [PROVIDER_SCENARIO_IOS_SIMULATOR],
114114
});
115+
// The recording finalizer and Swift helper still read PATH and the cache from the process
116+
// (capture-kit and the root helpers move to the host in #3777), so the scenario sets both.
115117
const previousPath = process.env.PATH;
116118
const previousSwiftCacheDir = process.env.AGENT_DEVICE_SWIFT_CACHE_DIR;
117119
process.env.PATH = tmpDir;

0 commit comments

Comments
 (0)