diff --git a/packages/contracts/src/dispatch-disclosure.fixtures.ts b/packages/contracts/src/dispatch-disclosure.fixtures.ts index c7ab4137b4..441205541c 100644 --- a/packages/contracts/src/dispatch-disclosure.fixtures.ts +++ b/packages/contracts/src/dispatch-disclosure.fixtures.ts @@ -37,11 +37,11 @@ export const DISPATCH_DISCLOSURE_TABLE_PATH = path.join( * followed by `test(\`${row.id}`, which {@link DISPATCH_DISCLOSURE_ROW_LOOP} matches. */ export const DISPATCH_DISCLOSURE_DRIVER_OWNERS: Readonly> = { - 'daemon.': 'src/daemon/interaction/internal/__tests__/interaction-dispatch-disclosure.test.ts', + 'daemon.': 'src/__tests__/daemon-composition/interaction/interaction-dispatch-disclosure.test.ts', 'daemon.scroll-no-progress': 'src/daemon/__tests__/scroll-movement.test.ts', - 'daemon.route.': 'src/daemon/__tests__/request-dispatch-disclosure.test.ts', + 'daemon.route.': 'src/__tests__/daemon-composition/request-dispatch-disclosure.test.ts', 'post-action-guard.': - 'src/daemon/interaction/internal/__tests__/interaction-dispatch-disclosure.test.ts', + 'src/__tests__/daemon-composition/interaction/interaction-dispatch-disclosure.test.ts', 'ios-runner.': 'packages/platform-apple/src/runner/__tests__/runner-dispatch-disclosure.test.ts', 'ios-runner.pre-send.': 'packages/platform-apple/src/runner/__tests__/runner-lifecycle-dispatch-disclosure.test.ts', @@ -56,7 +56,7 @@ export const DISPATCH_DISCLOSURE_DRIVER_OWNERS: Readonly> 'web-agent-browser.': 'packages/platform-web/src/__tests__/agent-browser-dispatch-disclosure.test.ts', 'maestro-direct.': - 'src/daemon/interaction/internal/__tests__/interaction-touch-direct-ios.test.ts', + 'src/__tests__/daemon-composition/interaction/interaction-touch-direct-ios.test.ts', }; /** The per-row driving loop every driver file carries. */ diff --git a/packages/contracts/src/snapshot-runtime.test.ts b/packages/contracts/src/snapshot-runtime.test.ts index f19374d4c6..2499553980 100644 --- a/packages/contracts/src/snapshot-runtime.test.ts +++ b/packages/contracts/src/snapshot-runtime.test.ts @@ -114,7 +114,8 @@ test('provider snapshot binding presents acquired facts through the supplied hos // signal is fixed at bind time, but `wait` binds once and polls many times, so // each poll must be able to cancel its own capture without cancelling the // binding. These are the contract-level halves of that claim; the poll-deadline -// behaviour itself is proven end to end in `src/daemon/__tests__/wait-runtime.test.ts`. +// behaviour itself is proven end to end in +// `src/__tests__/daemon-composition/wait-runtime.test.ts`. // --------------------------------------------------------------------------- test('a capture with no per-capture signal receives the binding signal itself, not a wrapper', () => { diff --git a/packages/test-kit/src/boundary-fault-matrix.ts b/packages/test-kit/src/boundary-fault-matrix.ts index 1de46d21b8..afdc2d6fcc 100644 --- a/packages/test-kit/src/boundary-fault-matrix.ts +++ b/packages/test-kit/src/boundary-fault-matrix.ts @@ -193,7 +193,9 @@ export const BOUNDARY_FAULT_MATRIX = { 'optional-optimization-failure': { mutation: { kind: 'covered', - evidence: ['src/daemon/interaction/internal/__tests__/interaction-touch-direct-ios.test.ts'], + evidence: [ + 'src/__tests__/daemon-composition/interaction/interaction-touch-direct-ios.test.ts', + ], invariants: ['best-effort-degradation'], }, read: { diff --git a/src/daemon/__tests__/capture-disclosure.test.ts b/src/__tests__/daemon-composition/capture-disclosure.test.ts similarity index 91% rename from src/daemon/__tests__/capture-disclosure.test.ts rename to src/__tests__/daemon-composition/capture-disclosure.test.ts index 7a5b638e6d..e8972a9630 100644 --- a/src/daemon/__tests__/capture-disclosure.test.ts +++ b/src/__tests__/daemon-composition/capture-disclosure.test.ts @@ -1,15 +1,18 @@ import { test, expect, vi, beforeEach } from 'vitest'; -import { legacyDispatchCapture } from './legacy-snapshot-capture-fixture.ts'; -import { handleFindCommands } from '../interaction/index.ts'; -import { getRuntimeBindings } from './interaction-get-runtime-fixture.ts'; -import { dispatchFindReadOnlyViaRuntime } from '../selector-runtime.ts'; -import { dispatchWaitViaRuntime } from '../wait-runtime.ts'; -import type { DaemonRequest, DaemonResponse } from '../daemon-request.ts'; +import { legacyDispatchCapture } from '../../daemon/__tests__/legacy-snapshot-capture-fixture.ts'; +import { handleFindCommands } from '../../daemon/interaction/index.ts'; +import { getRuntimeBindings } from '../../daemon/__tests__/interaction-get-runtime-fixture.ts'; +import { dispatchFindReadOnlyViaRuntime } from '../../daemon/selector-runtime.ts'; +import { dispatchWaitViaRuntime } from '../../daemon/wait-runtime.ts'; +import type { DaemonRequest, DaemonResponse } from '../../daemon/daemon-request.ts'; import { ANDROID_SYSTEM_SURFACE_DISCLOSURE } from '@agent-device/contracts/android-system-surface-disclosure'; import { iosSystemSurfaceDisclosure } from '@agent-device/contracts/ios-system-surface'; -import { snapshotRuntimeFixture } from './snapshot-runtime-fixture.ts'; -import { makeSessionStore } from './support/store-factory.ts'; -import { makeAndroidSession, makeIosSession } from './support/session-factories.ts'; +import { snapshotRuntimeFixture } from '../../daemon/__tests__/snapshot-runtime-fixture.ts'; +import { makeSessionStore } from '../../daemon/__tests__/support/store-factory.ts'; +import { + makeAndroidSession, + makeIosSession, +} from '../../daemon/__tests__/support/session-factories.ts'; import { platformResourceCleanup } from '../../platform-runtime-resource-cleanup.ts'; import { testCreateCommandSurface } from './command-surface-fixture.ts'; @@ -22,20 +25,20 @@ vi.mock('@agent-device/device-selection/dispatch-resolve', async (importOriginal }; }); -vi.mock('../snapshot-interactor-capture.ts', async () => { - const fixture = await import('./legacy-snapshot-capture-fixture.ts'); +vi.mock('../../daemon/snapshot-interactor-capture.ts', async () => { + const fixture = await import('../../daemon/__tests__/legacy-snapshot-capture-fixture.ts'); return { captureSnapshotWithInteractor: fixture.captureSnapshotThroughLegacyDispatchFixture }; }); -vi.mock('../device/device-ready.ts', () => ({ +vi.mock('../../daemon/device/device-ready.ts', () => ({ ensureDeviceReady: vi.fn(async () => {}), })); import { resolveTargetDevice } from '@agent-device/device-selection/dispatch-resolve'; import { ANDROID_EMULATOR } from '@agent-device/test-kit/device-fixtures'; -import { withSystemSurfaceDisclosure } from '../capture-disclosure.ts'; +import { withSystemSurfaceDisclosure } from '../../daemon/capture-disclosure.ts'; import { iosTargetActivationDisclosure } from '@agent-device/contracts/ios-target-activation'; -import { TARGET_ACTIVATION_FACT } from './capture-disclosure-target-activation-fact.ts'; +import { TARGET_ACTIVATION_FACT } from '../../daemon/__tests__/capture-disclosure-target-activation-fact.ts'; // The occluding-shade capture every scenario below consumes: no application window content, one // active quick-settings surface. The Android capture route stamps systemSurfaceOnly on both the diff --git a/src/daemon/__tests__/command-surface-fixture.ts b/src/__tests__/daemon-composition/command-surface-fixture.ts similarity index 100% rename from src/daemon/__tests__/command-surface-fixture.ts rename to src/__tests__/daemon-composition/command-surface-fixture.ts diff --git a/src/daemon/__tests__/generic-settle.test.ts b/src/__tests__/daemon-composition/generic-settle.test.ts similarity index 96% rename from src/daemon/__tests__/generic-settle.test.ts rename to src/__tests__/daemon-composition/generic-settle.test.ts index 62e887af35..735294fd80 100644 --- a/src/daemon/__tests__/generic-settle.test.ts +++ b/src/__tests__/daemon-composition/generic-settle.test.ts @@ -1,4 +1,4 @@ -import { daemonPlatformServicesFixture } from './platform-services-fixture.ts'; +import { daemonPlatformServicesFixture } from '../../daemon/__tests__/platform-services-fixture.ts'; import { beforeEach, expect, test, vi } from 'vitest'; import type { CommandFlags } from '@agent-device/contracts/command'; import type { RawSnapshotNode } from '@agent-device/kernel/snapshot'; @@ -8,15 +8,15 @@ import { iosSystemSurfaceTransitionDisclosure, type IosSystemSurfaceProvenance, } from '@agent-device/contracts/ios-system-surface'; -import { makeIosSession } from './support/session-factories.ts'; -import { makeSessionStore } from './support/store-factory.ts'; -import { activateCompleteRefFrame, refFrameState } from '../ref-frame.ts'; -import { setSessionSnapshot } from '../session-snapshot.ts'; -import type { SessionStore } from '../session-store.ts'; -import type { DaemonRequest, DaemonResponse } from '../daemon-request.ts'; -import type { SessionRef, SessionState } from '../session-state.ts'; +import { makeIosSession } from '../../daemon/__tests__/support/session-factories.ts'; +import { makeSessionStore } from '../../daemon/__tests__/support/store-factory.ts'; +import { activateCompleteRefFrame, refFrameState } from '../../daemon/ref-frame.ts'; +import { setSessionSnapshot } from '../../daemon/session-snapshot.ts'; +import type { SessionStore } from '../../daemon/session-store.ts'; +import type { DaemonRequest, DaemonResponse } from '../../daemon/daemon-request.ts'; +import type { SessionRef, SessionState } from '../../daemon/session-state.ts'; import { buildSnapshotState } from '@agent-device/capture-kit/snapshot-state'; -import { selectorCaptureFixture } from './selector-capture-fixture.ts'; +import { selectorCaptureFixture } from '../../daemon/__tests__/selector-capture-fixture.ts'; import { testCreateCommandSurface } from './command-surface-fixture.ts'; // #1638 `--settle` on the GENERIC daemon route (scroll/back): the settled diff, @@ -25,8 +25,8 @@ import { testCreateCommandSurface } from './command-surface-fixture.ts'; // a resolution, and the observation must run after the deferred-outcome // markers. Quiet windows are tuned down so no test waits real time. -vi.mock('../interaction/index.ts', async (importOriginal) => { - const actual = await importOriginal(); +vi.mock('../../daemon/interaction/index.ts', async (importOriginal) => { + const actual = await importOriginal(); return { ...actual, captureSnapshotForSession: vi.fn(async () => ({ @@ -38,9 +38,9 @@ vi.mock('../interaction/index.ts', async (importOriginal) => { }; }); -import { captureSnapshotForSession } from '../interaction/index.ts'; -import { dispatchGenericCommand } from '../request-generic-dispatch.ts'; -import { pendingSurfaceStabilization } from '../deferred-interaction-outcome.ts'; +import { captureSnapshotForSession } from '../../daemon/interaction/index.ts'; +import { dispatchGenericCommand } from '../../daemon/request-generic-dispatch.ts'; +import { pendingSurfaceStabilization } from '../../daemon/deferred-interaction-outcome.ts'; const mockCaptureSnapshotForSession = vi.mocked(captureSnapshotForSession); diff --git a/src/__tests__/daemon-composition/handlers/lease-provider-credentials.test.ts b/src/__tests__/daemon-composition/handlers/lease-provider-credentials.test.ts new file mode 100644 index 0000000000..9c7a8e2b3d --- /dev/null +++ b/src/__tests__/daemon-composition/handlers/lease-provider-credentials.test.ts @@ -0,0 +1,244 @@ +import assert from 'node:assert/strict'; +import fs from 'node:fs'; +import path from 'node:path'; +import { test } from 'vitest'; +import { handleLeaseCommands } from '../../../daemon/handlers/lease.ts'; +import { LeaseRegistry } from '../../../daemon/lease-registry.ts'; +import type { DaemonRequest } from '../../../daemon/daemon-request.ts'; +import { makeSessionStore } from '../../../daemon/__tests__/support/store-factory.ts'; +import { AppError } from '@agent-device/kernel/errors'; +import { + providerCredentialFingerprint, + readDaemonProviderCredentials, +} from '../../../provider-credential-fingerprint.ts'; +import { pluginHome, selectPluginManifest } from '../../../plugins/plugin.fixtures.ts'; + +/** + * Lease refusal compares the client's credential fingerprint against the digest the daemon + * computes from its own startup environment through the real root fingerprint reader and the + * installed-plugin manifest registry. Those digests and manifest lookups are the composition + * this suite pins, so it lives root-owned; lease mechanics stay in the daemon suite. + */ + +function allocateRequest(): DaemonRequest { + return { + token: 'test-token', + session: 'lease-ttl-test', + command: 'lease_allocate', + positionals: [], + flags: {}, + meta: { + tenantId: 'tenant-a', + runId: 'run-a', + clientId: 'client-a', + leaseBackend: 'android-instance', + leaseProvider: 'cloud', + }, + }; +} + +const LIMRUN_ATTACH_ENV = { + LIMRUN_API_KEY: 'lim-key', + LIM_IOS_INSTANCE_URL: 'https://region.limrun.example/v1/ios_x/api', + LIM_IOS_INSTANCE_TOKEN: 'ios-token', +}; +const BROWSERSTACK_ENV = { BROWSERSTACK_USERNAME: 'user', BROWSERSTACK_ACCESS_KEY: 'key-1' }; + +function providerAllocateRequest( + leaseProvider: string, + providerCredentialFingerprint: string | undefined, + leaseBackend: 'ios-instance' | 'android-instance' = 'ios-instance', +): DaemonRequest { + const request = allocateRequest(); + return { + ...request, + meta: { + ...request.meta, + leaseProvider, + leaseBackend, + providerCredentialFingerprint, + }, + }; +} + +async function allocateWithDaemonEnv( + req: DaemonRequest, + daemonEnv: Record, +): Promise<{ allocations: number; error?: AppError }> { + const registry = new LeaseRegistry(); + let allocations = 0; + try { + await handleLeaseCommands({ + req, + sessionName: req.session, + sessionStore: makeSessionStore('agent-device-provider-credentials-'), + leaseRegistry: registry, + providerCredentials: readDaemonProviderCredentials(daemonEnv, '/tmp/agent device state'), + leaseLifecycleProvider: { + allocate: async () => { + allocations += 1; + return {}; + }, + }, + }); + } catch (error) { + assert.deepEqual(registry.listActiveLeases(), []); + return { allocations, error: error as AppError }; + } + return { allocations }; +} + +test('a daemon started with only LIMRUN_API_KEY refuses a shell with instance variables before allocation', async () => { + const outcome = await allocateWithDaemonEnv( + providerAllocateRequest('limrun', providerCredentialFingerprint('limrun', LIMRUN_ATTACH_ENV)), + { LIMRUN_API_KEY: 'lim-key' }, + ); + + assert.equal(outcome.allocations, 0); + assert.equal(outcome.error?.code, 'INVALID_ARGS'); + assert.equal(outcome.error?.details?.reason, 'provider-credentials-changed'); + assert.equal(outcome.error?.details?.provider, 'limrun'); + assert.match( + String(outcome.error?.details?.hint), + /agent-device daemon stop --state-dir '\/tmp\/agent device state'/, + ); +}); + +test('a Limrun lease compares only the leased platform instance variables', async () => { + const daemonEnv = { + ...LIMRUN_ATTACH_ENV, + LIM_ANDROID_INSTANCE_URL: 'https://region.limrun.example/v1/android_x/api', + LIM_ANDROID_INSTANCE_TOKEN: 'android-token', + LIM_ANDROID_INSTANCE_ADB_URL: 'wss://region.limrun.example/v1/android_x/adb', + }; + const shellEnv = { ...daemonEnv, LIM_ANDROID_INSTANCE_TOKEN: 'android-token-2' }; + const allocate = async (leaseBackend: 'ios-instance' | 'android-instance') => + await allocateWithDaemonEnv( + providerAllocateRequest( + 'limrun', + providerCredentialFingerprint('limrun', shellEnv, leaseBackend), + leaseBackend, + ), + daemonEnv, + ); + + assert.equal((await allocate('ios-instance')).error, undefined); + assert.equal( + (await allocate('android-instance')).error?.details?.reason, + 'provider-credentials-changed', + ); +}); + +test('a daemon holding rotated BrowserStack keys refuses before allocation', async () => { + const outcome = await allocateWithDaemonEnv( + providerAllocateRequest( + 'browserstack', + providerCredentialFingerprint('browserstack', { + ...BROWSERSTACK_ENV, + BROWSERSTACK_ACCESS_KEY: 'key-2', + }), + ), + BROWSERSTACK_ENV, + ); + + assert.equal(outcome.allocations, 0); + assert.equal(outcome.error?.details?.reason, 'provider-credentials-changed'); + assert.equal(outcome.error?.details?.provider, 'browserstack'); +}); + +test.for([ + ['limrun', LIMRUN_ATTACH_ENV], + ['browserstack', BROWSERSTACK_ENV], +] as const)( + 'a daemon holding the %s credentials of the shell allocates', + async ([provider, env]) => { + const outcome = await allocateWithDaemonEnv( + providerAllocateRequest(provider, providerCredentialFingerprint(provider, env)), + env, + ); + + assert.equal(outcome.error, undefined); + assert.equal(outcome.allocations, 1); + }, +); + +test('a daemon holding credentials allocates for a shell with none', async () => { + const outcome = await allocateWithDaemonEnv( + providerAllocateRequest('limrun', providerCredentialFingerprint('limrun', {})), + { LIMRUN_API_KEY: 'lim-key' }, + ); + + assert.equal(outcome.error, undefined); + assert.equal(outcome.allocations, 1); +}); + +test('a daemon started without BrowserStack credentials refuses a shell that has them', async () => { + const outcome = await allocateWithDaemonEnv( + providerAllocateRequest( + 'browserstack', + providerCredentialFingerprint('browserstack', BROWSERSTACK_ENV), + ), + {}, + ); + + assert.equal(outcome.allocations, 0); + assert.equal(outcome.error?.details?.reason, 'provider-credentials-changed'); + assert.match(String(outcome.error?.message), /started without the browserstack credentials/); +}); + +function testMuPluginEnv(): Record { + const manifest = path.resolve( + import.meta.dirname, + '../../../../packages/provider-testmu/package.json', + ); + const { home, env } = pluginHome(); + selectPluginManifest(home, JSON.parse(fs.readFileSync(manifest, 'utf8'))); + return env; +} + +test('a daemon holding other TestMu AI credentials refuses before allocation', async () => { + const home = testMuPluginEnv(); + const daemonEnv = { ...home, LT_USERNAME: 'user', LT_ACCESS_KEY: 'key-1' }; + const outcome = await allocateWithDaemonEnv( + providerAllocateRequest( + 'testmu', + providerCredentialFingerprint('testmu', { ...daemonEnv, LT_ACCESS_KEY: 'key-2' }), + ), + daemonEnv, + ); + + assert.equal(outcome.allocations, 0); + assert.equal(outcome.error?.code, 'INVALID_ARGS'); + assert.equal(outcome.error?.details?.reason, 'provider-credentials-changed'); + assert.equal(outcome.error?.details?.provider, 'testmu'); +}); + +test('a daemon holding the TestMu AI credentials of the shell allocates', async () => { + const env = { ...testMuPluginEnv(), LT_USERNAME: 'user', LT_ACCESS_KEY: 'key-1' }; + const outcome = await allocateWithDaemonEnv( + providerAllocateRequest('testmu', providerCredentialFingerprint('testmu', env)), + env, + ); + + assert.equal(outcome.error, undefined); + assert.equal(outcome.allocations, 1); +}); + +test('a daemon started without TestMu AI credentials refuses a shell that has them', async () => { + const home = testMuPluginEnv(); + const outcome = await allocateWithDaemonEnv( + providerAllocateRequest( + 'testmu', + providerCredentialFingerprint('testmu', { + ...home, + LT_USERNAME: 'user', + LT_ACCESS_KEY: 'key-1', + }), + ), + home, + ); + + assert.equal(outcome.allocations, 0); + assert.equal(outcome.error?.details?.reason, 'provider-credentials-changed'); + assert.match(String(outcome.error?.message), /started without the testmu credentials/); +}); diff --git a/src/__tests__/daemon-composition/handlers/snapshot-handler-freshness.test.ts b/src/__tests__/daemon-composition/handlers/snapshot-handler-freshness.test.ts index c1a90ecaea..456c151e15 100644 --- a/src/__tests__/daemon-composition/handlers/snapshot-handler-freshness.test.ts +++ b/src/__tests__/daemon-composition/handlers/snapshot-handler-freshness.test.ts @@ -10,7 +10,7 @@ import { setActiveProviderDeviceRuntimes, } from '../../../provider-device-runtime.ts'; import { installProviderDeviceAdmission } from '../../../daemon/provider-device-admission.ts'; -import { testCreateCommandSurface } from '../../../daemon/__tests__/command-surface-fixture.ts'; +import { testCreateCommandSurface } from '../command-surface-fixture.ts'; // The daemon reads provider ownership through its own typed admission seam; production // installs it from root composition, and these tests compose it the same way. diff --git a/src/daemon/handlers/__tests__/snapshot-handler-wait.test.ts b/src/__tests__/daemon-composition/handlers/snapshot-handler-wait.test.ts similarity index 93% rename from src/daemon/handlers/__tests__/snapshot-handler-wait.test.ts rename to src/__tests__/daemon-composition/handlers/snapshot-handler-wait.test.ts index b77e688a98..f8ac888679 100644 --- a/src/daemon/handlers/__tests__/snapshot-handler-wait.test.ts +++ b/src/__tests__/daemon-composition/handlers/snapshot-handler-wait.test.ts @@ -1,22 +1,22 @@ import { test, expect, vi, afterEach, beforeEach } from 'vitest'; -import { legacyDispatchCapture } from '../../__tests__/legacy-snapshot-capture-fixture.ts'; -import { resetGetRuntimeFixture } from '../../__tests__/interaction-get-runtime-fixture.ts'; +import { legacyDispatchCapture } from '../../../daemon/__tests__/legacy-snapshot-capture-fixture.ts'; +import { resetGetRuntimeFixture } from '../../../daemon/__tests__/interaction-get-runtime-fixture.ts'; import { isActiveProviderDevice, setActiveProviderDeviceRuntimes, } from '../../../provider-device-runtime.ts'; -import { installProviderDeviceAdmission } from '../../provider-device-admission.ts'; -import { testCreateCommandSurface } from '../../__tests__/command-surface-fixture.ts'; +import { installProviderDeviceAdmission } from '../../../daemon/provider-device-admission.ts'; +import { testCreateCommandSurface } from '../command-surface-fixture.ts'; // The daemon reads provider ownership through its own typed admission seam; production // installs it from root composition, and these tests compose it the same way. installProviderDeviceAdmission({ isActive: isActiveProviderDevice }); -import type { SessionState } from '../../session-state.ts'; +import type { SessionState } from '../../../daemon/session-state.ts'; import { buildSnapshotPresentationKey } from '@agent-device/kernel/snapshot'; import { resetSnapshotRuntimeFixture, snapshotRuntimeFixture, -} from '../../__tests__/snapshot-runtime-fixture.ts'; +} from '../../../daemon/__tests__/snapshot-runtime-fixture.ts'; import { androidCapture, androidDevice, @@ -31,10 +31,10 @@ import { makeSession, makeSessionStore, snapshotRequest, -} from './snapshot-handler.fixtures.ts'; +} from '../../../daemon/handlers/__tests__/snapshot-handler.fixtures.ts'; -vi.mock('../../snapshot-interactor-capture.ts', async () => { - const fixture = await import('../../__tests__/legacy-snapshot-capture-fixture.ts'); +vi.mock('../../../daemon/snapshot-interactor-capture.ts', async () => { + const fixture = await import('../../../daemon/__tests__/legacy-snapshot-capture-fixture.ts'); return { captureSnapshotWithInteractor: fixture.captureSnapshotThroughLegacyDispatchFixture }; }); vi.mock('@agent-device/platform-apple/runner/operations', async (importOriginal) => { @@ -47,12 +47,12 @@ vi.mock('@agent-device/platform-apple/runner/operations', async (importOriginal) // unambiguous environment; that live-probe logic is covered by // ios-app-session-hint.test.ts. Stubbed here so this suite stays hermetic and // fast — defaults to "no enrichment", matching the current-behavior fallback. -vi.mock('../../ios-app-session-hint.ts', () => ({ +vi.mock('../../../daemon/ios-app-session-hint.ts', () => ({ buildIosOpenCommandHint: vi.fn(async () => undefined), })); import { runAppleRunnerCommand } from '@agent-device/platform-apple/runner/operations'; -import { buildIosOpenCommandHint } from '../../ios-app-session-hint.ts'; +import { buildIosOpenCommandHint } from '../../../daemon/ios-app-session-hint.ts'; const mockRunnerCommand = vi.mocked(runAppleRunnerCommand); const mockBuildIosOpenCommandHint = vi.mocked(buildIosOpenCommandHint); diff --git a/src/daemon/handlers/__tests__/snapshot-handler.test.ts b/src/__tests__/daemon-composition/handlers/snapshot-handler.test.ts similarity index 93% rename from src/daemon/handlers/__tests__/snapshot-handler.test.ts rename to src/__tests__/daemon-composition/handlers/snapshot-handler.test.ts index 6a85a194f6..8fc3e5ef25 100644 --- a/src/daemon/handlers/__tests__/snapshot-handler.test.ts +++ b/src/__tests__/daemon-composition/handlers/snapshot-handler.test.ts @@ -1,20 +1,20 @@ -import { daemonPlatformServicesFixture } from '../../__tests__/platform-services-fixture.ts'; +import { daemonPlatformServicesFixture } from '../../../daemon/__tests__/platform-services-fixture.ts'; import { test, expect, vi, afterEach, beforeEach } from 'vitest'; -import { legacyDispatchCapture } from '../../__tests__/legacy-snapshot-capture-fixture.ts'; -import { resetGetRuntimeFixture } from '../../__tests__/interaction-get-runtime-fixture.ts'; -import { resetSnapshotRuntimeFixture } from '../../__tests__/snapshot-runtime-fixture.ts'; +import { legacyDispatchCapture } from '../../../daemon/__tests__/legacy-snapshot-capture-fixture.ts'; +import { resetGetRuntimeFixture } from '../../../daemon/__tests__/interaction-get-runtime-fixture.ts'; +import { resetSnapshotRuntimeFixture } from '../../../daemon/__tests__/snapshot-runtime-fixture.ts'; import { isActiveProviderDevice, setActiveProviderDeviceRuntimes, } from '../../../provider-device-runtime.ts'; -import { installProviderDeviceAdmission } from '../../provider-device-admission.ts'; -import { testCreateCommandSurface } from '../../__tests__/command-surface-fixture.ts'; +import { installProviderDeviceAdmission } from '../../../daemon/provider-device-admission.ts'; +import { testCreateCommandSurface } from '../command-surface-fixture.ts'; // The daemon reads provider ownership through its own typed admission seam; production // installs it from root composition, and these tests compose it the same way. installProviderDeviceAdmission({ isActive: isActiveProviderDevice }); -import type { DaemonResponse } from '../../daemon-request.ts'; -import type { SessionState } from '../../session-state.ts'; +import type { DaemonResponse } from '../../../daemon/daemon-request.ts'; +import type { SessionState } from '../../../daemon/session-state.ts'; import { androidCapture, androidDevice, @@ -26,10 +26,10 @@ import { makeSessionStore, providerIosDevice, snapshotRequest, -} from './snapshot-handler.fixtures.ts'; +} from '../../../daemon/handlers/__tests__/snapshot-handler.fixtures.ts'; -vi.mock('../../snapshot-interactor-capture.ts', async () => { - const fixture = await import('../../__tests__/legacy-snapshot-capture-fixture.ts'); +vi.mock('../../../daemon/snapshot-interactor-capture.ts', async () => { + const fixture = await import('../../../daemon/__tests__/legacy-snapshot-capture-fixture.ts'); return { captureSnapshotWithInteractor: fixture.captureSnapshotThroughLegacyDispatchFixture }; }); vi.mock('@agent-device/platform-apple/runner/operations', async (importOriginal) => { @@ -42,13 +42,18 @@ vi.mock('@agent-device/platform-apple/runner/operations', async (importOriginal) // unambiguous environment; that live-probe logic is covered by // ios-app-session-hint.test.ts. Stubbed here so this suite stays hermetic and // fast — defaults to "no enrichment", matching the current-behavior fallback. -vi.mock('../../ios-app-session-hint.ts', () => ({ +vi.mock('../../../daemon/ios-app-session-hint.ts', () => ({ buildIosOpenCommandHint: vi.fn(async () => undefined), })); import { runAppleRunnerCommand } from '@agent-device/platform-apple/runner/operations'; -import { buildIosOpenCommandHint } from '../../ios-app-session-hint.ts'; -import { expireRefFrame, refFrame, refFrameState, refFrameTree } from '../../ref-frame.ts'; +import { buildIosOpenCommandHint } from '../../../daemon/ios-app-session-hint.ts'; +import { + expireRefFrame, + refFrame, + refFrameState, + refFrameTree, +} from '../../../daemon/ref-frame.ts'; const mockRunnerCommand = vi.mocked(runAppleRunnerCommand); const mockBuildIosOpenCommandHint = vi.mocked(buildIosOpenCommandHint); diff --git a/src/daemon/handlers/__tests__/snapshot-scoped-refs.test.ts b/src/__tests__/daemon-composition/handlers/snapshot-scoped-refs.test.ts similarity index 91% rename from src/daemon/handlers/__tests__/snapshot-scoped-refs.test.ts rename to src/__tests__/daemon-composition/handlers/snapshot-scoped-refs.test.ts index 55595e30fe..b8c02f6c65 100644 --- a/src/daemon/handlers/__tests__/snapshot-scoped-refs.test.ts +++ b/src/__tests__/daemon-composition/handlers/snapshot-scoped-refs.test.ts @@ -1,12 +1,12 @@ import { beforeEach, expect, test } from 'vitest'; -import { legacyDispatchCapture } from '../../__tests__/legacy-snapshot-capture-fixture.ts'; -import { handleSnapshotCommands as handleProductionSnapshotCommands } from '../snapshot.ts'; +import { legacyDispatchCapture } from '../../../daemon/__tests__/legacy-snapshot-capture-fixture.ts'; +import { handleSnapshotCommands as handleProductionSnapshotCommands } from '../../../daemon/handlers/snapshot.ts'; import type { RawSnapshotNode, SnapshotState } from '@agent-device/kernel/snapshot'; -import { makeAndroidSession } from '../../__tests__/support/session-factories.ts'; -import { makeSessionStore } from '../../__tests__/support/store-factory.ts'; -import { expireRefFrame } from '../../ref-frame.ts'; -import { snapshotRuntimeFixture } from '../../__tests__/snapshot-runtime-fixture.ts'; -import { testCreateCommandSurface } from '../../__tests__/command-surface-fixture.ts'; +import { makeAndroidSession } from '../../../daemon/__tests__/support/session-factories.ts'; +import { makeSessionStore } from '../../../daemon/__tests__/support/store-factory.ts'; +import { expireRefFrame } from '../../../daemon/ref-frame.ts'; +import { snapshotRuntimeFixture } from '../../../daemon/__tests__/snapshot-runtime-fixture.ts'; +import { testCreateCommandSurface } from '../command-surface-fixture.ts'; const ANDROID_SCRIPT_ERROR = 'Unable to load script. Make sure you are running Metro.'; diff --git a/src/daemon/handlers/__tests__/snapshot-session-cleanup.test.ts b/src/__tests__/daemon-composition/handlers/snapshot-session-cleanup.test.ts similarity index 94% rename from src/daemon/handlers/__tests__/snapshot-session-cleanup.test.ts rename to src/__tests__/daemon-composition/handlers/snapshot-session-cleanup.test.ts index 5c097b52c7..230644271e 100644 --- a/src/daemon/handlers/__tests__/snapshot-session-cleanup.test.ts +++ b/src/__tests__/daemon-composition/handlers/snapshot-session-cleanup.test.ts @@ -9,7 +9,7 @@ vi.mock('@agent-device/platform-apple/app-lifecycle', async (importOriginal) => closeIosApp: vi.fn(async () => {}), })); -import { withSessionlessRunnerCleanup } from '../../snapshot-session.ts'; +import { withSessionlessRunnerCleanup } from '../../../daemon/snapshot-session.ts'; import { platformResourceCleanup } from '../../../platform-runtime-resource-cleanup.ts'; import { closeIosApp } from '@agent-device/platform-apple/app-lifecycle'; import { stopIosRunnerSession } from '@agent-device/platform-apple/runner/operations'; @@ -18,7 +18,7 @@ import { isActiveProviderDevice, setActiveProviderDeviceRuntimes, } from '../../../provider-device-runtime.ts'; -import { installProviderDeviceAdmission } from '../../provider-device-admission.ts'; +import { installProviderDeviceAdmission } from '../../../daemon/provider-device-admission.ts'; // The daemon reads provider ownership through its own typed admission seam; production // installs it from root composition, and these tests compose it the same way. diff --git a/src/daemon/handlers/__tests__/wait-landmark-recording.test.ts b/src/__tests__/daemon-composition/handlers/wait-landmark-recording.test.ts similarity index 88% rename from src/daemon/handlers/__tests__/wait-landmark-recording.test.ts rename to src/__tests__/daemon-composition/handlers/wait-landmark-recording.test.ts index a5e1621394..38e625ef8a 100644 --- a/src/daemon/handlers/__tests__/wait-landmark-recording.test.ts +++ b/src/__tests__/daemon-composition/handlers/wait-landmark-recording.test.ts @@ -12,18 +12,18 @@ * `WAIT_LANDMARK_MISMATCH_REASON` refusal. */ import { test, expect, vi, beforeEach } from 'vitest'; -import { legacyDispatchCapture } from '../../__tests__/legacy-snapshot-capture-fixture.ts'; -import { dispatchWaitViaRuntime } from '../../wait-runtime.ts'; -import type { DaemonRequest } from '../../daemon-request.ts'; +import { legacyDispatchCapture } from '../../../daemon/__tests__/legacy-snapshot-capture-fixture.ts'; +import { dispatchWaitViaRuntime } from '../../../daemon/wait-runtime.ts'; +import type { DaemonRequest } from '../../../daemon/daemon-request.ts'; import { WAIT_LANDMARK_MISMATCH_REASON } from '@agent-device/contracts/replay'; import type { TargetAnnotationV1 } from '@agent-device/contracts/replay'; -import { snapshotRuntimeFixture } from '../../__tests__/snapshot-runtime-fixture.ts'; -import { makeSessionStore } from '../../__tests__/support/store-factory.ts'; +import { snapshotRuntimeFixture } from '../../../daemon/__tests__/snapshot-runtime-fixture.ts'; +import { makeSessionStore } from '../../../daemon/__tests__/support/store-factory.ts'; import { makeAndroidSession, authoringPublication, -} from '../../__tests__/support/session-factories.ts'; -import { testCreateCommandSurface } from '../../__tests__/command-surface-fixture.ts'; +} from '../../../daemon/__tests__/support/session-factories.ts'; +import { testCreateCommandSurface } from '../command-surface-fixture.ts'; vi.mock('@agent-device/device-selection/dispatch-resolve', async (importOriginal) => { const actual = @@ -34,12 +34,12 @@ vi.mock('@agent-device/device-selection/dispatch-resolve', async (importOriginal }; }); -vi.mock('../../snapshot-interactor-capture.ts', async () => { - const fixture = await import('../../__tests__/legacy-snapshot-capture-fixture.ts'); +vi.mock('../../../daemon/snapshot-interactor-capture.ts', async () => { + const fixture = await import('../../../daemon/__tests__/legacy-snapshot-capture-fixture.ts'); return { captureSnapshotWithInteractor: fixture.captureSnapshotThroughLegacyDispatchFixture }; }); -vi.mock('../../device/device-ready.ts', () => ({ +vi.mock('../../../daemon/device/device-ready.ts', () => ({ ensureDeviceReady: vi.fn(async () => {}), })); diff --git a/src/__tests__/daemon-composition/http-server-limrun-uploaded-apps.test.ts b/src/__tests__/daemon-composition/http-server-limrun-uploaded-apps.test.ts index 98a6130714..eec1b4e051 100644 --- a/src/__tests__/daemon-composition/http-server-limrun-uploaded-apps.test.ts +++ b/src/__tests__/daemon-composition/http-server-limrun-uploaded-apps.test.ts @@ -20,7 +20,7 @@ import { LeaseRegistry } from '../../daemon/lease-registry.ts'; import { createDaemonHttpServer } from '../../daemon/server/http-server.ts'; import { createRequestHandler } from '../../daemon/__tests__/test-device-runtime-gateway.ts'; import { mkdtempForTestSync } from '@agent-device/test-kit/tmp-dir'; -import { testCreateCommandSurface } from '../../daemon/__tests__/command-surface-fixture.ts'; +import { testCreateCommandSurface } from './command-surface-fixture.ts'; const limrunIo = vi.hoisted(() => ({ listAssets: vi.fn(), diff --git a/src/daemon/interaction/internal/__tests__/find-ambiguous-match.test.ts b/src/__tests__/daemon-composition/interaction/find-ambiguous-match.test.ts similarity index 91% rename from src/daemon/interaction/internal/__tests__/find-ambiguous-match.test.ts rename to src/__tests__/daemon-composition/interaction/find-ambiguous-match.test.ts index b16dad8350..3344438a1c 100644 --- a/src/daemon/interaction/internal/__tests__/find-ambiguous-match.test.ts +++ b/src/__tests__/daemon-composition/interaction/find-ambiguous-match.test.ts @@ -7,16 +7,17 @@ vi.mock('@agent-device/device-selection/dispatch-resolve', async (importOriginal resolveTargetDevice: actual.resolveTargetDevice, }; }); -vi.mock('../../../snapshot-interactor-capture.ts', async () => { - const fixture = await import('../../../__tests__/legacy-snapshot-capture-fixture.ts'); +vi.mock('../../../daemon/snapshot-interactor-capture.ts', async () => { + const fixture = await import('../../../daemon/__tests__/legacy-snapshot-capture-fixture.ts'); return { captureSnapshotWithInteractor: fixture.captureSnapshotThroughLegacyDispatchFixture }; }); import { resetFindTouchRuntimeFixture, runFindClickScenario, -} from './find-touch-runtime-fixture.ts'; -import { refFrameScope, refFrameState } from '../../../ref-frame.ts'; +} from '../../../daemon/interaction/internal/__tests__/find-touch-runtime-fixture.ts'; +import { testCreateCommandSurface } from '../command-surface-fixture.ts'; +import { refFrameScope, refFrameState } from '../../../daemon/ref-frame.ts'; beforeEach(() => { resetFindTouchRuntimeFixture(); @@ -39,6 +40,7 @@ test('handleFindCommands ambiguous match lists snapshot-line candidates capped a }); const { response } = await runFindClickScenario({ + createCommandSurface: testCreateCommandSurface, positionals: ['Follow', 'click'], nodes: [ { index: 0, ref: 'e1', type: 'Application', rect: { x: 0, y: 0, width: 800, height: 1200 } }, @@ -72,6 +74,7 @@ test('handleFindCommands ambiguous match lists snapshot-line candidates capped a test('handleFindCommands ambiguous match with few candidates lists them all uncapped', async () => { const { response } = await runFindClickScenario({ + createCommandSurface: testCreateCommandSurface, positionals: ['Follow', 'click'], nodes: [ { index: 0, ref: 'e1', type: 'Application', rect: { x: 0, y: 0, width: 800, height: 1200 } }, @@ -126,6 +129,7 @@ test('handleFindCommands list returns every match without acting', async () => { }); const { response, invokeCalls, session } = await runFindClickScenario({ + createCommandSurface: testCreateCommandSurface, positionals: ['text', 'Follow', 'list'], nodes: [ { index: 0, ref: 'e1', type: 'Application', rect: { x: 0, y: 0, width: 800, height: 1200 } }, @@ -152,6 +156,7 @@ test('handleFindCommands list returns every match without acting', async () => { test('handleFindCommands list on a unique match still lists instead of tapping', async () => { const { response, invokeCalls } = await runFindClickScenario({ + createCommandSurface: testCreateCommandSurface, positionals: ['Dictionary', 'list'], nodes: [ { index: 0, ref: 'e1', type: 'Application', rect: { x: 0, y: 0, width: 800, height: 1200 } }, @@ -190,6 +195,7 @@ test('handleFindCommands selector-shaped find rejects multiple matches with cand }); const { response, invokeCalls } = await runFindClickScenario({ + createCommandSurface: testCreateCommandSurface, positionals: ['role=button', 'click'], nodes: [ { index: 0, ref: 'e1', type: 'Application', rect: { x: 0, y: 0, width: 800, height: 1200 } }, @@ -219,6 +225,7 @@ test('handleFindCommands selector-shaped find honors the explicit --first opt-ou }); const { response, invokeCalls } = await runFindClickScenario({ + createCommandSurface: testCreateCommandSurface, positionals: ['role=button', 'click'], flags: { findFirst: true }, nodes: [ diff --git a/src/daemon/interaction/internal/__tests__/find-production-route.test.ts b/src/__tests__/daemon-composition/interaction/find-production-route.test.ts similarity index 88% rename from src/daemon/interaction/internal/__tests__/find-production-route.test.ts rename to src/__tests__/daemon-composition/interaction/find-production-route.test.ts index e9e412d6b6..c5352f6de8 100644 --- a/src/daemon/interaction/internal/__tests__/find-production-route.test.ts +++ b/src/__tests__/daemon-composition/interaction/find-production-route.test.ts @@ -1,10 +1,10 @@ import { test, expect, vi, beforeEach } from 'vitest'; -import { handleInteractionCommands } from '../../index.ts'; +import { handleInteractionCommands } from '../../../daemon/interaction/index.ts'; import type { CommandFlags } from '@agent-device/contracts/command'; -import type { DaemonRequest, DaemonResponse } from '../../../daemon-request.ts'; -import { makeSessionStore } from '../../../__tests__/support/store-factory.ts'; -import { makeIosSession as makeSession } from '../../../__tests__/support/session-factories.ts'; -import { testCreateCommandSurface } from '../../../__tests__/command-surface-fixture.ts'; +import type { DaemonRequest, DaemonResponse } from '../../../daemon/daemon-request.ts'; +import { makeSessionStore } from '../../../daemon/__tests__/support/store-factory.ts'; +import { makeIosSession as makeSession } from '../../../daemon/__tests__/support/session-factories.ts'; +import { testCreateCommandSurface } from '../command-surface-fixture.ts'; vi.mock('@agent-device/device-selection/dispatch-resolve', async (importOriginal) => { const actual = (await importOriginal()) as Record; @@ -13,8 +13,8 @@ vi.mock('@agent-device/device-selection/dispatch-resolve', async (importOriginal resolveTargetDevice: actual.resolveTargetDevice, }; }); -vi.mock('../../../snapshot-interactor-capture.ts', async () => { - const fixture = await import('../../../__tests__/legacy-snapshot-capture-fixture.ts'); +vi.mock('../../../daemon/snapshot-interactor-capture.ts', async () => { + const fixture = await import('../../../daemon/__tests__/legacy-snapshot-capture-fixture.ts'); return { captureSnapshotWithInteractor: fixture.captureSnapshotThroughLegacyDispatchFixture }; }); @@ -22,8 +22,8 @@ import { findTouchRuntimeBindings, mockDispatch, resetFindTouchRuntimeFixture, -} from './find-touch-runtime-fixture.ts'; -import { invokeFindHandler } from './find-handler-fixture.ts'; +} from '../../../daemon/interaction/internal/__tests__/find-touch-runtime-fixture.ts'; +import { invokeFindHandler } from '../../../daemon/interaction/internal/__tests__/find-handler-fixture.ts'; beforeEach(() => { resetFindTouchRuntimeFixture(); @@ -102,6 +102,7 @@ async function runFindThroughLeaf(options: { const invokeCalls: DaemonRequest[] = []; const response = await invokeFindHandler({ + createCommandSurface: testCreateCommandSurface, sessionName, sessionStore, positionals: options.positionals, diff --git a/src/daemon/interaction/internal/__tests__/find-read-only.test.ts b/src/__tests__/daemon-composition/interaction/find-read-only.test.ts similarity index 88% rename from src/daemon/interaction/internal/__tests__/find-read-only.test.ts rename to src/__tests__/daemon-composition/interaction/find-read-only.test.ts index e2c3a38b0a..80cb0ea335 100644 --- a/src/daemon/interaction/internal/__tests__/find-read-only.test.ts +++ b/src/__tests__/daemon-composition/interaction/find-read-only.test.ts @@ -1,11 +1,11 @@ import { test, expect, vi, beforeEach } from 'vitest'; -import type { SessionState } from '../../../session-state.ts'; +import type { SessionState } from '../../../daemon/session-state.ts'; import { buildSnapshotSignatures } from '@agent-device/capture-kit/snapshot-freshness'; -import { makeSessionStore } from '../../../__tests__/support/store-factory.ts'; +import { makeSessionStore } from '../../../daemon/__tests__/support/store-factory.ts'; import { makeAuthoringSession, makeIosSession as makeSession, -} from '../../../__tests__/support/session-factories.ts'; +} from '../../../daemon/__tests__/support/session-factories.ts'; vi.mock('@agent-device/device-selection/dispatch-resolve', async (importOriginal) => { const actual = (await importOriginal()) as Record; @@ -14,8 +14,8 @@ vi.mock('@agent-device/device-selection/dispatch-resolve', async (importOriginal resolveTargetDevice: actual.resolveTargetDevice, }; }); -vi.mock('../../../snapshot-interactor-capture.ts', async () => { - const fixture = await import('../../../__tests__/legacy-snapshot-capture-fixture.ts'); +vi.mock('../../../daemon/snapshot-interactor-capture.ts', async () => { + const fixture = await import('../../../daemon/__tests__/legacy-snapshot-capture-fixture.ts'); return { captureSnapshotWithInteractor: fixture.captureSnapshotThroughLegacyDispatchFixture }; }); @@ -23,8 +23,9 @@ import { mockDispatch, resetFindTouchRuntimeFixture, runFindClickScenario, -} from './find-touch-runtime-fixture.ts'; -import { invokeFindHandler } from './find-handler-fixture.ts'; +} from '../../../daemon/interaction/internal/__tests__/find-touch-runtime-fixture.ts'; +import { testCreateCommandSurface } from '../command-surface-fixture.ts'; +import { invokeFindHandler } from '../../../daemon/interaction/internal/__tests__/find-handler-fixture.ts'; beforeEach(() => { resetFindTouchRuntimeFixture(); @@ -89,6 +90,7 @@ test('handleFindCommands wait bypasses snapshot cache while Android freshness re }); const { response } = await runFindClickScenario({ + createCommandSurface: testCreateCommandSurface, positionals: ['text', 'Create document', 'wait', '700'], session, }); @@ -136,6 +138,7 @@ test('handleFindCommands wait reports sparse verdict through selector runtime ro }); const { response } = await runFindClickScenario({ + createCommandSurface: testCreateCommandSurface, positionals: ['text', 'Never appears', 'wait', '350'], session, }); @@ -154,6 +157,7 @@ test('handleFindCommands wait reports sparse verdict through selector runtime ro test('handleFindCommands wait captures fresh snapshots while polling', async () => { const { response } = await runFindClickScenario({ + createCommandSurface: testCreateCommandSurface, positionals: ['text', 'Never appears', 'wait', '350'], nodes: [{ index: 0, depth: 0, type: 'StaticText', label: 'Other text' }], }); @@ -196,6 +200,7 @@ test('read-only find while recording is intentionally deferred from target-v1 ev }); const response = await invokeFindHandler({ + createCommandSurface: testCreateCommandSurface, sessionName, sessionStore, positionals: ['text', 'Save', 'exists'], diff --git a/src/daemon/interaction/internal/__tests__/interaction-capture-disclosure.test.ts b/src/__tests__/daemon-composition/interaction/interaction-capture-disclosure.test.ts similarity index 89% rename from src/daemon/interaction/internal/__tests__/interaction-capture-disclosure.test.ts rename to src/__tests__/daemon-composition/interaction/interaction-capture-disclosure.test.ts index 5f141592e8..3be6ee7bfc 100644 --- a/src/daemon/interaction/internal/__tests__/interaction-capture-disclosure.test.ts +++ b/src/__tests__/daemon-composition/interaction/interaction-capture-disclosure.test.ts @@ -6,17 +6,20 @@ import { type SnapshotState, } from '@agent-device/kernel/snapshot'; import { iosTargetActivationDisclosure } from '@agent-device/contracts/ios-target-activation'; -import { makeSessionStore } from '../../../__tests__/support/store-factory.ts'; -import { handleInteractionCommands } from '../../index.ts'; -import { getRuntimeBindings } from '../../../__tests__/interaction-get-runtime-fixture.ts'; -import { contextFromFlags, makeSession } from './interaction-touch-fixtures.ts'; -import { legacyDispatchCapture } from '../../../__tests__/legacy-snapshot-capture-fixture.ts'; -import { markDeferredInteractionOutcome } from '../../../deferred-interaction-outcome.ts'; +import { makeSessionStore } from '../../../daemon/__tests__/support/store-factory.ts'; +import { handleInteractionCommands } from '../../../daemon/interaction/index.ts'; +import { getRuntimeBindings } from '../../../daemon/__tests__/interaction-get-runtime-fixture.ts'; +import { + contextFromFlags, + makeSession, +} from '../../../daemon/interaction/internal/__tests__/interaction-touch-fixtures.ts'; +import { legacyDispatchCapture } from '../../../daemon/__tests__/legacy-snapshot-capture-fixture.ts'; +import { markDeferredInteractionOutcome } from '../../../daemon/deferred-interaction-outcome.ts'; import { formatPostGestureOutcomeWarning } from '@agent-device/capture-kit/post-gesture-stability'; -import { testCreateCommandSurface } from '../../../__tests__/command-surface-fixture.ts'; +import { testCreateCommandSurface } from '../command-surface-fixture.ts'; -vi.mock('../../../snapshot-interactor-capture.ts', async () => { - const fixture = await import('../../../__tests__/legacy-snapshot-capture-fixture.ts'); +vi.mock('../../../daemon/snapshot-interactor-capture.ts', async () => { + const fixture = await import('../../../daemon/__tests__/legacy-snapshot-capture-fixture.ts'); return { captureSnapshotWithInteractor: fixture.captureSnapshotThroughLegacyDispatchFixture }; }); diff --git a/src/daemon/interaction/internal/__tests__/interaction-common.test.ts b/src/__tests__/daemon-composition/interaction/interaction-common.test.ts similarity index 94% rename from src/daemon/interaction/internal/__tests__/interaction-common.test.ts rename to src/__tests__/daemon-composition/interaction/interaction-common.test.ts index 9e1a9e4496..4aea4698bf 100644 --- a/src/daemon/interaction/internal/__tests__/interaction-common.test.ts +++ b/src/__tests__/daemon-composition/interaction/interaction-common.test.ts @@ -1,21 +1,24 @@ import type { CommandFlags } from '@agent-device/contracts/command'; -import { legacyDispatchCapture } from '../../../__tests__/legacy-snapshot-capture-fixture.ts'; +import { legacyDispatchCapture } from '../../../daemon/__tests__/legacy-snapshot-capture-fixture.ts'; import { beforeEach, expect, test } from 'vitest'; import { makeIosSession, makeAuthoringSession, authoringPublication, -} from '../../../__tests__/support/session-factories.ts'; -import { makeSessionStore } from '../../../__tests__/support/store-factory.ts'; +} from '../../../daemon/__tests__/support/session-factories.ts'; +import { makeSessionStore } from '../../../daemon/__tests__/support/store-factory.ts'; import { attachRefs, type RawSnapshotNode } from '@agent-device/kernel/snapshot'; -import { finalizeTouchInteraction, handleInteractionCommands } from '../../index.ts'; +import { + finalizeTouchInteraction, + handleInteractionCommands, +} from '../../../daemon/interaction/index.ts'; import { IOS_SIMULATOR } from '@agent-device/test-kit/device-fixtures'; import { getRuntimeBindings, mockFillPoint, resetGetRuntimeFixture, -} from '../../../__tests__/interaction-get-runtime-fixture.ts'; -import { testCreateCommandSurface } from '../../../__tests__/command-surface-fixture.ts'; +} from '../../../daemon/__tests__/interaction-get-runtime-fixture.ts'; +import { testCreateCommandSurface } from '../command-surface-fixture.ts'; const contextFromFlags = (_flags: CommandFlags | undefined) => ({}); diff --git a/src/daemon/interaction/internal/__tests__/interaction-dispatch-disclosure.test.ts b/src/__tests__/daemon-composition/interaction/interaction-dispatch-disclosure.test.ts similarity index 91% rename from src/daemon/interaction/internal/__tests__/interaction-dispatch-disclosure.test.ts rename to src/__tests__/daemon-composition/interaction/interaction-dispatch-disclosure.test.ts index 97907e2a0d..b1cea82bbf 100644 --- a/src/daemon/interaction/internal/__tests__/interaction-dispatch-disclosure.test.ts +++ b/src/__tests__/daemon-composition/interaction/interaction-dispatch-disclosure.test.ts @@ -1,4 +1,4 @@ -import { daemonPlatformServicesFixture } from '../../../__tests__/platform-services-fixture.ts'; +import { daemonPlatformServicesFixture } from '../../../daemon/__tests__/platform-services-fixture.ts'; import assert from 'node:assert/strict'; import fs from 'node:fs'; import { beforeEach, test, vi } from 'vitest'; @@ -10,39 +10,39 @@ import { DISPATCH_DISCLOSURE_TABLE_PATH, dispatchDisclosureRowsOwnedBy, } from '@agent-device/contracts/dispatch-disclosure-fixtures'; -import { makeSessionStore } from '../../../__tests__/support/store-factory.ts'; -import { makeAndroidSession } from '../../../__tests__/support/session-factories.ts'; +import { makeSessionStore } from '../../../daemon/__tests__/support/store-factory.ts'; +import { makeAndroidSession } from '../../../daemon/__tests__/support/session-factories.ts'; import { getRuntimeBindings, mockFillPoint, mockTapPoint, resetGetRuntimeFixture, -} from '../../../__tests__/interaction-get-runtime-fixture.ts'; -import { captureSnapshotWithInteractor } from '../../../snapshot-interactor-capture.ts'; -import { discloseRequestDispatch } from '../../../request-dispatch-disclosure.ts'; +} from '../../../daemon/__tests__/interaction-get-runtime-fixture.ts'; +import { captureSnapshotWithInteractor } from '../../../daemon/snapshot-interactor-capture.ts'; +import { discloseRequestDispatch } from '../../../daemon/request-dispatch-disclosure.ts'; import { createRequestDispatchLedger, recordBoundMutations, -} from '../../../request-dispatch-ledger.ts'; -import type { BindDeviceRuntime } from '../../../request-runtime-binding.ts'; -import { clearAndroidObservationFixture } from '../../../__tests__/android-observation-fixture.ts'; -import { activateCompleteRefFrame, expireRefFrame } from '../../../ref-frame.ts'; -import { handleInteractionCommands } from '../../index.ts'; -import type { InteractionRouteInput } from '../types.ts'; -import { assertAndroidPressStayedInApp } from '../interaction-android-escape.ts'; -import { gestureRuntimeBindingsFixture } from './gesture-runtime-bindings.fixtures.ts'; +} from '../../../daemon/request-dispatch-ledger.ts'; +import type { BindDeviceRuntime } from '../../../daemon/request-runtime-binding.ts'; +import { clearAndroidObservationFixture } from '../../../daemon/__tests__/android-observation-fixture.ts'; +import { activateCompleteRefFrame, expireRefFrame } from '../../../daemon/ref-frame.ts'; +import { handleInteractionCommands } from '../../../daemon/interaction/index.ts'; +import type { InteractionRouteInput } from '../../../daemon/interaction/internal/types.ts'; +import { assertAndroidPressStayedInApp } from '../../../daemon/interaction/internal/interaction-android-escape.ts'; +import { gestureRuntimeBindingsFixture } from '../../../daemon/interaction/internal/__tests__/gesture-runtime-bindings.fixtures.ts'; import { contextFromFlags, makeSession, makeStaleRefSession, -} from './interaction-touch-fixtures.ts'; -import { testCreateCommandSurface } from '../../../__tests__/command-surface-fixture.ts'; +} from '../../../daemon/interaction/internal/__tests__/interaction-touch-fixtures.ts'; +import { testCreateCommandSurface } from '../command-surface-fixture.ts'; // contracts/fixtures/dispatch-disclosure.json, daemon and post-action guard rows: the daemon rows // drive a real `press` through the daemon interaction handler, inside the router's dispatch seam, // with only the device touch mocked; the guard row drives the guard itself. -vi.mock('../../../snapshot-interactor-capture.ts', () => ({ +vi.mock('../../../daemon/snapshot-interactor-capture.ts', () => ({ captureSnapshotWithInteractor: vi.fn(), })); diff --git a/src/daemon/interaction/internal/__tests__/interaction-gesture-drag.test.ts b/src/__tests__/daemon-composition/interaction/interaction-gesture-drag.test.ts similarity index 88% rename from src/daemon/interaction/internal/__tests__/interaction-gesture-drag.test.ts rename to src/__tests__/daemon-composition/interaction/interaction-gesture-drag.test.ts index 79f43740fe..c19b200dea 100644 --- a/src/daemon/interaction/internal/__tests__/interaction-gesture-drag.test.ts +++ b/src/__tests__/daemon-composition/interaction/interaction-gesture-drag.test.ts @@ -1,21 +1,21 @@ -import { daemonPlatformServicesFixture } from '../../../__tests__/platform-services-fixture.ts'; +import { daemonPlatformServicesFixture } from '../../../daemon/__tests__/platform-services-fixture.ts'; import { beforeEach, expect, test } from 'vitest'; import { attachRefs } from '@agent-device/kernel/snapshot'; import { makeIosSession, authoringPublication, -} from '../../../__tests__/support/session-factories.ts'; -import { makeSessionStore } from '../../../__tests__/support/store-factory.ts'; -import { activateCompleteRefFrame, refFrameState } from '../../../ref-frame.ts'; +} from '../../../daemon/__tests__/support/session-factories.ts'; +import { makeSessionStore } from '../../../daemon/__tests__/support/store-factory.ts'; +import { activateCompleteRefFrame, refFrameState } from '../../../daemon/ref-frame.ts'; -import { handleInteractionCommands } from '../../index.ts'; -import { gestureRuntimeBindingsFixture } from './gesture-runtime-bindings.fixtures.ts'; -import { testCreateCommandSurface } from '../../../__tests__/command-surface-fixture.ts'; +import { handleInteractionCommands } from '../../../daemon/interaction/index.ts'; +import { gestureRuntimeBindingsFixture } from '../../../daemon/interaction/internal/__tests__/gesture-runtime-bindings.fixtures.ts'; +import { testCreateCommandSurface } from '../command-surface-fixture.ts'; const contextFromFlags = () => ({}); const captureSnapshotForSession = async ({ session, -}: import('../../../session-state.ts').SessionRef) => session.snapshot!; +}: import('../../../daemon/session-state.ts').SessionRef) => session.snapshot!; let gestures = gestureRuntimeBindingsFixture(); beforeEach(() => { diff --git a/src/daemon/interaction/internal/__tests__/interaction-get.test.ts b/src/__tests__/daemon-composition/interaction/interaction-get.test.ts similarity index 96% rename from src/daemon/interaction/internal/__tests__/interaction-get.test.ts rename to src/__tests__/daemon-composition/interaction/interaction-get.test.ts index a731babfae..fce694bd3d 100644 --- a/src/daemon/interaction/internal/__tests__/interaction-get.test.ts +++ b/src/__tests__/daemon-composition/interaction/interaction-get.test.ts @@ -1,24 +1,27 @@ import { test, expect, vi, beforeEach } from 'vitest'; -import { legacyDispatchCapture } from '../../../__tests__/legacy-snapshot-capture-fixture.ts'; +import { legacyDispatchCapture } from '../../../daemon/__tests__/legacy-snapshot-capture-fixture.ts'; import { attachRefs } from '@agent-device/kernel/snapshot'; import { WEB_DESKTOP_DEVICE } from '@agent-device/test-kit/device-fixtures'; import { makeAndroidSession as makeBaseAndroidSession, makeIosSession, -} from '../../../__tests__/support/session-factories.ts'; -import { makeSessionStore } from '../../../__tests__/support/store-factory.ts'; -import { expireRefFrame } from '../../../ref-frame.ts'; -import { setSessionSnapshot, STALE_SNAPSHOT_REFS_WARNING } from '../../../session-snapshot.ts'; -import { handleInteractionCommands } from '../../index.ts'; +} from '../../../daemon/__tests__/support/session-factories.ts'; +import { makeSessionStore } from '../../../daemon/__tests__/support/store-factory.ts'; +import { expireRefFrame } from '../../../daemon/ref-frame.ts'; +import { + setSessionSnapshot, + STALE_SNAPSHOT_REFS_WARNING, +} from '../../../daemon/session-snapshot.ts'; +import { handleInteractionCommands } from '../../../daemon/interaction/index.ts'; import { buildSnapshotState } from '@agent-device/capture-kit/snapshot-state'; import { contextFromFlags, makeSession, makeStaleRefSession, makeVisibleButtonSnapshot, - runInteraction, -} from './interaction-touch-fixtures.ts'; -import { testCreateCommandSurface } from '../../../__tests__/command-surface-fixture.ts'; +} from '../../../daemon/interaction/internal/__tests__/interaction-touch-fixtures.ts'; +import { runInteraction } from './interaction-touch-runner.ts'; +import { testCreateCommandSurface } from '../command-surface-fixture.ts'; // Non-touch interaction routing: the `get` and `is` reads the public handler // owns. Touch commands live in the interaction-touch* test files. @@ -27,8 +30,8 @@ const { mockRunAppleRunnerCommand } = vi.hoisted(() => ({ mockRunAppleRunnerCommand: vi.fn(), })); -vi.mock('../../../snapshot-interactor-capture.ts', async () => { - const fixture = await import('../../../__tests__/legacy-snapshot-capture-fixture.ts'); +vi.mock('../../../daemon/snapshot-interactor-capture.ts', async () => { + const fixture = await import('../../../daemon/__tests__/legacy-snapshot-capture-fixture.ts'); return { captureSnapshotWithInteractor: fixture.captureSnapshotThroughLegacyDispatchFixture }; }); @@ -56,7 +59,7 @@ import { getRuntimeBindings, mockReadTextAtPoint, resetGetRuntimeFixture, -} from '../../../__tests__/interaction-get-runtime-fixture.ts'; +} from '../../../daemon/__tests__/interaction-get-runtime-fixture.ts'; import { getAndroidAppState, getAndroidBlockingDialogObservation, diff --git a/src/daemon/interaction/internal/__tests__/interaction-ios-tap-outcome.test.ts b/src/__tests__/daemon-composition/interaction/interaction-ios-tap-outcome.test.ts similarity index 95% rename from src/daemon/interaction/internal/__tests__/interaction-ios-tap-outcome.test.ts rename to src/__tests__/daemon-composition/interaction/interaction-ios-tap-outcome.test.ts index eafa297b90..8cc4d79428 100644 --- a/src/daemon/interaction/internal/__tests__/interaction-ios-tap-outcome.test.ts +++ b/src/__tests__/daemon-composition/interaction/interaction-ios-tap-outcome.test.ts @@ -1,5 +1,5 @@ import type { CommandFlags } from '@agent-device/contracts/command'; -import { legacyDispatchCapture } from '../../../__tests__/legacy-snapshot-capture-fixture.ts'; +import { legacyDispatchCapture } from '../../../daemon/__tests__/legacy-snapshot-capture-fixture.ts'; import { beforeEach, expect, test, vi } from 'vitest'; import fs from 'node:fs'; @@ -7,40 +7,40 @@ import path from 'node:path'; import { AppError } from '@agent-device/kernel/errors'; import { buildSnapshotPresentationKey } from '@agent-device/kernel/snapshot'; import { buildSnapshotState } from '@agent-device/capture-kit/snapshot-state'; -import { handleInteractionCommands } from '../../index.ts'; +import { handleInteractionCommands } from '../../../daemon/interaction/index.ts'; import { makeIosSession, authoringPublication, -} from '../../../__tests__/support/session-factories.ts'; -import { makeSessionStore } from '../../../__tests__/support/store-factory.ts'; -import { SessionScriptWriter } from '../../../session-script-writer.ts'; -import { runReplayForTest } from '../../../__tests__/replay-runtime/replay-command-fixture.ts'; -import { replayScriptSourceBundleFor } from '../../../../__tests__/test-utils/replay-script-source.ts'; +} from '../../../daemon/__tests__/support/session-factories.ts'; +import { makeSessionStore } from '../../../daemon/__tests__/support/store-factory.ts'; +import { SessionScriptWriter } from '../../../daemon/session-script-writer.ts'; +import { runReplayForTest } from '../../../daemon/__tests__/replay-runtime/replay-command-fixture.ts'; +import { replayScriptSourceBundleFor } from '../../test-utils/replay-script-source.ts'; import { imageViewerNodes, profileNodes, snapshot, snapshotPayload, -} from './interaction-ios-tap-outcome-fixtures.ts'; +} from '../../../daemon/interaction/internal/__tests__/interaction-ios-tap-outcome-fixtures.ts'; import { appCaptureComparisonIdentity, appCaptureComparisonKey, systemSurfaceCaptureComparisonKey, -} from '../../../__tests__/ios-comparison-key-fixture.ts'; +} from '../../../daemon/__tests__/ios-comparison-key-fixture.ts'; import { IOS_SIMULATOR } from '@agent-device/test-kit/device-fixtures'; import { getRuntimeBindings, mockTapPoint, resetGetRuntimeFixture, -} from '../../../__tests__/interaction-get-runtime-fixture.ts'; -import { captureSnapshotWithInteractor } from '../../../snapshot-interactor-capture.ts'; -import { corroborateIosTapFailure } from '../interaction-ios-tap-outcome.ts'; -import { movingTargetBaseline } from '../../../deferred-interaction-outcome.ts'; +} from '../../../daemon/__tests__/interaction-get-runtime-fixture.ts'; +import { captureSnapshotWithInteractor } from '../../../daemon/snapshot-interactor-capture.ts'; +import { corroborateIosTapFailure } from '../../../daemon/interaction/internal/interaction-ios-tap-outcome.ts'; +import { movingTargetBaseline } from '../../../daemon/deferred-interaction-outcome.ts'; import { mkdtempForTestSync } from '@agent-device/test-kit/tmp-dir'; -import { testCreateCommandSurface } from '../../../__tests__/command-surface-fixture.ts'; +import { testCreateCommandSurface } from '../command-surface-fixture.ts'; -vi.mock('../../../snapshot-interactor-capture.ts', async () => { - const fixture = await import('../../../__tests__/legacy-snapshot-capture-fixture.ts'); +vi.mock('../../../daemon/snapshot-interactor-capture.ts', async () => { + const fixture = await import('../../../daemon/__tests__/legacy-snapshot-capture-fixture.ts'); return { captureSnapshotWithInteractor: vi.fn(fixture.captureSnapshotThroughLegacyDispatchFixture), }; diff --git a/src/__tests__/daemon-composition/interaction/interaction-settle-private-ax-route.test.ts b/src/__tests__/daemon-composition/interaction/interaction-settle-private-ax-route.test.ts index 68f063778a..9171418dda 100644 --- a/src/__tests__/daemon-composition/interaction/interaction-settle-private-ax-route.test.ts +++ b/src/__tests__/daemon-composition/interaction/interaction-settle-private-ax-route.test.ts @@ -8,7 +8,7 @@ import { handleInteractionCommands } from '../../../daemon/interaction/index.ts' import { getRuntimeBindings } from '../../../daemon/__tests__/interaction-get-runtime-fixture.ts'; import { getInteractor } from '../../../core/interactors.ts'; import { installInteractorResolution } from '../../../daemon/interactor-resolution.ts'; -import { testCreateCommandSurface } from '../../../daemon/__tests__/command-surface-fixture.ts'; +import { testCreateCommandSurface } from '../command-surface-fixture.ts'; // Root composition hands the daemon its interactor resolution; this test drives the real // settle capture, so it composes the real lookup the way the process root does. diff --git a/src/daemon/interaction/internal/__tests__/interaction-settle.test.ts b/src/__tests__/daemon-composition/interaction/interaction-settle.test.ts similarity index 94% rename from src/daemon/interaction/internal/__tests__/interaction-settle.test.ts rename to src/__tests__/daemon-composition/interaction/interaction-settle.test.ts index 42da9e3006..0f5a4f51ef 100644 --- a/src/daemon/interaction/internal/__tests__/interaction-settle.test.ts +++ b/src/__tests__/daemon-composition/interaction/interaction-settle.test.ts @@ -1,21 +1,24 @@ -import { daemonPlatformServicesFixture } from '../../../__tests__/platform-services-fixture.ts'; +import { daemonPlatformServicesFixture } from '../../../daemon/__tests__/platform-services-fixture.ts'; import type { CommandFlags } from '@agent-device/contracts/command'; -import { legacyDispatchCapture } from '../../../__tests__/legacy-snapshot-capture-fixture.ts'; +import { legacyDispatchCapture } from '../../../daemon/__tests__/legacy-snapshot-capture-fixture.ts'; import { test, expect, vi, beforeEach } from 'vitest'; -import { createInteractionRuntime, handleInteractionCommands } from '../../index.ts'; -import type { SessionStore } from '../../../session-store.ts'; -import type { SessionRef, SessionState } from '../../../session-state.ts'; +import { + createInteractionRuntime, + handleInteractionCommands, +} from '../../../daemon/interaction/index.ts'; +import type { SessionStore } from '../../../daemon/session-store.ts'; +import type { SessionRef, SessionState } from '../../../daemon/session-state.ts'; import { buildSnapshotState } from '@agent-device/capture-kit/snapshot-state'; -import { setSessionSnapshot } from '../../../session-snapshot.ts'; +import { setSessionSnapshot } from '../../../daemon/session-snapshot.ts'; import { activateCompleteRefFrame, expireRefFrame, refFrameState, refFrameTree, -} from '../../../ref-frame.ts'; -import { captureSnapshotWithInteractor } from '../../../snapshot-interactor-capture.ts'; -import { makeSessionStore } from '../../../__tests__/support/store-factory.ts'; -import { makeIosSession } from '../../../__tests__/support/session-factories.ts'; +} from '../../../daemon/ref-frame.ts'; +import { captureSnapshotWithInteractor } from '../../../daemon/snapshot-interactor-capture.ts'; +import { makeSessionStore } from '../../../daemon/__tests__/support/store-factory.ts'; +import { makeIosSession } from '../../../daemon/__tests__/support/session-factories.ts'; import { clearRequestAbortRegistration, registerRequestAbort, @@ -26,8 +29,8 @@ import { mockFillPoint, mockTapPoint, resetGetRuntimeFixture, -} from '../../../__tests__/interaction-get-runtime-fixture.ts'; -import { testCreateCommandSurface } from '../../../__tests__/command-surface-fixture.ts'; +} from '../../../daemon/__tests__/interaction-get-runtime-fixture.ts'; +import { testCreateCommandSurface } from '../command-surface-fixture.ts'; // #1101 --settle daemon response shape: the settle payload (diff + settled + // refsGeneration) rides the wire response through the shared builder, and a @@ -36,7 +39,7 @@ import { testCreateCommandSurface } from '../../../__tests__/command-surface-fix // beyond a few poll ticks. const mockCaptureSnapshotForSession = vi.hoisted(() => vi.fn()); -vi.mock('../../../snapshot-interactor-capture.ts', () => ({ +vi.mock('../../../daemon/snapshot-interactor-capture.ts', () => ({ captureSnapshotWithInteractor: vi.fn(), })); const nativeCapture = vi.mocked(captureSnapshotWithInteractor); diff --git a/src/daemon/interaction/internal/__tests__/interaction-target-evidence.test.ts b/src/__tests__/daemon-composition/interaction/interaction-target-evidence.test.ts similarity index 95% rename from src/daemon/interaction/internal/__tests__/interaction-target-evidence.test.ts rename to src/__tests__/daemon-composition/interaction/interaction-target-evidence.test.ts index bf8c836372..9f58f7a4a7 100644 --- a/src/daemon/interaction/internal/__tests__/interaction-target-evidence.test.ts +++ b/src/__tests__/daemon-composition/interaction/interaction-target-evidence.test.ts @@ -1,20 +1,20 @@ import type { CommandFlags } from '@agent-device/contracts/command'; -import { legacyDispatchCapture } from '../../../__tests__/legacy-snapshot-capture-fixture.ts'; +import { legacyDispatchCapture } from '../../../daemon/__tests__/legacy-snapshot-capture-fixture.ts'; import { test, expect, vi, beforeEach } from 'vitest'; import fs from 'node:fs'; import path from 'node:path'; -import { handleInteractionCommands } from '../../index.ts'; +import { handleInteractionCommands } from '../../../daemon/interaction/index.ts'; import { attachRefs, type RawSnapshotNode } from '@agent-device/kernel/snapshot'; -import { makeSessionStore } from '../../../__tests__/support/store-factory.ts'; +import { makeSessionStore } from '../../../daemon/__tests__/support/store-factory.ts'; import { makeIosSession, makeAuthoringSession, authoringPublication, -} from '../../../__tests__/support/session-factories.ts'; -import { SessionScriptWriter } from '../../../session-script-writer.ts'; -import type { SessionState } from '../../../session-state.ts'; +} from '../../../daemon/__tests__/support/session-factories.ts'; +import { SessionScriptWriter } from '../../../daemon/session-script-writer.ts'; +import type { SessionState } from '../../../daemon/session-state.ts'; import { mkdtempForTestSync } from '@agent-device/test-kit/tmp-dir'; -import { testCreateCommandSurface } from '../../../__tests__/command-surface-fixture.ts'; +import { testCreateCommandSurface } from '../command-surface-fixture.ts'; // ADR 0012 decision 3, daemon-routed recording: target-v1 evidence is // computed only while the session is being recorded, lands on the recorded @@ -27,8 +27,8 @@ const { mockRunAppleRunnerCommand } = vi.hoisted(() => ({ mockRunAppleRunnerCommand: vi.fn(), })); -vi.mock('../../../snapshot-interactor-capture.ts', async () => { - const fixture = await import('../../../__tests__/legacy-snapshot-capture-fixture.ts'); +vi.mock('../../../daemon/snapshot-interactor-capture.ts', async () => { + const fixture = await import('../../../daemon/__tests__/legacy-snapshot-capture-fixture.ts'); return { captureSnapshotWithInteractor: fixture.captureSnapshotThroughLegacyDispatchFixture }; }); @@ -44,7 +44,7 @@ vi.mock('@agent-device/platform-apple/runner/operations', async (importOriginal) import { getRuntimeBindings, resetGetRuntimeFixture, -} from '../../../__tests__/interaction-get-runtime-fixture.ts'; +} from '../../../daemon/__tests__/interaction-get-runtime-fixture.ts'; const contextFromFlags = (_flags: CommandFlags | undefined) => ({}); beforeEach(() => { diff --git a/src/daemon/interaction/internal/__tests__/interaction-touch-android-freshness.test.ts b/src/__tests__/daemon-composition/interaction/interaction-touch-android-freshness.test.ts similarity index 93% rename from src/daemon/interaction/internal/__tests__/interaction-touch-android-freshness.test.ts rename to src/__tests__/daemon-composition/interaction/interaction-touch-android-freshness.test.ts index 75dea53d2f..298e4d9e12 100644 --- a/src/daemon/interaction/internal/__tests__/interaction-touch-android-freshness.test.ts +++ b/src/__tests__/daemon-composition/interaction/interaction-touch-android-freshness.test.ts @@ -1,14 +1,17 @@ import { test, expect, vi, beforeEach } from 'vitest'; import { attachRefs } from '@agent-device/kernel/snapshot'; -import { makeSessionStore } from '../../../__tests__/support/store-factory.ts'; -import { handleInteractionCommands } from '../../index.ts'; +import { makeSessionStore } from '../../../daemon/__tests__/support/store-factory.ts'; +import { handleInteractionCommands } from '../../../daemon/interaction/index.ts'; import { getRuntimeBindings, mockTapPoint, resetGetRuntimeFixture, -} from '../../../__tests__/interaction-get-runtime-fixture.ts'; -import { contextFromFlags, makeAndroidSession } from './interaction-touch-fixtures.ts'; -import { testCreateCommandSurface } from '../../../__tests__/command-surface-fixture.ts'; +} from '../../../daemon/__tests__/interaction-get-runtime-fixture.ts'; +import { + contextFromFlags, + makeAndroidSession, +} from '../../../daemon/interaction/internal/__tests__/interaction-touch-fixtures.ts'; +import { testCreateCommandSurface } from '../command-surface-fixture.ts'; // The Android ref-refresh capture a @ref mutation takes before dispatch: when // it runs, what it may not retarget, and the comparison-safe baseline it hands @@ -28,7 +31,7 @@ vi.mock('@agent-device/platform-android/mechanics', async (importOriginal) => { }; }); -vi.mock('../../../snapshot-interactor-capture.ts', () => ({ +vi.mock('../../../daemon/snapshot-interactor-capture.ts', () => ({ captureSnapshotWithInteractor: vi.fn(), })); @@ -43,8 +46,8 @@ import { getAndroidBlockingDialogObservation, getAndroidScreenSize, } from '@agent-device/platform-android/mechanics'; -import { captureSnapshotWithInteractor } from '../../../snapshot-interactor-capture.ts'; -import { activateCompleteRefFrame } from '../../../ref-frame.ts'; +import { captureSnapshotWithInteractor } from '../../../daemon/snapshot-interactor-capture.ts'; +import { activateCompleteRefFrame } from '../../../daemon/ref-frame.ts'; const mockGetAndroidAppState = vi.mocked(getAndroidAppState); const mockGetAndroidBlockingDialogObservation = vi.mocked(getAndroidBlockingDialogObservation); const mockGetAndroidScreenSize = vi.mocked(getAndroidScreenSize); diff --git a/src/daemon/interaction/internal/__tests__/interaction-touch-android-readiness.test.ts b/src/__tests__/daemon-composition/interaction/interaction-touch-android-readiness.test.ts similarity index 91% rename from src/daemon/interaction/internal/__tests__/interaction-touch-android-readiness.test.ts rename to src/__tests__/daemon-composition/interaction/interaction-touch-android-readiness.test.ts index 01a21b51f1..951b4d0cc9 100644 --- a/src/daemon/interaction/internal/__tests__/interaction-touch-android-readiness.test.ts +++ b/src/__tests__/daemon-composition/interaction/interaction-touch-android-readiness.test.ts @@ -1,22 +1,25 @@ import { test, expect, vi, beforeEach } from 'vitest'; import { attachRefs } from '@agent-device/kernel/snapshot'; -import { makeSessionStore } from '../../../__tests__/support/store-factory.ts'; -import { expireRefFrame } from '../../../ref-frame.ts'; -import { handleInteractionCommands } from '../../index.ts'; +import { makeSessionStore } from '../../../daemon/__tests__/support/store-factory.ts'; +import { expireRefFrame } from '../../../daemon/ref-frame.ts'; +import { handleInteractionCommands } from '../../../daemon/interaction/index.ts'; import { getRuntimeBindings, mockTapPoint, resetGetRuntimeFixture, -} from '../../../__tests__/interaction-get-runtime-fixture.ts'; -import { contextFromFlags, makeAndroidSession } from './interaction-touch-fixtures.ts'; -import { testCreateCommandSurface } from '../../../__tests__/command-surface-fixture.ts'; +} from '../../../daemon/__tests__/interaction-get-runtime-fixture.ts'; +import { + contextFromFlags, + makeAndroidSession, +} from '../../../daemon/interaction/internal/__tests__/interaction-touch-fixtures.ts'; +import { testCreateCommandSurface } from '../command-surface-fixture.ts'; // The Android device state a dispatch has to survive: an escape to launcher or // Settings fails the press, a permission prompt warns instead, and // blocking-dialog recovery aborts an admitted @ref rather than retargeting it. type EnsureAndroidBlockingSystemDialogReady = - typeof import('../../../android-system-dialog.ts').ensureAndroidBlockingSystemDialogReady; + typeof import('../../../daemon/android-system-dialog.ts').ensureAndroidBlockingSystemDialogReady; const { androidDialogReadiness } = vi.hoisted(() => ({ androidDialogReadiness: { @@ -39,7 +42,7 @@ vi.mock('@agent-device/platform-android/mechanics', async (importOriginal) => { }; }); -vi.mock('../../../snapshot-interactor-capture.ts', () => ({ +vi.mock('../../../daemon/snapshot-interactor-capture.ts', () => ({ captureSnapshotWithInteractor: vi.fn(), })); @@ -51,8 +54,8 @@ vi.mock('@agent-device/platform-apple/runner/operations', async (importOriginal) // The blocking-dialog readiness check runs for real (its focus probe is mocked // above); the recovery regression below swaps in a recovering implementation. -vi.mock('../../../android-system-dialog.ts', async (importOriginal) => { - const actual = await importOriginal(); +vi.mock('../../../daemon/android-system-dialog.ts', async (importOriginal) => { + const actual = await importOriginal(); androidDialogReadiness.actual = actual.ensureAndroidBlockingSystemDialogReady; return { ...actual, ensureAndroidBlockingSystemDialogReady: androidDialogReadiness.spy }; }); @@ -62,7 +65,7 @@ import { getAndroidBlockingDialogObservation, getAndroidScreenSize, } from '@agent-device/platform-android/mechanics'; -import { captureSnapshotWithInteractor } from '../../../snapshot-interactor-capture.ts'; +import { captureSnapshotWithInteractor } from '../../../daemon/snapshot-interactor-capture.ts'; const mockGetAndroidAppState = vi.mocked(getAndroidAppState); const mockGetAndroidBlockingDialogObservation = vi.mocked(getAndroidBlockingDialogObservation); const mockGetAndroidScreenSize = vi.mocked(getAndroidScreenSize); diff --git a/src/daemon/interaction/internal/__tests__/interaction-touch-direct-ios-eligibility.test.ts b/src/__tests__/daemon-composition/interaction/interaction-touch-direct-ios-eligibility.test.ts similarity index 92% rename from src/daemon/interaction/internal/__tests__/interaction-touch-direct-ios-eligibility.test.ts rename to src/__tests__/daemon-composition/interaction/interaction-touch-direct-ios-eligibility.test.ts index 3b32d89ebc..f8c812eccc 100644 --- a/src/daemon/interaction/internal/__tests__/interaction-touch-direct-ios-eligibility.test.ts +++ b/src/__tests__/daemon-composition/interaction/interaction-touch-direct-ios-eligibility.test.ts @@ -1,17 +1,17 @@ import { test, expect, vi, beforeEach } from 'vitest'; import { attachRefs } from '@agent-device/kernel/snapshot'; -import { makeIosSession } from '../../../__tests__/support/session-factories.ts'; -import { makeSessionStore } from '../../../__tests__/support/store-factory.ts'; -import { handleInteractionCommands } from '../../index.ts'; +import { makeIosSession } from '../../../daemon/__tests__/support/session-factories.ts'; +import { makeSessionStore } from '../../../daemon/__tests__/support/store-factory.ts'; +import { handleInteractionCommands } from '../../../daemon/interaction/index.ts'; import { getRuntimeBindings, mockFillPoint, mockTapElementSelector, mockTapPoint, resetGetRuntimeFixture, -} from '../../../__tests__/interaction-get-runtime-fixture.ts'; -import { contextFromFlags } from './interaction-touch-fixtures.ts'; -import { testCreateCommandSurface } from '../../../__tests__/command-surface-fixture.ts'; +} from '../../../daemon/__tests__/interaction-get-runtime-fixture.ts'; +import { contextFromFlags } from '../../../daemon/interaction/internal/__tests__/interaction-touch-fixtures.ts'; +import { testCreateCommandSurface } from '../command-surface-fixture.ts'; // Ordinary selectors stay capture-backed. Only the explicit Maestro // non-hittable fallback may use the direct iOS selector route. @@ -30,7 +30,7 @@ vi.mock('@agent-device/platform-android/mechanics', async (importOriginal) => { }; }); -vi.mock('../../../snapshot-interactor-capture.ts', () => ({ +vi.mock('../../../daemon/snapshot-interactor-capture.ts', () => ({ captureSnapshotWithInteractor: vi.fn(), })); @@ -45,7 +45,7 @@ import { getAndroidBlockingDialogObservation, getAndroidScreenSize, } from '@agent-device/platform-android/mechanics'; -import { captureSnapshotWithInteractor } from '../../../snapshot-interactor-capture.ts'; +import { captureSnapshotWithInteractor } from '../../../daemon/snapshot-interactor-capture.ts'; const mockGetAndroidAppState = vi.mocked(getAndroidAppState); const mockGetAndroidBlockingDialogObservation = vi.mocked(getAndroidBlockingDialogObservation); const mockGetAndroidScreenSize = vi.mocked(getAndroidScreenSize); diff --git a/src/daemon/interaction/internal/__tests__/interaction-touch-direct-ios.test.ts b/src/__tests__/daemon-composition/interaction/interaction-touch-direct-ios.test.ts similarity index 86% rename from src/daemon/interaction/internal/__tests__/interaction-touch-direct-ios.test.ts rename to src/__tests__/daemon-composition/interaction/interaction-touch-direct-ios.test.ts index 3f5ee807c2..084cfd589d 100644 --- a/src/daemon/interaction/internal/__tests__/interaction-touch-direct-ios.test.ts +++ b/src/__tests__/daemon-composition/interaction/interaction-touch-direct-ios.test.ts @@ -7,24 +7,24 @@ import { dispatchDisclosureRowsOwnedBy, } from '@agent-device/contracts/dispatch-disclosure-fixtures'; import { beforeEach, expect, test, vi } from 'vitest'; -import { makeIosSession } from '../../../__tests__/support/session-factories.ts'; -import { makeSessionStore } from '../../../__tests__/support/store-factory.ts'; -import { handleInteractionCommands } from '../../index.ts'; +import { makeIosSession } from '../../../daemon/__tests__/support/session-factories.ts'; +import { makeSessionStore } from '../../../daemon/__tests__/support/store-factory.ts'; +import { handleInteractionCommands } from '../../../daemon/interaction/index.ts'; import { getRuntimeBindings, mockTapElementSelector, mockTapPoint, resetGetRuntimeFixture, -} from '../../../__tests__/interaction-get-runtime-fixture.ts'; +} from '../../../daemon/__tests__/interaction-get-runtime-fixture.ts'; import { contextFromFlags, makeStaleRefSession, makeTwoButtonNodes, - runInteraction, -} from './interaction-touch-fixtures.ts'; -import { refFrameState } from '../../../ref-frame.ts'; -import { captureSnapshotWithInteractor } from '../../../snapshot-interactor-capture.ts'; -import { testCreateCommandSurface } from '../../../__tests__/command-surface-fixture.ts'; +} from '../../../daemon/interaction/internal/__tests__/interaction-touch-fixtures.ts'; +import { runInteraction } from './interaction-touch-runner.ts'; +import { refFrameState } from '../../../daemon/ref-frame.ts'; +import { captureSnapshotWithInteractor } from '../../../daemon/snapshot-interactor-capture.ts'; +import { testCreateCommandSurface } from '../command-surface-fixture.ts'; vi.mock('@agent-device/platform-android/mechanics', async (importOriginal) => { const actual = await importOriginal(); @@ -36,7 +36,7 @@ vi.mock('@agent-device/platform-android/mechanics', async (importOriginal) => { }; }); -vi.mock('../../../snapshot-interactor-capture.ts', () => ({ +vi.mock('../../../daemon/snapshot-interactor-capture.ts', () => ({ captureSnapshotWithInteractor: vi.fn(), })); diff --git a/src/daemon/interaction/internal/__tests__/interaction-touch-fill.test.ts b/src/__tests__/daemon-composition/interaction/interaction-touch-fill.test.ts similarity index 94% rename from src/daemon/interaction/internal/__tests__/interaction-touch-fill.test.ts rename to src/__tests__/daemon-composition/interaction/interaction-touch-fill.test.ts index b776d8d93a..ef4c38ff12 100644 --- a/src/daemon/interaction/internal/__tests__/interaction-touch-fill.test.ts +++ b/src/__tests__/daemon-composition/interaction/interaction-touch-fill.test.ts @@ -1,22 +1,22 @@ import { test, expect, vi, beforeEach } from 'vitest'; import { attachRefs } from '@agent-device/kernel/snapshot'; import { withAppleRunnerProvider } from '@agent-device/platform-apple/runner'; -import { makeSessionStore } from '../../../__tests__/support/store-factory.ts'; -import { activateCompleteRefFrame, expireRefFrame } from '../../../ref-frame.ts'; -import { STALE_SNAPSHOT_REFS_WARNING } from '../../../session-snapshot.ts'; -import { handleInteractionCommands } from '../../index.ts'; +import { makeSessionStore } from '../../../daemon/__tests__/support/store-factory.ts'; +import { activateCompleteRefFrame, expireRefFrame } from '../../../daemon/ref-frame.ts'; +import { STALE_SNAPSHOT_REFS_WARNING } from '../../../daemon/session-snapshot.ts'; +import { handleInteractionCommands } from '../../../daemon/interaction/index.ts'; import { getRuntimeBindings, mockFillPoint, resetGetRuntimeFixture, -} from '../../../__tests__/interaction-get-runtime-fixture.ts'; +} from '../../../daemon/__tests__/interaction-get-runtime-fixture.ts'; import { contextFromFlags, makeSession, makeStaleRefSession, - runInteraction, -} from './interaction-touch-fixtures.ts'; -import { testCreateCommandSurface } from '../../../__tests__/command-surface-fixture.ts'; +} from '../../../daemon/interaction/internal/__tests__/interaction-touch-fixtures.ts'; +import { runInteraction } from './interaction-touch-runner.ts'; +import { testCreateCommandSurface } from '../command-surface-fixture.ts'; // How fill is admitted and projected: its @ref admission and pins, the editable // node it keeps, and the guards that refuse before typing. @@ -39,7 +39,7 @@ vi.mock('@agent-device/platform-android/mechanics', async (importOriginal) => { }; }); -vi.mock('../../../snapshot-interactor-capture.ts', () => ({ +vi.mock('../../../daemon/snapshot-interactor-capture.ts', () => ({ captureSnapshotWithInteractor: vi.fn(), })); @@ -54,7 +54,7 @@ import { getAndroidBlockingDialogObservation, getAndroidScreenSize, } from '@agent-device/platform-android/mechanics'; -import { captureSnapshotWithInteractor } from '../../../snapshot-interactor-capture.ts'; +import { captureSnapshotWithInteractor } from '../../../daemon/snapshot-interactor-capture.ts'; const mockGetAndroidAppState = vi.mocked(getAndroidAppState); const mockGetAndroidBlockingDialogObservation = vi.mocked(getAndroidBlockingDialogObservation); const mockGetAndroidScreenSize = vi.mocked(getAndroidScreenSize); diff --git a/src/daemon/interaction/internal/__tests__/interaction-touch-payload.test.ts b/src/__tests__/daemon-composition/interaction/interaction-touch-payload.test.ts similarity index 95% rename from src/daemon/interaction/internal/__tests__/interaction-touch-payload.test.ts rename to src/__tests__/daemon-composition/interaction/interaction-touch-payload.test.ts index 64f00fd542..83458c6226 100644 --- a/src/daemon/interaction/internal/__tests__/interaction-touch-payload.test.ts +++ b/src/__tests__/daemon-composition/interaction/interaction-touch-payload.test.ts @@ -1,19 +1,19 @@ import { test, expect, vi, beforeEach } from 'vitest'; import { attachRefs } from '@agent-device/kernel/snapshot'; -import { makeSessionStore } from '../../../__tests__/support/store-factory.ts'; -import { handleInteractionCommands } from '../../index.ts'; +import { makeSessionStore } from '../../../daemon/__tests__/support/store-factory.ts'; +import { handleInteractionCommands } from '../../../daemon/interaction/index.ts'; import { getRuntimeBindings, mockTapPoint, resetGetRuntimeFixture, -} from '../../../__tests__/interaction-get-runtime-fixture.ts'; +} from '../../../daemon/__tests__/interaction-get-runtime-fixture.ts'; import { contextFromFlags, installTestScreenRecording, makeAndroidSession, makeSession, -} from './interaction-touch-fixtures.ts'; -import { testCreateCommandSurface } from '../../../__tests__/command-surface-fixture.ts'; +} from '../../../daemon/interaction/internal/__tests__/interaction-touch-fixtures.ts'; +import { testCreateCommandSurface } from '../command-surface-fixture.ts'; // What a built touch payload carries: the recorded action entry and touch // visualization, the coordinates and reference frame each platform resolves, @@ -33,7 +33,7 @@ vi.mock('@agent-device/platform-android/mechanics', async (importOriginal) => { }; }); -vi.mock('../../../snapshot-interactor-capture.ts', () => ({ +vi.mock('../../../daemon/snapshot-interactor-capture.ts', () => ({ captureSnapshotWithInteractor: vi.fn(), })); @@ -48,7 +48,7 @@ import { getAndroidBlockingDialogObservation, getAndroidScreenSize, } from '@agent-device/platform-android/mechanics'; -import { captureSnapshotWithInteractor } from '../../../snapshot-interactor-capture.ts'; +import { captureSnapshotWithInteractor } from '../../../daemon/snapshot-interactor-capture.ts'; const mockGetAndroidAppState = vi.mocked(getAndroidAppState); const mockGetAndroidBlockingDialogObservation = vi.mocked(getAndroidBlockingDialogObservation); const mockGetAndroidScreenSize = vi.mocked(getAndroidScreenSize); diff --git a/src/daemon/interaction/internal/__tests__/interaction-touch-prepare.test.ts b/src/__tests__/daemon-composition/interaction/interaction-touch-prepare.test.ts similarity index 93% rename from src/daemon/interaction/internal/__tests__/interaction-touch-prepare.test.ts rename to src/__tests__/daemon-composition/interaction/interaction-touch-prepare.test.ts index 1689563fd6..d200ee305c 100644 --- a/src/daemon/interaction/internal/__tests__/interaction-touch-prepare.test.ts +++ b/src/__tests__/daemon-composition/interaction/interaction-touch-prepare.test.ts @@ -16,16 +16,16 @@ import { import { attachRefs, type RawSnapshotNode } from '@agent-device/kernel/snapshot'; import type { DeviceInfo } from '@agent-device/kernel/device'; import { createUnavailableRuntimeFactsForTest } from '@agent-device/test-kit/runtime-operation-facts'; -import { makeIosAppSession } from '../../../__tests__/support/session-factories.ts'; -import { makeSessionStore } from '../../../__tests__/support/store-factory.ts'; +import { makeIosAppSession } from '../../../daemon/__tests__/support/session-factories.ts'; +import { makeSessionStore } from '../../../daemon/__tests__/support/store-factory.ts'; import type { BindDeviceRuntime, InspectDeviceRuntimeFacts, -} from '../../../request-runtime-binding.ts'; -import { daemonPlatformServicesFixture } from '../../../__tests__/platform-services-fixture.ts'; -import { testCreateCommandSurface } from '../../../__tests__/command-surface-fixture.ts'; -import { handleInteractionCommands } from '../../index.ts'; -import type { SessionStore } from '../../../session-store.ts'; +} from '../../../daemon/request-runtime-binding.ts'; +import { daemonPlatformServicesFixture } from '../../../daemon/__tests__/platform-services-fixture.ts'; +import { testCreateCommandSurface } from '../command-surface-fixture.ts'; +import { handleInteractionCommands } from '../../../daemon/interaction/index.ts'; +import type { SessionStore } from '../../../daemon/session-store.ts'; // #3510: the capture an interaction's post-action observation polls. A coordinate-targeted press or // fill acts through a use that declares no capture, so before this its settle loop read the screen @@ -56,7 +56,7 @@ const BRIDGE_PRODUCED = Object.freeze({ }); const mockInteractorCapture = vi.hoisted(() => vi.fn()); -vi.mock('../../../snapshot-interactor-capture.ts', () => ({ +vi.mock('../../../daemon/snapshot-interactor-capture.ts', () => ({ captureSnapshotWithInteractor: mockInteractorCapture, })); diff --git a/src/daemon/interaction/internal/__tests__/interaction-touch-press-admission.test.ts b/src/__tests__/daemon-composition/interaction/interaction-touch-press-admission.test.ts similarity index 95% rename from src/daemon/interaction/internal/__tests__/interaction-touch-press-admission.test.ts rename to src/__tests__/daemon-composition/interaction/interaction-touch-press-admission.test.ts index a13d00a590..52eeb5b0ae 100644 --- a/src/daemon/interaction/internal/__tests__/interaction-touch-press-admission.test.ts +++ b/src/__tests__/daemon-composition/interaction/interaction-touch-press-admission.test.ts @@ -1,14 +1,17 @@ import { test, expect, vi, beforeEach } from 'vitest'; import { attachRefs } from '@agent-device/kernel/snapshot'; -import { makeSessionStore } from '../../../__tests__/support/store-factory.ts'; -import { activateCompleteRefFrame, refFrameState } from '../../../ref-frame.ts'; -import { setSessionSnapshot, STALE_SNAPSHOT_REFS_WARNING } from '../../../session-snapshot.ts'; -import { handleInteractionCommands } from '../../index.ts'; +import { makeSessionStore } from '../../../daemon/__tests__/support/store-factory.ts'; +import { activateCompleteRefFrame, refFrameState } from '../../../daemon/ref-frame.ts'; +import { + setSessionSnapshot, + STALE_SNAPSHOT_REFS_WARNING, +} from '../../../daemon/session-snapshot.ts'; +import { handleInteractionCommands } from '../../../daemon/interaction/index.ts'; import { getRuntimeBindings, mockTapPoint, resetGetRuntimeFixture, -} from '../../../__tests__/interaction-get-runtime-fixture.ts'; +} from '../../../daemon/__tests__/interaction-get-runtime-fixture.ts'; import { contextFromFlags, findResolvedTarget, @@ -17,10 +20,9 @@ import { makeStaleRefSession, makeTwoButtonNodes, readPressPoint, - runFindInternalClick, - runInteraction, -} from './interaction-touch-fixtures.ts'; -import { testCreateCommandSurface } from '../../../__tests__/command-surface-fixture.ts'; +} from '../../../daemon/interaction/internal/__tests__/interaction-touch-fixtures.ts'; +import { runFindInternalClick, runInteraction } from './interaction-touch-runner.ts'; +import { testCreateCommandSurface } from '../command-surface-fixture.ts'; // Whether a targeted touch may act, and on what: click-option and positional // validation, and the ADR 0014 @ref rules (staleness, pins, frame expiry, @@ -40,7 +42,7 @@ vi.mock('@agent-device/platform-android/mechanics', async (importOriginal) => { }; }); -vi.mock('../../../snapshot-interactor-capture.ts', () => ({ +vi.mock('../../../daemon/snapshot-interactor-capture.ts', () => ({ captureSnapshotWithInteractor: vi.fn(), })); @@ -55,7 +57,7 @@ import { getAndroidBlockingDialogObservation, getAndroidScreenSize, } from '@agent-device/platform-android/mechanics'; -import { captureSnapshotWithInteractor } from '../../../snapshot-interactor-capture.ts'; +import { captureSnapshotWithInteractor } from '../../../daemon/snapshot-interactor-capture.ts'; const mockGetAndroidAppState = vi.mocked(getAndroidAppState); const mockGetAndroidBlockingDialogObservation = vi.mocked(getAndroidBlockingDialogObservation); const mockGetAndroidScreenSize = vi.mocked(getAndroidScreenSize); diff --git a/src/daemon/interaction/internal/__tests__/interaction-touch-press.test.ts b/src/__tests__/daemon-composition/interaction/interaction-touch-press.test.ts similarity index 95% rename from src/daemon/interaction/internal/__tests__/interaction-touch-press.test.ts rename to src/__tests__/daemon-composition/interaction/interaction-touch-press.test.ts index b3ab00dd00..ae57d07403 100644 --- a/src/daemon/interaction/internal/__tests__/interaction-touch-press.test.ts +++ b/src/__tests__/daemon-composition/interaction/interaction-touch-press.test.ts @@ -1,13 +1,13 @@ import { test, expect, vi, beforeEach } from 'vitest'; import { attachRefs } from '@agent-device/kernel/snapshot'; -import { makeIosSession } from '../../../__tests__/support/session-factories.ts'; -import { makeSessionStore } from '../../../__tests__/support/store-factory.ts'; -import { handleInteractionCommands } from '../../index.ts'; +import { makeIosSession } from '../../../daemon/__tests__/support/session-factories.ts'; +import { makeSessionStore } from '../../../daemon/__tests__/support/store-factory.ts'; +import { handleInteractionCommands } from '../../../daemon/interaction/index.ts'; import { getRuntimeBindings, mockTapPoint, resetGetRuntimeFixture, -} from '../../../__tests__/interaction-get-runtime-fixture.ts'; +} from '../../../daemon/__tests__/interaction-get-runtime-fixture.ts'; import { contextFromFlags, findResolvedTarget, @@ -16,9 +16,9 @@ import { makeSession, makeStaleRefSession, readPressPoint, - runFindInternalClick, -} from './interaction-touch-fixtures.ts'; -import { testCreateCommandSurface } from '../../../__tests__/command-surface-fixture.ts'; +} from '../../../daemon/interaction/internal/__tests__/interaction-touch-fixtures.ts'; +import { runFindInternalClick } from './interaction-touch-runner.ts'; +import { testCreateCommandSurface } from '../command-surface-fixture.ts'; // Which node an admitted press/click acts on: hittable-ancestor promotion, the // macOS menubar wrapper, button projection, and a mutating find's pre-resolved @@ -38,7 +38,7 @@ vi.mock('@agent-device/platform-android/mechanics', async (importOriginal) => { }; }); -vi.mock('../../../snapshot-interactor-capture.ts', () => ({ +vi.mock('../../../daemon/snapshot-interactor-capture.ts', () => ({ captureSnapshotWithInteractor: vi.fn(), })); @@ -53,7 +53,7 @@ import { getAndroidBlockingDialogObservation, getAndroidScreenSize, } from '@agent-device/platform-android/mechanics'; -import { captureSnapshotWithInteractor } from '../../../snapshot-interactor-capture.ts'; +import { captureSnapshotWithInteractor } from '../../../daemon/snapshot-interactor-capture.ts'; const mockGetAndroidAppState = vi.mocked(getAndroidAppState); const mockGetAndroidBlockingDialogObservation = vi.mocked(getAndroidBlockingDialogObservation); const mockGetAndroidScreenSize = vi.mocked(getAndroidScreenSize); diff --git a/src/daemon/interaction/internal/__tests__/interaction-touch-response.test.ts b/src/__tests__/daemon-composition/interaction/interaction-touch-response.test.ts similarity index 96% rename from src/daemon/interaction/internal/__tests__/interaction-touch-response.test.ts rename to src/__tests__/daemon-composition/interaction/interaction-touch-response.test.ts index bdc926b797..ab22406e52 100644 --- a/src/daemon/interaction/internal/__tests__/interaction-touch-response.test.ts +++ b/src/__tests__/daemon-composition/interaction/interaction-touch-response.test.ts @@ -1,4 +1,4 @@ -import { daemonPlatformServicesFixture } from '../../../__tests__/platform-services-fixture.ts'; +import { daemonPlatformServicesFixture } from '../../../daemon/__tests__/platform-services-fixture.ts'; import fs from 'node:fs'; import path from 'node:path'; import { @@ -8,26 +8,26 @@ import { import { mkdtempForTestSync } from '@agent-device/test-kit/tmp-dir'; import { test, expect, vi, beforeEach } from 'vitest'; import { attachRefs } from '@agent-device/kernel/snapshot'; -import { makeSessionStore } from '../../../__tests__/support/store-factory.ts'; -import { handleInteractionCommands } from '../../index.ts'; +import { makeSessionStore } from '../../../daemon/__tests__/support/store-factory.ts'; +import { handleInteractionCommands } from '../../../daemon/interaction/index.ts'; import { buildInteractionResponseData, buildTargetedTouchResponsePayloads, transformTouchResponseData, -} from '../interaction-touch-response.ts'; +} from '../../../daemon/interaction/internal/interaction-touch-response.ts'; import type { PressCommandResult } from '@agent-device/contracts/interaction'; import { getRuntimeBindings, mockFillPoint, mockTapPoint, resetGetRuntimeFixture, -} from '../../../__tests__/interaction-get-runtime-fixture.ts'; +} from '../../../daemon/__tests__/interaction-get-runtime-fixture.ts'; import { contextFromFlags, installTestScreenRecording, makeSession, -} from './interaction-touch-fixtures.ts'; -import { testCreateCommandSurface } from '../../../__tests__/command-surface-fixture.ts'; +} from '../../../daemon/interaction/internal/__tests__/interaction-touch-fixtures.ts'; +import { testCreateCommandSurface } from '../command-surface-fixture.ts'; // The identity extras the one response site composes: --verify evidence rides // the interactionResultExtra allowlist on every branch, and no branch invents @@ -47,7 +47,7 @@ vi.mock('@agent-device/platform-android/mechanics', async (importOriginal) => { }; }); -vi.mock('../../../snapshot-interactor-capture.ts', () => ({ +vi.mock('../../../daemon/snapshot-interactor-capture.ts', () => ({ captureSnapshotWithInteractor: vi.fn(), })); @@ -62,7 +62,7 @@ import { getAndroidBlockingDialogObservation, getAndroidScreenSize, } from '@agent-device/platform-android/mechanics'; -import { captureSnapshotWithInteractor } from '../../../snapshot-interactor-capture.ts'; +import { captureSnapshotWithInteractor } from '../../../daemon/snapshot-interactor-capture.ts'; const mockGetAndroidAppState = vi.mocked(getAndroidAppState); const mockGetAndroidBlockingDialogObservation = vi.mocked(getAndroidBlockingDialogObservation); const mockGetAndroidScreenSize = vi.mocked(getAndroidScreenSize); diff --git a/src/__tests__/daemon-composition/interaction/interaction-touch-runner.ts b/src/__tests__/daemon-composition/interaction/interaction-touch-runner.ts new file mode 100644 index 0000000000..2d36b3ab22 --- /dev/null +++ b/src/__tests__/daemon-composition/interaction/interaction-touch-runner.ts @@ -0,0 +1,50 @@ +import { handleInteractionCommands } from '../../../daemon/interaction/index.ts'; +import { getRuntimeBindings } from '../../../daemon/__tests__/interaction-get-runtime-fixture.ts'; +import { contextFromFlags } from '../../../daemon/interaction/internal/__tests__/interaction-touch-fixtures.ts'; +import { testCreateCommandSurface } from '../command-surface-fixture.ts'; +import type { SessionStore } from '../../../daemon/session-store.ts'; + +/** + * The real command-surface legs the relocated interaction suites drive through the handler. + * The daemon-policy suites keep their fake surface and the shared factories in + * `interaction-touch-fixtures.ts`; running the real command surface is the composition these + * suites moved here to pin, so the runners live beside them. + */ +export async function runInteraction( + sessionStore: SessionStore, + sessionName: string, + command: string, + positionals: string[], + flags: Record = {}, +) { + return await handleInteractionCommands({ + createCommandSurface: testCreateCommandSurface, + req: { token: 't', session: sessionName, command, positionals, flags }, + sessionName, + sessionStore, + contextFromFlags, + ...getRuntimeBindings(), + }); +} + +export async function runFindInternalClick( + sessionStore: SessionStore, + sessionName: string, + internal: Record, +) { + return await handleInteractionCommands({ + createCommandSurface: testCreateCommandSurface, + req: { + token: 't', + session: sessionName, + command: 'click', + positionals: ['@e2'], + flags: { noRecord: true }, + internal, + }, + sessionName, + sessionStore, + contextFromFlags, + ...getRuntimeBindings(), + }); +} diff --git a/src/daemon/interaction/internal/__tests__/interaction-touch-runtime.test.ts b/src/__tests__/daemon-composition/interaction/interaction-touch-runtime.test.ts similarity index 95% rename from src/daemon/interaction/internal/__tests__/interaction-touch-runtime.test.ts rename to src/__tests__/daemon-composition/interaction/interaction-touch-runtime.test.ts index 77b5396cc2..33073b078d 100644 --- a/src/daemon/interaction/internal/__tests__/interaction-touch-runtime.test.ts +++ b/src/__tests__/daemon-composition/interaction/interaction-touch-runtime.test.ts @@ -1,17 +1,20 @@ import { test, expect, vi, beforeEach } from 'vitest'; import { attachRefs } from '@agent-device/kernel/snapshot'; import { withAppleRunnerProvider } from '@agent-device/platform-apple/runner'; -import { makeSessionStore } from '../../../__tests__/support/store-factory.ts'; -import { handleInteractionCommands } from '../../index.ts'; +import { makeSessionStore } from '../../../daemon/__tests__/support/store-factory.ts'; +import { handleInteractionCommands } from '../../../daemon/interaction/index.ts'; import { elementReadFixtureState, getRuntimeBindings, mockQuerySelector, mockTapPoint, resetGetRuntimeFixture, -} from '../../../__tests__/interaction-get-runtime-fixture.ts'; -import { contextFromFlags, makeSession } from './interaction-touch-fixtures.ts'; -import { testCreateCommandSurface } from '../../../__tests__/command-surface-fixture.ts'; +} from '../../../daemon/__tests__/interaction-get-runtime-fixture.ts'; +import { + contextFromFlags, + makeSession, +} from '../../../daemon/interaction/internal/__tests__/interaction-touch-fixtures.ts'; +import { testCreateCommandSurface } from '../command-surface-fixture.ts'; // What the shared runtime dispatch does with the resolved target: refuse // unusable frame evidence rather than recapture positionally (ADR 0014), refuse @@ -35,7 +38,7 @@ vi.mock('@agent-device/platform-android/mechanics', async (importOriginal) => { }; }); -vi.mock('../../../snapshot-interactor-capture.ts', () => ({ +vi.mock('../../../daemon/snapshot-interactor-capture.ts', () => ({ captureSnapshotWithInteractor: vi.fn(), })); @@ -50,7 +53,7 @@ import { getAndroidBlockingDialogObservation, getAndroidScreenSize, } from '@agent-device/platform-android/mechanics'; -import { captureSnapshotWithInteractor } from '../../../snapshot-interactor-capture.ts'; +import { captureSnapshotWithInteractor } from '../../../daemon/snapshot-interactor-capture.ts'; const mockGetAndroidAppState = vi.mocked(getAndroidAppState); const mockGetAndroidBlockingDialogObservation = vi.mocked(getAndroidBlockingDialogObservation); const mockGetAndroidScreenSize = vi.mocked(getAndroidScreenSize); diff --git a/src/daemon/interaction/internal/__tests__/interaction-touch.test.ts b/src/__tests__/daemon-composition/interaction/interaction-touch.test.ts similarity index 95% rename from src/daemon/interaction/internal/__tests__/interaction-touch.test.ts rename to src/__tests__/daemon-composition/interaction/interaction-touch.test.ts index 193c3decb8..2503449eda 100644 --- a/src/daemon/interaction/internal/__tests__/interaction-touch.test.ts +++ b/src/__tests__/daemon-composition/interaction/interaction-touch.test.ts @@ -1,8 +1,8 @@ import { test, expect, vi, beforeEach } from 'vitest'; import { attachRefs } from '@agent-device/kernel/snapshot'; -import { makeSessionStore } from '../../../__tests__/support/store-factory.ts'; +import { makeSessionStore } from '../../../daemon/__tests__/support/store-factory.ts'; import { WEB_DESKTOP_DEVICE } from '@agent-device/test-kit/device-fixtures'; -import { handleInteractionCommands } from '../../index.ts'; +import { handleInteractionCommands } from '../../../daemon/interaction/index.ts'; import { getRuntimeBindings, mockHoverPoint, @@ -11,14 +11,14 @@ import { mockTapPoint, resetGetRuntimeFixture, runtimeBindingSpies, -} from '../../../__tests__/interaction-get-runtime-fixture.ts'; +} from '../../../daemon/__tests__/interaction-get-runtime-fixture.ts'; import { contextFromFlags, makeMacOsDesktopSession, makeMacOsMenubarSession, makeSession, -} from './interaction-touch-fixtures.ts'; -import { testCreateCommandSurface } from '../../../__tests__/command-surface-fixture.ts'; +} from '../../../daemon/interaction/internal/__tests__/interaction-touch-fixtures.ts'; +import { testCreateCommandSurface } from '../command-surface-fixture.ts'; // Router ownership: one representative per touch command proves // handleInteractionCommands claims press/click/longpress/hover/fill. @@ -37,7 +37,7 @@ vi.mock('@agent-device/platform-android/mechanics', async (importOriginal) => { }; }); -vi.mock('../../../snapshot-interactor-capture.ts', () => ({ +vi.mock('../../../daemon/snapshot-interactor-capture.ts', () => ({ captureSnapshotWithInteractor: vi.fn(), })); @@ -52,7 +52,7 @@ import { getAndroidBlockingDialogObservation, getAndroidScreenSize, } from '@agent-device/platform-android/mechanics'; -import { captureSnapshotWithInteractor } from '../../../snapshot-interactor-capture.ts'; +import { captureSnapshotWithInteractor } from '../../../daemon/snapshot-interactor-capture.ts'; const mockGetAndroidAppState = vi.mocked(getAndroidAppState); const mockGetAndroidBlockingDialogObservation = vi.mocked(getAndroidBlockingDialogObservation); const mockGetAndroidScreenSize = vi.mocked(getAndroidScreenSize); diff --git a/src/daemon/__tests__/is-runtime.test.ts b/src/__tests__/daemon-composition/is-runtime.test.ts similarity index 96% rename from src/daemon/__tests__/is-runtime.test.ts rename to src/__tests__/daemon-composition/is-runtime.test.ts index aa58f8406e..c413e78ce9 100644 --- a/src/daemon/__tests__/is-runtime.test.ts +++ b/src/__tests__/daemon-composition/is-runtime.test.ts @@ -1,4 +1,4 @@ -import { daemonPlatformServicesFixture } from './platform-services-fixture.ts'; +import { daemonPlatformServicesFixture } from '../../daemon/__tests__/platform-services-fixture.ts'; import { afterEach, beforeEach, expect, test, vi } from 'vitest'; import type { SnapshotResult } from '@agent-device/contracts/snapshot-runtime'; import { buildSnapshotPresentationKey } from '@agent-device/kernel/snapshot'; @@ -7,14 +7,14 @@ import { makeAndroidSession, makeIosAppSession, makeIosSession, -} from './support/session-factories.ts'; -import { makeSessionStore } from './support/store-factory.ts'; -import { withTestDeviceInventory } from '../../__tests__/test-utils/device-inventory-gateways.ts'; +} from '../../daemon/__tests__/support/session-factories.ts'; +import { makeSessionStore } from '../../daemon/__tests__/support/store-factory.ts'; +import { withTestDeviceInventory } from '../test-utils/device-inventory-gateways.ts'; import { makeSnapshotState } from '@agent-device/selectors/snapshot-geometry-fixtures'; import type { PostGestureOutcome } from '@agent-device/kernel/snapshot'; -import type { DaemonRequest } from '../daemon-request.ts'; -import { selectorCaptureFixture } from './selector-capture-fixture.ts'; -import { markDeferredInteractionOutcome } from '../deferred-interaction-outcome.ts'; +import type { DaemonRequest } from '../../daemon/daemon-request.ts'; +import { selectorCaptureFixture } from '../../daemon/__tests__/selector-capture-fixture.ts'; +import { markDeferredInteractionOutcome } from '../../daemon/deferred-interaction-outcome.ts'; import { formatPostGestureOutcomeWarning } from '@agent-device/capture-kit/post-gesture-stability'; import { testCreateCommandSurface } from './command-surface-fixture.ts'; @@ -26,7 +26,7 @@ vi.mock('@agent-device/platform-apple/runner/operations', async (importOriginal) return { ...actual, runAppleRunnerCommand: mockRunAppleRunnerCommand }; }); -import { dispatchIsViaRuntime } from '../selector-runtime.ts'; +import { dispatchIsViaRuntime } from '../../daemon/selector-runtime.ts'; beforeEach(() => { mockRunAppleRunnerCommand.mockReset(); diff --git a/src/daemon/__tests__/request-dispatch-disclosure.test.ts b/src/__tests__/daemon-composition/request-dispatch-disclosure.test.ts similarity index 93% rename from src/daemon/__tests__/request-dispatch-disclosure.test.ts rename to src/__tests__/daemon-composition/request-dispatch-disclosure.test.ts index 7ee372a70c..0099365042 100644 --- a/src/daemon/__tests__/request-dispatch-disclosure.test.ts +++ b/src/__tests__/daemon-composition/request-dispatch-disclosure.test.ts @@ -10,7 +10,9 @@ vi.mock('@agent-device/platform-apple/runner/operations', async (importOriginal) return { ...actual, stopIosRunnerSession: vi.fn(async () => {}) }; }); -vi.mock('../device/device-ready.ts', () => ({ ensureDeviceReady: vi.fn(async () => {}) })); +vi.mock('../../daemon/device/device-ready.ts', () => ({ + ensureDeviceReady: vi.fn(async () => {}), +})); import { AppError } from '@agent-device/kernel/errors'; import { resolveCommandRecordingEffect } from '@agent-device/command-registry/registry'; @@ -22,21 +24,25 @@ import { DISPATCH_DISCLOSURE_TABLE_PATH, dispatchDisclosureRowsOwnedBy, } from '@agent-device/contracts/dispatch-disclosure-fixtures'; -import { createTestDeviceInventoryGateways } from '../../__tests__/test-utils/device-inventory-gateways.ts'; -import { makeAndroidSession, makeIosAppSession, makeSession } from './support/session-factories.ts'; -import { makeSessionStore } from './support/store-factory.ts'; +import { createTestDeviceInventoryGateways } from '../test-utils/device-inventory-gateways.ts'; +import { + makeAndroidSession, + makeIosAppSession, + makeSession, +} from '../../daemon/__tests__/support/session-factories.ts'; +import { makeSessionStore } from '../../daemon/__tests__/support/store-factory.ts'; import { mkdtempForTestSync } from '@agent-device/test-kit/tmp-dir'; -import type { DaemonRequest } from '../daemon-request.ts'; -import { discloseRequestDispatch } from '../request-dispatch-disclosure.ts'; -import { createRequestDispatchLedger } from '../request-dispatch-ledger.ts'; -import { LeaseRegistry } from '../lease-registry.ts'; -import type { SessionState } from '../session-state.ts'; -import { clearAndroidObservationFixture } from './android-observation-fixture.ts'; +import type { DaemonRequest } from '../../daemon/daemon-request.ts'; +import { discloseRequestDispatch } from '../../daemon/request-dispatch-disclosure.ts'; +import { createRequestDispatchLedger } from '../../daemon/request-dispatch-ledger.ts'; +import { LeaseRegistry } from '../../daemon/lease-registry.ts'; +import type { SessionState } from '../../daemon/session-state.ts'; +import { clearAndroidObservationFixture } from '../../daemon/__tests__/android-observation-fixture.ts'; import { createRequestHandler, gestureRuntimeSpies, lifecycleDeviceRuntimeGateway, -} from './test-device-runtime-gateway.ts'; +} from '../../daemon/__tests__/test-device-runtime-gateway.ts'; // contracts/fixtures/dispatch-disclosure.json, daemon.route rows: each drives one request through // the real request router, with only the bound device operations faked. diff --git a/src/__tests__/daemon-composition/request-handler-chain.test.ts b/src/__tests__/daemon-composition/request-handler-chain.test.ts index 6680edec9e..599ee3230e 100644 --- a/src/__tests__/daemon-composition/request-handler-chain.test.ts +++ b/src/__tests__/daemon-composition/request-handler-chain.test.ts @@ -27,7 +27,7 @@ import { createAudioProbeAdmissionLedger } from '@agent-device/capture-kit/audio import { createPerfCaptureAdmissionLedger } from '@agent-device/capture-kit/perf-capture-admission-ledger'; import { createScreenRecordingAdmissionLedger } from '@agent-device/capture-kit/screen-recording-admission-ledger'; import { eagerClosureOf } from '../eager-import-closure.fixtures.ts'; -import { testCreateCommandSurface } from '../../daemon/__tests__/command-surface-fixture.ts'; +import { testCreateCommandSurface } from './command-surface-fixture.ts'; function makeRequest(command: string, positionals: string[] = []): DaemonRequest { return { diff --git a/src/__tests__/daemon-composition/request-router-android-modal.test.ts b/src/__tests__/daemon-composition/request-router-android-modal.test.ts index 26ccfd9751..6c9b67a872 100644 --- a/src/__tests__/daemon-composition/request-router-android-modal.test.ts +++ b/src/__tests__/daemon-composition/request-router-android-modal.test.ts @@ -4,7 +4,7 @@ import { test, expect, vi } from 'vitest'; import path from 'node:path'; import { AppError } from '@agent-device/kernel/errors'; import type { RawSnapshotNode } from '@agent-device/kernel/snapshot'; -import { testCreateCommandSurface } from '../../daemon/__tests__/command-surface-fixture.ts'; +import { testCreateCommandSurface } from './command-surface-fixture.ts'; let snapshotCalls = 0; let snapshotMode: 'blocking-dialog' | 'throws' = 'blocking-dialog'; diff --git a/src/__tests__/daemon-composition/request-router-android-perf.test.ts b/src/__tests__/daemon-composition/request-router-android-perf.test.ts index 94cdda0a11..c9a159791e 100644 --- a/src/__tests__/daemon-composition/request-router-android-perf.test.ts +++ b/src/__tests__/daemon-composition/request-router-android-perf.test.ts @@ -12,7 +12,7 @@ import { createPlatformRuntimeGateway, createRequestPlatformProviders, } from '../../platform-runtime.ts'; -import { testCreateCommandSurface } from '../../daemon/__tests__/command-surface-fixture.ts'; +import { testCreateCommandSurface } from './command-surface-fixture.ts'; function makeAndroidSessionStore(name: string): SessionStore { const sessionStore = new SessionStore(`/tmp/${name}`); diff --git a/src/__tests__/daemon-composition/request-router-android-snapshot-helper.test.ts b/src/__tests__/daemon-composition/request-router-android-snapshot-helper.test.ts index 48aa11749b..9aa08ef42d 100644 --- a/src/__tests__/daemon-composition/request-router-android-snapshot-helper.test.ts +++ b/src/__tests__/daemon-composition/request-router-android-snapshot-helper.test.ts @@ -11,7 +11,7 @@ import { createPlatformRuntimeGateway, createRequestPlatformProviders, } from '../../platform-runtime.ts'; -import { testCreateCommandSurface } from '../../daemon/__tests__/command-surface-fixture.ts'; +import { testCreateCommandSurface } from './command-surface-fixture.ts'; function makeAndroidSessionStore(name: string): SessionStore { const sessionStore = new SessionStore(`/tmp/${name}`); diff --git a/src/__tests__/daemon-composition/request-router-fill-text-stdin.test.ts b/src/__tests__/daemon-composition/request-router-fill-text-stdin.test.ts index 2a0f391c3d..297075a27f 100644 --- a/src/__tests__/daemon-composition/request-router-fill-text-stdin.test.ts +++ b/src/__tests__/daemon-composition/request-router-fill-text-stdin.test.ts @@ -20,7 +20,7 @@ import { } from '../../daemon/__tests__/support/session-factories.ts'; import { WEB_DESKTOP_DEVICE } from '@agent-device/test-kit/device-fixtures'; import { mkdtempForTestSync } from '@agent-device/test-kit/tmp-dir'; -import { testCreateCommandSurface } from '../../daemon/__tests__/command-surface-fixture.ts'; +import { testCreateCommandSurface } from './command-surface-fixture.ts'; import { replayScriptSourceBundleFor } from '../test-utils/replay-script-source.ts'; import { createPlatformRuntimeGateway, diff --git a/src/daemon/__tests__/request-router-lock-policy.test.ts b/src/__tests__/daemon-composition/request-router-lock-policy.test.ts similarity index 96% rename from src/daemon/__tests__/request-router-lock-policy.test.ts rename to src/__tests__/daemon-composition/request-router-lock-policy.test.ts index 8c989123e4..9c658461ce 100644 --- a/src/daemon/__tests__/request-router-lock-policy.test.ts +++ b/src/__tests__/daemon-composition/request-router-lock-policy.test.ts @@ -1,9 +1,9 @@ import { createTestDeviceInventoryGateways, createTestDeviceInventoryGatewaysFromProvider, -} from '../../__tests__/test-utils/device-inventory-gateways.ts'; +} from '../test-utils/device-inventory-gateways.ts'; import { test, expect, vi, beforeEach } from 'vitest'; -import { legacyDispatchCapture } from './legacy-snapshot-capture-fixture.ts'; +import { legacyDispatchCapture } from '../../daemon/__tests__/legacy-snapshot-capture-fixture.ts'; import path from 'node:path'; import { testCreateCommandSurface } from './command-surface-fixture.ts'; @@ -13,17 +13,19 @@ vi.mock('@agent-device/platform-apple/runner/operations', async (importOriginal) return { ...actual, stopIosRunnerSession: vi.fn(async () => {}) }; }); -vi.mock('../device/device-ready.ts', () => ({ ensureDeviceReady: vi.fn(async () => {}) })); +vi.mock('../../daemon/device/device-ready.ts', () => ({ + ensureDeviceReady: vi.fn(async () => {}), +})); import { createRequestHandler, lifecycleDeviceRuntimeGateway, systemRuntimeSpies, -} from './test-device-runtime-gateway.ts'; -import { snapshotRuntimeFixture } from './snapshot-runtime-fixture.ts'; -import type { SessionState } from '../session-state.ts'; -import { LeaseRegistry } from '../lease-registry.ts'; -import { makeSessionStore } from './support/store-factory.ts'; +} from '../../daemon/__tests__/test-device-runtime-gateway.ts'; +import { snapshotRuntimeFixture } from '../../daemon/__tests__/snapshot-runtime-fixture.ts'; +import type { SessionState } from '../../daemon/session-state.ts'; +import { LeaseRegistry } from '../../daemon/lease-registry.ts'; +import { makeSessionStore } from '../../daemon/__tests__/support/store-factory.ts'; import type { DeviceRuntimeGateway } from '@agent-device/contracts/platform-runtime'; import { type PlatformRuntimeOperations, diff --git a/src/daemon/__tests__/request-router-macos-app-lease.test.ts b/src/__tests__/daemon-composition/request-router-macos-app-lease.test.ts similarity index 88% rename from src/daemon/__tests__/request-router-macos-app-lease.test.ts rename to src/__tests__/daemon-composition/request-router-macos-app-lease.test.ts index 64fa67fb3d..4875c8f609 100644 --- a/src/daemon/__tests__/request-router-macos-app-lease.test.ts +++ b/src/__tests__/daemon-composition/request-router-macos-app-lease.test.ts @@ -1,14 +1,14 @@ import { afterEach, beforeEach, expect, test, vi } from 'vitest'; import path from 'node:path'; -import { createTestDeviceInventoryGateways } from '../../__tests__/test-utils/device-inventory-gateways.ts'; +import { createTestDeviceInventoryGateways } from '../test-utils/device-inventory-gateways.ts'; import { MACOS_DEVICE } from '@agent-device/test-kit/device-fixtures'; -import { makeSessionStore } from './support/store-factory.ts'; -import { makeMacOsSession } from './support/session-factories.ts'; +import { makeSessionStore } from '../../daemon/__tests__/support/store-factory.ts'; +import { makeMacOsSession } from '../../daemon/__tests__/support/session-factories.ts'; import { mkdtempForTestSync } from '@agent-device/test-kit/tmp-dir'; -import type { DaemonRequest, DaemonResponse } from '../daemon-request.ts'; -import { LeaseRegistry } from '../lease-registry.ts'; -import { createRequestHandler } from './test-device-runtime-gateway.ts'; -import { screenshotRuntimeFixture } from './screenshot-runtime-fixture.ts'; +import type { DaemonRequest, DaemonResponse } from '../../daemon/daemon-request.ts'; +import { LeaseRegistry } from '../../daemon/lease-registry.ts'; +import { createRequestHandler } from '../../daemon/__tests__/test-device-runtime-gateway.ts'; +import { screenshotRuntimeFixture } from '../../daemon/__tests__/screenshot-runtime-fixture.ts'; import { testCreateCommandSurface } from './command-surface-fixture.ts'; const BUNDLE_ID = 'com.example.leased'; diff --git a/src/__tests__/daemon-composition/request-router-provider-credentials.test.ts b/src/__tests__/daemon-composition/request-router-provider-credentials.test.ts index 3e1255a1ec..64df4cf00a 100644 --- a/src/__tests__/daemon-composition/request-router-provider-credentials.test.ts +++ b/src/__tests__/daemon-composition/request-router-provider-credentials.test.ts @@ -9,7 +9,7 @@ import { } from '../../provider-credential-fingerprint.ts'; import { LeaseRegistry } from '../../daemon/lease-registry.ts'; import { createRequestHandler } from '../../daemon/__tests__/test-device-runtime-gateway.ts'; -import { testCreateCommandSurface } from '../../daemon/__tests__/command-surface-fixture.ts'; +import { testCreateCommandSurface } from './command-surface-fixture.ts'; const DAEMON_ENV = { LIMRUN_API_KEY: 'lim-key' }; diff --git a/src/__tests__/daemon-composition/request-router-record-runtime-lock.test.ts b/src/__tests__/daemon-composition/request-router-record-runtime-lock.test.ts index 54d839e6b1..c9bd99c4d7 100644 --- a/src/__tests__/daemon-composition/request-router-record-runtime-lock.test.ts +++ b/src/__tests__/daemon-composition/request-router-record-runtime-lock.test.ts @@ -17,7 +17,7 @@ import { mkdtempForTestSync } from '@agent-device/test-kit/tmp-dir'; import { LeaseRegistry } from '../../daemon/lease-registry.ts'; import { createPlatformRuntimeGateway } from '../../platform-runtime.ts'; import { createRequestHandler } from '../../daemon/__tests__/test-device-runtime-gateway.ts'; -import { testCreateCommandSurface } from '../../daemon/__tests__/command-surface-fixture.ts'; +import { testCreateCommandSurface } from './command-surface-fixture.ts'; const DEVICE: DeviceInfo = { platform: 'android', diff --git a/src/daemon/__tests__/request-router-recording-health.test.ts b/src/__tests__/daemon-composition/request-router-recording-health.test.ts similarity index 87% rename from src/daemon/__tests__/request-router-recording-health.test.ts rename to src/__tests__/daemon-composition/request-router-recording-health.test.ts index 03473e1605..b14d4c3070 100644 --- a/src/daemon/__tests__/request-router-recording-health.test.ts +++ b/src/__tests__/daemon-composition/request-router-recording-health.test.ts @@ -1,20 +1,20 @@ -import { createTestDeviceInventoryGateways } from '../../__tests__/test-utils/device-inventory-gateways.ts'; -import { legacyDispatchCapture } from './legacy-snapshot-capture-fixture.ts'; +import { createTestDeviceInventoryGateways } from '../test-utils/device-inventory-gateways.ts'; +import { legacyDispatchCapture } from '../../daemon/__tests__/legacy-snapshot-capture-fixture.ts'; import { test, expect, vi, beforeEach } from 'vitest'; import path from 'node:path'; import { testCreateCommandSurface } from './command-surface-fixture.ts'; -import { daemonPlatformServicesFixture } from './platform-services-fixture.ts'; +import { daemonPlatformServicesFixture } from '../../daemon/__tests__/platform-services-fixture.ts'; import { createRequestHandler, gestureDeviceRuntimeGateway, gestureRuntimeSpies, -} from './test-device-runtime-gateway.ts'; -import type { SessionState } from '../session-state.ts'; -import { LeaseRegistry } from '../lease-registry.ts'; -import { makeSessionStore } from './support/store-factory.ts'; -import { makeTestScreenRecordingResource } from './support/screen-recording-live-handle.ts'; +} from '../../daemon/__tests__/test-device-runtime-gateway.ts'; +import type { SessionState } from '../../daemon/session-state.ts'; +import { LeaseRegistry } from '../../daemon/lease-registry.ts'; +import { makeSessionStore } from '../../daemon/__tests__/support/store-factory.ts'; +import { makeTestScreenRecordingResource } from '../../daemon/__tests__/support/screen-recording-live-handle.ts'; import { mkdtempForTestSync } from '@agent-device/test-kit/tmp-dir'; // The observation spy hangs off the port the router composes with (ADR 0019 section 11), not off diff --git a/src/__tests__/daemon-composition/request-router-replay-scope.test.ts b/src/__tests__/daemon-composition/request-router-replay-scope.test.ts index 4c69b896d2..f41c2b8e6c 100644 --- a/src/__tests__/daemon-composition/request-router-replay-scope.test.ts +++ b/src/__tests__/daemon-composition/request-router-replay-scope.test.ts @@ -5,7 +5,7 @@ import fs from 'node:fs'; import path from 'node:path'; import { getResolveTargetDeviceMock } from '../../daemon/__tests__/request-router-dispatch-mocks.ts'; -import { testCreateCommandSurface } from '../../daemon/__tests__/command-surface-fixture.ts'; +import { testCreateCommandSurface } from './command-surface-fixture.ts'; vi.mock('../../daemon/device/device-ready.ts', () => ({ ensureDeviceReady: vi.fn(async () => {}), diff --git a/src/__tests__/daemon-composition/request-router-replay-test-ime.test.ts b/src/__tests__/daemon-composition/request-router-replay-test-ime.test.ts index 9a868e0220..9761d3e8e0 100644 --- a/src/__tests__/daemon-composition/request-router-replay-test-ime.test.ts +++ b/src/__tests__/daemon-composition/request-router-replay-test-ime.test.ts @@ -11,7 +11,7 @@ import fs from 'node:fs'; import path from 'node:path'; import { getResolveTargetDeviceMock } from '../../daemon/__tests__/request-router-dispatch-mocks.ts'; -import { testCreateCommandSurface } from '../../daemon/__tests__/command-surface-fixture.ts'; +import { testCreateCommandSurface } from './command-surface-fixture.ts'; vi.mock('../../daemon/device/device-ready.ts', () => ({ ensureDeviceReady: vi.fn(async () => {}), diff --git a/src/daemon/__tests__/request-router-screenshot.test.ts b/src/__tests__/daemon-composition/request-router-screenshot.test.ts similarity index 96% rename from src/daemon/__tests__/request-router-screenshot.test.ts rename to src/__tests__/daemon-composition/request-router-screenshot.test.ts index 82b2c94f8d..aea0c395d2 100644 --- a/src/daemon/__tests__/request-router-screenshot.test.ts +++ b/src/__tests__/daemon-composition/request-router-screenshot.test.ts @@ -1,5 +1,5 @@ -import { createTestDeviceInventoryGateways } from '../../__tests__/test-utils/device-inventory-gateways.ts'; -import { legacyDispatchCapture } from './legacy-snapshot-capture-fixture.ts'; +import { createTestDeviceInventoryGateways } from '../test-utils/device-inventory-gateways.ts'; +import { legacyDispatchCapture } from '../../daemon/__tests__/legacy-snapshot-capture-fixture.ts'; import { test, expect, vi, beforeEach } from 'vitest'; import fs from 'node:fs'; @@ -16,21 +16,21 @@ vi.mock('@agent-device/platform-android/mechanics', async (importOriginal) => { }; }); -import { createRequestHandler } from './test-device-runtime-gateway.ts'; +import { createRequestHandler } from '../../daemon/__tests__/test-device-runtime-gateway.ts'; import { screenshotRuntimeFixture, writeSolidPng, type ScreenshotRuntimeFixture, type ScreenshotRuntimeFixtureOptions, -} from './screenshot-runtime-fixture.ts'; -import type { DaemonRequest } from '../daemon-request.ts'; -import type { SessionState } from '../session-state.ts'; -import { LeaseRegistry } from '../lease-registry.ts'; +} from '../../daemon/__tests__/screenshot-runtime-fixture.ts'; +import type { DaemonRequest } from '../../daemon/daemon-request.ts'; +import type { SessionState } from '../../daemon/session-state.ts'; +import { LeaseRegistry } from '../../daemon/lease-registry.ts'; import { attachRefs } from '@agent-device/kernel/snapshot'; import { PNG } from '@agent-device/capture-kit/png'; import { ANDROID_EMULATOR, IOS_SIMULATOR } from '@agent-device/test-kit/device-fixtures'; -import { makeSessionStore } from './support/store-factory.ts'; -import { makeSession as makeBaseSession } from './support/session-factories.ts'; +import { makeSessionStore } from '../../daemon/__tests__/support/store-factory.ts'; +import { makeSession as makeBaseSession } from '../../daemon/__tests__/support/session-factories.ts'; import { mkdtempForTestSync } from '@agent-device/test-kit/tmp-dir'; function makeSession(name: string): SessionState { diff --git a/src/daemon/__tests__/screenshot-runtime.test.ts b/src/__tests__/daemon-composition/screenshot-runtime.test.ts similarity index 95% rename from src/daemon/__tests__/screenshot-runtime.test.ts rename to src/__tests__/daemon-composition/screenshot-runtime.test.ts index 705867188b..0ee2edd9b1 100644 --- a/src/daemon/__tests__/screenshot-runtime.test.ts +++ b/src/__tests__/daemon-composition/screenshot-runtime.test.ts @@ -1,4 +1,4 @@ -import { daemonPlatformServicesFixture } from './platform-services-fixture.ts'; +import { daemonPlatformServicesFixture } from '../../daemon/__tests__/platform-services-fixture.ts'; import fs from 'node:fs'; import path from 'node:path'; @@ -6,12 +6,15 @@ import { expect, test } from 'vitest'; import { SCREENSHOT_CROP_REASONS } from '@agent-device/contracts/capture'; import type { RawSnapshotNode } from '@agent-device/kernel/snapshot'; import { ANDROID_EMULATOR, IOS_SIMULATOR } from '@agent-device/test-kit/device-fixtures'; -import { makeSession } from './support/session-factories.ts'; -import type { GenericPlatformExecutionParams } from '../generic-leaf-execution.ts'; -import { resolveScreenshotGenericExecution } from '../screenshot-runtime.ts'; -import { screenshotRuntimeFixture, writeSolidPng } from './screenshot-runtime-fixture.ts'; -import type { DaemonRequest } from '../daemon-request.ts'; -import type { SessionState } from '../session-state.ts'; +import { makeSession } from '../../daemon/__tests__/support/session-factories.ts'; +import type { GenericPlatformExecutionParams } from '../../daemon/generic-leaf-execution.ts'; +import { resolveScreenshotGenericExecution } from '../../daemon/screenshot-runtime.ts'; +import { + screenshotRuntimeFixture, + writeSolidPng, +} from '../../daemon/__tests__/screenshot-runtime-fixture.ts'; +import type { DaemonRequest } from '../../daemon/daemon-request.ts'; +import type { SessionState } from '../../daemon/session-state.ts'; import { mkdtempForTestSync } from '@agent-device/test-kit/tmp-dir'; import { testCreateCommandSurface } from './command-surface-fixture.ts'; diff --git a/src/daemon/__tests__/selector-runtime-ambiguity-issuance.test.ts b/src/__tests__/daemon-composition/selector-runtime-ambiguity-issuance.test.ts similarity index 93% rename from src/daemon/__tests__/selector-runtime-ambiguity-issuance.test.ts rename to src/__tests__/daemon-composition/selector-runtime-ambiguity-issuance.test.ts index 9b6d8c174e..c475a8ca2b 100644 --- a/src/daemon/__tests__/selector-runtime-ambiguity-issuance.test.ts +++ b/src/__tests__/daemon-composition/selector-runtime-ambiguity-issuance.test.ts @@ -1,23 +1,23 @@ -import { daemonPlatformServicesFixture } from './platform-services-fixture.ts'; +import { daemonPlatformServicesFixture } from '../../daemon/__tests__/platform-services-fixture.ts'; import { test, expect, vi, beforeEach } from 'vitest'; import { attachRefs } from '@agent-device/kernel/snapshot'; -import { makeSessionStore } from './support/store-factory.ts'; -import { selectorCaptureFixture } from './selector-capture-fixture.ts'; -import { refFrameScope, refFrameState } from '../ref-frame.ts'; -import type { DaemonRequest } from '../daemon-request.ts'; -import { dispatchIsViaRuntime } from '../selector-runtime.ts'; +import { makeSessionStore } from '../../daemon/__tests__/support/store-factory.ts'; +import { selectorCaptureFixture } from '../../daemon/__tests__/selector-capture-fixture.ts'; +import { refFrameScope, refFrameState } from '../../daemon/ref-frame.ts'; +import type { DaemonRequest } from '../../daemon/daemon-request.ts'; +import { dispatchIsViaRuntime } from '../../daemon/selector-runtime.ts'; import { IOS_SIMULATOR } from '@agent-device/test-kit/device-fixtures'; import { getRuntimeBindings, mockTapPoint, resetGetRuntimeFixture, -} from './interaction-get-runtime-fixture.ts'; +} from '../../daemon/__tests__/interaction-get-runtime-fixture.ts'; import { contextFromFlags, makeStaleRefSession, readPressPoint, -} from '../interaction/internal/__tests__/interaction-touch-fixtures.ts'; -import { handleInteractionCommands } from '../interaction/index.ts'; +} from '../../daemon/interaction/internal/__tests__/interaction-touch-fixtures.ts'; +import { handleInteractionCommands } from '../../daemon/interaction/index.ts'; import { testCreateCommandSurface } from './command-surface-fixture.ts'; // #2870 review, the reviewer's pinned invariant: a response that prints @@ -43,8 +43,9 @@ vi.mock('@agent-device/platform-android/mechanics', async (importOriginal) => { }; }); -vi.mock('../snapshot-interactor-capture.ts', async (importOriginal) => { - const actual = await importOriginal(); +vi.mock('../../daemon/snapshot-interactor-capture.ts', async (importOriginal) => { + const actual = + await importOriginal(); return { ...actual, captureSnapshotWithInteractor: mockCaptureSnapshotWithInteractor }; }); diff --git a/src/daemon/selector-runtime-backend.test.ts b/src/__tests__/daemon-composition/selector-runtime-backend.test.ts similarity index 91% rename from src/daemon/selector-runtime-backend.test.ts rename to src/__tests__/daemon-composition/selector-runtime-backend.test.ts index ac07f752f2..584f87f1b9 100644 --- a/src/daemon/selector-runtime-backend.test.ts +++ b/src/__tests__/daemon-composition/selector-runtime-backend.test.ts @@ -1,16 +1,16 @@ -import { daemonPlatformServicesFixture } from './__tests__/platform-services-fixture.ts'; +import { daemonPlatformServicesFixture } from '../../daemon/__tests__/platform-services-fixture.ts'; import path from 'node:path'; import { expect, test, vi } from 'vitest'; import type { CaptureSnapshotInput, SnapshotResult, } from '@agent-device/contracts/snapshot-runtime'; -import { createSelectorRuntimeForDevice } from './selector-runtime-backend.ts'; -import { SessionStore } from './session-store.ts'; -import type { SessionState } from './session-state.ts'; +import { createSelectorRuntimeForDevice } from '../../daemon/selector-runtime-backend.ts'; +import { SessionStore } from '../../daemon/session-store.ts'; +import type { SessionState } from '../../daemon/session-state.ts'; import { mkdtempForTestSync } from '@agent-device/test-kit/tmp-dir'; import { makeSnapshotState } from '@agent-device/selectors/snapshot-geometry-fixtures'; -import { testCreateCommandSurface } from './__tests__/command-surface-fixture.ts'; +import { testCreateCommandSurface } from './command-surface-fixture.ts'; const device: SessionState['device'] = { platform: 'apple', diff --git a/src/daemon/__tests__/selector-runtime.test.ts b/src/__tests__/daemon-composition/selector-runtime.test.ts similarity index 91% rename from src/daemon/__tests__/selector-runtime.test.ts rename to src/__tests__/daemon-composition/selector-runtime.test.ts index f57ed7922c..464b4167e7 100644 --- a/src/daemon/__tests__/selector-runtime.test.ts +++ b/src/__tests__/daemon-composition/selector-runtime.test.ts @@ -1,4 +1,4 @@ -import { daemonPlatformServicesFixture } from './platform-services-fixture.ts'; +import { daemonPlatformServicesFixture } from '../../daemon/__tests__/platform-services-fixture.ts'; import { expect, test } from 'vitest'; import { localRuntimeOwner, @@ -11,9 +11,9 @@ import { type SnapshotResult, } from '@agent-device/contracts/snapshot-runtime'; import { createUnavailableRuntimeFactsForTest } from '@agent-device/test-kit/runtime-operation-facts'; -import { makeSessionStore } from './support/store-factory.ts'; -import { makeSession as makeStoredSession } from './support/session-factories.ts'; -import { dispatchGetViaRuntime } from '../selector-runtime.ts'; +import { makeSessionStore } from '../../daemon/__tests__/support/store-factory.ts'; +import { makeSession as makeStoredSession } from '../../daemon/__tests__/support/session-factories.ts'; +import { dispatchGetViaRuntime } from '../../daemon/selector-runtime.ts'; import { testCreateCommandSurface } from './command-surface-fixture.ts'; test.each(['rebuild', 'retire'] as const)( diff --git a/src/__tests__/daemon-composition/server/daemon-runtime-snapshot-shutdown.test.ts b/src/__tests__/daemon-composition/server/daemon-runtime-snapshot-shutdown.test.ts index 8269b9a9eb..7e986a20f6 100644 --- a/src/__tests__/daemon-composition/server/daemon-runtime-snapshot-shutdown.test.ts +++ b/src/__tests__/daemon-composition/server/daemon-runtime-snapshot-shutdown.test.ts @@ -13,7 +13,7 @@ import { platformResourceCleanup } from '../../../platform-runtime-resource-clea import { DAEMON_SESSION_TEARDOWN_TIMEOUT_MS } from '../../../daemon/session-teardown-budget.ts'; import { dispatchSnapshotViaRuntime } from '../../../daemon/snapshot-runtime.ts'; import { teardownDaemonSessionForShutdown } from '../../../daemon/server/daemon-runtime.ts'; -import { testCreateCommandSurface } from '../../../daemon/__tests__/command-surface-fixture.ts'; +import { testCreateCommandSurface } from '../command-surface-fixture.ts'; vi.mock('@agent-device/device-selection/dispatch-resolve', () => ({ resolveTargetDevice: vi.fn(async () => ANDROID_EMULATOR), diff --git a/src/__tests__/daemon-composition/server/daemon-runtime-web-close-teardown.test.ts b/src/__tests__/daemon-composition/server/daemon-runtime-web-close-teardown.test.ts index f9325d0d92..1119913108 100644 --- a/src/__tests__/daemon-composition/server/daemon-runtime-web-close-teardown.test.ts +++ b/src/__tests__/daemon-composition/server/daemon-runtime-web-close-teardown.test.ts @@ -127,3 +127,38 @@ test('daemon shutdown reports a web close failure on stderr instead of losing it expect(stderrChunks.join('')).toMatch(/web_browser/); expect(sessionStore.get(session.name)).toBeUndefined(); }); + +// The platform filter lives in the composed adapter, not in the neutral teardown: the daemon +// asks the port for every session, and only a web device reaches the agent-browser process. +test('daemon session teardown never dispatches a web close for a non-web session', async () => { + const root = mkdtempForTestSync('agent-device-non-web-teardown-'); + // With the fake installed, a close the adapter should never ask for reaches the + // agent-browser process seam (mockRunCmd) and fails below instead of passing silently. + await installFakeManagedAgentBrowser(root); + const sessionStore = new SessionStore(path.join(root, 'sessions')); + sessionStore.publish('android-non-web-teardown-session', { + name: 'android-non-web-teardown-session', + device: { + platform: 'android', + id: 'emulator-5554', + name: 'Pixel', + kind: 'emulator', + booted: true, + }, + createdAt: Date.now(), + actions: [], + }); + const stderrChunks: string[] = []; + + await teardownDaemonSessionForShutdown({ + ref: sessionStore.lookup('android-non-web-teardown-session')!, + sessionStore, + stderr: { write: (chunk) => stderrChunks.push(chunk) }, + platformCleanup: platformResourceCleanup, + }); + + // The snapshot-helper leg is a real-mechanics no-op for a device with no registered helper + // session; a mistaken web close would surface on the process seam and on stderr below. + expect(mockRunCmd).not.toHaveBeenCalled(); + expect(stderrChunks.join('')).toBe(''); +}); diff --git a/src/daemon/__tests__/snapshot-command-runtime.test.ts b/src/__tests__/daemon-composition/snapshot-command-runtime.test.ts similarity index 91% rename from src/daemon/__tests__/snapshot-command-runtime.test.ts rename to src/__tests__/daemon-composition/snapshot-command-runtime.test.ts index dd7551b52b..f4bcd18c48 100644 --- a/src/daemon/__tests__/snapshot-command-runtime.test.ts +++ b/src/__tests__/daemon-composition/snapshot-command-runtime.test.ts @@ -1,16 +1,16 @@ -import { daemonPlatformServicesFixture } from './platform-services-fixture.ts'; +import { daemonPlatformServicesFixture } from '../../daemon/__tests__/platform-services-fixture.ts'; import { afterEach, expect, test } from 'vitest'; -import { makeAndroidSession } from './support/session-factories.ts'; -import { makeSessionStore } from './support/store-factory.ts'; +import { makeAndroidSession } from '../../daemon/__tests__/support/session-factories.ts'; +import { makeSessionStore } from '../../daemon/__tests__/support/store-factory.ts'; import { clearRequestAbortRegistration, markRequestCanceled, registerRequestAbort, } from '@agent-device/host-kit/request'; -import { dispatchSnapshotDiffViaRuntime } from '../snapshot-diff-runtime.ts'; -import { dispatchSnapshotViaRuntime } from '../snapshot-runtime.ts'; -import { legacyDispatchCapture } from './legacy-snapshot-capture-fixture.ts'; -import { snapshotRuntimeFixture } from './snapshot-runtime-fixture.ts'; +import { dispatchSnapshotDiffViaRuntime } from '../../daemon/snapshot-diff-runtime.ts'; +import { dispatchSnapshotViaRuntime } from '../../daemon/snapshot-runtime.ts'; +import { legacyDispatchCapture } from '../../daemon/__tests__/legacy-snapshot-capture-fixture.ts'; +import { snapshotRuntimeFixture } from '../../daemon/__tests__/snapshot-runtime-fixture.ts'; import { testCreateCommandSurface } from './command-surface-fixture.ts'; /** diff --git a/src/daemon/__tests__/snapshot-diff-runtime.test.ts b/src/__tests__/daemon-composition/snapshot-diff-runtime.test.ts similarity index 92% rename from src/daemon/__tests__/snapshot-diff-runtime.test.ts rename to src/__tests__/daemon-composition/snapshot-diff-runtime.test.ts index be77a7801a..0adbfbc7c6 100644 --- a/src/daemon/__tests__/snapshot-diff-runtime.test.ts +++ b/src/__tests__/daemon-composition/snapshot-diff-runtime.test.ts @@ -1,4 +1,4 @@ -import { daemonPlatformServicesFixture } from './platform-services-fixture.ts'; +import { daemonPlatformServicesFixture } from '../../daemon/__tests__/platform-services-fixture.ts'; import { expect, test, vi } from 'vitest'; import { type DeviceBinding, @@ -13,12 +13,15 @@ import { snapshotRuntimeOperationFacts, } from '@agent-device/contracts/snapshot-runtime'; import { deviceShape } from '@agent-device/kernel/device'; -import { makeAndroidSession } from './support/session-factories.ts'; -import { makeSessionStore } from './support/store-factory.ts'; -import type { BindDeviceRuntime, InspectDeviceRuntimeFacts } from '../request-runtime-binding.ts'; -import { dispatchSnapshotDiffViaRuntime } from '../snapshot-diff-runtime.ts'; -import { expectRefusesUnavailableExactOwnerFact } from './runtime-binding-conformance.ts'; -import { unavailableDeviceRuntimeGateway } from './test-device-runtime-gateway.ts'; +import { makeAndroidSession } from '../../daemon/__tests__/support/session-factories.ts'; +import { makeSessionStore } from '../../daemon/__tests__/support/store-factory.ts'; +import type { + BindDeviceRuntime, + InspectDeviceRuntimeFacts, +} from '../../daemon/request-runtime-binding.ts'; +import { dispatchSnapshotDiffViaRuntime } from '../../daemon/snapshot-diff-runtime.ts'; +import { expectRefusesUnavailableExactOwnerFact } from '../../daemon/__tests__/runtime-binding-conformance.ts'; +import { unavailableDeviceRuntimeGateway } from '../../daemon/__tests__/test-device-runtime-gateway.ts'; import { testCreateCommandSurface } from './command-surface-fixture.ts'; const available = Object.freeze({ available: true } as const); diff --git a/src/daemon/__tests__/snapshot-quality-latch.test.ts b/src/__tests__/daemon-composition/snapshot-quality-latch.test.ts similarity index 94% rename from src/daemon/__tests__/snapshot-quality-latch.test.ts rename to src/__tests__/daemon-composition/snapshot-quality-latch.test.ts index 946fd992ab..d765e4bf75 100644 --- a/src/daemon/__tests__/snapshot-quality-latch.test.ts +++ b/src/__tests__/daemon-composition/snapshot-quality-latch.test.ts @@ -1,7 +1,7 @@ import path from 'node:path'; import { expect, test, vi } from 'vitest'; import type { SnapshotQualityVerdict } from '@agent-device/kernel/snapshot'; -import { makeIosSession } from './support/session-factories.ts'; +import { makeIosSession } from '../../daemon/__tests__/support/session-factories.ts'; import { recoveredSnapshotQualityWarning, renderSnapshotQualityWarnings, @@ -9,18 +9,18 @@ import { import { applyRecoveredWarningLatch, resolveRecoveredWarningLatch, -} from '../snapshot-quality-latch.ts'; -import { dispatchSnapshotDiffViaRuntime } from '../snapshot-diff-runtime.ts'; -import { dispatchSnapshotViaRuntime } from '../snapshot-runtime.ts'; -import { SessionStore } from '../session-store.ts'; -import type { SessionState } from '../session-state.ts'; -import { legacyDispatchCapture } from './legacy-snapshot-capture-fixture.ts'; -import { snapshotRuntimeFixture } from './snapshot-runtime-fixture.ts'; +} from '../../daemon/snapshot-quality-latch.ts'; +import { dispatchSnapshotDiffViaRuntime } from '../../daemon/snapshot-diff-runtime.ts'; +import { dispatchSnapshotViaRuntime } from '../../daemon/snapshot-runtime.ts'; +import { SessionStore } from '../../daemon/session-store.ts'; +import type { SessionState } from '../../daemon/session-state.ts'; +import { legacyDispatchCapture } from '../../daemon/__tests__/legacy-snapshot-capture-fixture.ts'; +import { snapshotRuntimeFixture } from '../../daemon/__tests__/snapshot-runtime-fixture.ts'; import { mkdtempForTestSync } from '@agent-device/test-kit/tmp-dir'; import { testCreateCommandSurface } from './command-surface-fixture.ts'; -vi.mock('../snapshot-interactor-capture.ts', async () => { - const fixture = await import('./legacy-snapshot-capture-fixture.ts'); +vi.mock('../../daemon/snapshot-interactor-capture.ts', async () => { + const fixture = await import('../../daemon/__tests__/legacy-snapshot-capture-fixture.ts'); return { captureSnapshotWithInteractor: fixture.captureSnapshotThroughLegacyDispatchFixture }; }); diff --git a/src/daemon/__tests__/snapshot-runtime-disclosure.test.ts b/src/__tests__/daemon-composition/snapshot-runtime-disclosure.test.ts similarity index 90% rename from src/daemon/__tests__/snapshot-runtime-disclosure.test.ts rename to src/__tests__/daemon-composition/snapshot-runtime-disclosure.test.ts index b793014c20..cd2aef5532 100644 --- a/src/daemon/__tests__/snapshot-runtime-disclosure.test.ts +++ b/src/__tests__/daemon-composition/snapshot-runtime-disclosure.test.ts @@ -4,17 +4,17 @@ import { iosTargetActivationDisclosure } from '@agent-device/contracts/ios-targe import type { IosTargetActivation, PostGestureOutcome } from '@agent-device/kernel/snapshot'; import { formatPostGestureOutcomeWarning } from '@agent-device/capture-kit/post-gesture-stability'; import { makeSnapshotState } from '@agent-device/selectors/snapshot-geometry-fixtures'; -import { markDeferredInteractionOutcome } from '../deferred-interaction-outcome.ts'; -import { makeIosSession } from './support/session-factories.ts'; +import { markDeferredInteractionOutcome } from '../../daemon/deferred-interaction-outcome.ts'; +import { makeIosSession } from '../../daemon/__tests__/support/session-factories.ts'; import { mkdtempForTestSync } from '@agent-device/test-kit/tmp-dir'; -import { SessionStore } from '../session-store.ts'; -import { handleSnapshotCommands } from '../handlers/snapshot.ts'; -import { legacyDispatchCapture } from './legacy-snapshot-capture-fixture.ts'; -import { snapshotRuntimeFixture } from './snapshot-runtime-fixture.ts'; +import { SessionStore } from '../../daemon/session-store.ts'; +import { handleSnapshotCommands } from '../../daemon/handlers/snapshot.ts'; +import { legacyDispatchCapture } from '../../daemon/__tests__/legacy-snapshot-capture-fixture.ts'; +import { snapshotRuntimeFixture } from '../../daemon/__tests__/snapshot-runtime-fixture.ts'; import { testCreateCommandSurface } from './command-surface-fixture.ts'; -vi.mock('../snapshot-interactor-capture.ts', async () => { - const fixture = await import('./legacy-snapshot-capture-fixture.ts'); +vi.mock('../../daemon/snapshot-interactor-capture.ts', async () => { + const fixture = await import('../../daemon/__tests__/legacy-snapshot-capture-fixture.ts'); return { captureSnapshotWithInteractor: fixture.captureSnapshotThroughLegacyDispatchFixture }; }); diff --git a/src/daemon/__tests__/sparse-fallback-screenshot.test.ts b/src/__tests__/daemon-composition/sparse-fallback-screenshot.test.ts similarity index 90% rename from src/daemon/__tests__/sparse-fallback-screenshot.test.ts rename to src/__tests__/daemon-composition/sparse-fallback-screenshot.test.ts index 6974a8c59a..b9a272a193 100644 --- a/src/daemon/__tests__/sparse-fallback-screenshot.test.ts +++ b/src/__tests__/daemon-composition/sparse-fallback-screenshot.test.ts @@ -1,19 +1,19 @@ -import { daemonPlatformServicesFixture } from './platform-services-fixture.ts'; +import { daemonPlatformServicesFixture } from '../../daemon/__tests__/platform-services-fixture.ts'; import path from 'node:path'; import { expect, test } from 'vitest'; import type { SnapshotQualityVerdict } from '@agent-device/kernel/snapshot'; -import { makeIosSession } from './support/session-factories.ts'; +import { makeIosSession } from '../../daemon/__tests__/support/session-factories.ts'; import { mkdtempForTest } from '@agent-device/test-kit/tmp-dir'; -import { SessionStore } from '../session-store.ts'; -import { dispatchSnapshotViaRuntime } from '../snapshot-runtime.ts'; -import type { DownloadableArtifactRegistration } from '../artifact-tracking.ts'; -import { finalizeDaemonResponse } from '../request-finalization.ts'; +import { SessionStore } from '../../daemon/session-store.ts'; +import { dispatchSnapshotViaRuntime } from '../../daemon/snapshot-runtime.ts'; +import type { DownloadableArtifactRegistration } from '../../daemon/artifact-tracking.ts'; +import { finalizeDaemonResponse } from '../../daemon/request-finalization.ts'; import { screenshotRuntimeFixture, writeSolidPng, type ScreenshotRuntimeFixture, type ScreenshotRuntimeFixtureOptions, -} from './screenshot-runtime-fixture.ts'; +} from '../../daemon/__tests__/screenshot-runtime-fixture.ts'; import { testCreateCommandSurface } from './command-surface-fixture.ts'; const SPARSE: SnapshotQualityVerdict = { diff --git a/src/daemon/__tests__/wait-runtime.test.ts b/src/__tests__/daemon-composition/wait-runtime.test.ts similarity index 98% rename from src/daemon/__tests__/wait-runtime.test.ts rename to src/__tests__/daemon-composition/wait-runtime.test.ts index 830a88669f..0246853bb4 100644 --- a/src/daemon/__tests__/wait-runtime.test.ts +++ b/src/__tests__/daemon-composition/wait-runtime.test.ts @@ -1,4 +1,4 @@ -import { daemonPlatformServicesFixture } from './platform-services-fixture.ts'; +import { daemonPlatformServicesFixture } from '../../daemon/__tests__/platform-services-fixture.ts'; import { expect, test, vi } from 'vitest'; import { WAIT_REASONS, type ReadinessPhase } from '@agent-device/contracts/wait'; import { AppError, createRequestCanceledError } from '@agent-device/kernel/errors'; @@ -21,14 +21,17 @@ import { snapshotRuntimeOperationFacts, } from '@agent-device/contracts/snapshot-runtime'; import { deviceShape, type DeviceInfo } from '@agent-device/kernel/device'; -import { makeSession } from './support/session-factories.ts'; -import { makeSessionStore } from './support/store-factory.ts'; +import { makeSession } from '../../daemon/__tests__/support/session-factories.ts'; +import { makeSessionStore } from '../../daemon/__tests__/support/store-factory.ts'; import { unavailableDeploymentSnapshotAndShutdownOperationFacts } from '@agent-device/test-kit/runtime-operation-facts'; -import type { BindDeviceRuntime, InspectDeviceRuntimeFacts } from '../request-runtime-binding.ts'; -import { handleSnapshotCommands } from '../handlers/snapshot.ts'; -import { resolveBoundSelectorCapture } from '../selector-capture-binding.ts'; -import { dispatchGetViaRuntime } from '../selector-runtime.ts'; -import type { DaemonRequest } from '../daemon-request.ts'; +import type { + BindDeviceRuntime, + InspectDeviceRuntimeFacts, +} from '../../daemon/request-runtime-binding.ts'; +import { handleSnapshotCommands } from '../../daemon/handlers/snapshot.ts'; +import { resolveBoundSelectorCapture } from '../../daemon/selector-capture-binding.ts'; +import { dispatchGetViaRuntime } from '../../daemon/selector-runtime.ts'; +import type { DaemonRequest } from '../../daemon/daemon-request.ts'; import { testCreateCommandSurface } from './command-surface-fixture.ts'; const webDevice = { diff --git a/src/cli/replay-test/__tests__/session-test-reporter-values-maestro.test.ts b/src/cli/replay-test/__tests__/session-test-reporter-values-maestro.test.ts index 5840123eed..b178ada491 100644 --- a/src/cli/replay-test/__tests__/session-test-reporter-values-maestro.test.ts +++ b/src/cli/replay-test/__tests__/session-test-reporter-values-maestro.test.ts @@ -20,7 +20,7 @@ import { daemonPlatformServicesFixture } from '../../../daemon/__tests__/platfor // Maestro replay resolves a target device through core/dispatch. Gesture viewport reads re-enter // the admitted internal runtime command; the invoke fixture below returns its typed viewport. import { expect, test, vi } from 'vitest'; -import { testCreateCommandSurface } from '../../../daemon/__tests__/command-surface-fixture.ts'; +import { testCreateCommandSurface } from '../../../__tests__/daemon-composition/command-surface-fixture.ts'; vi.mock('@agent-device/device-selection/dispatch-resolve', async (importOriginal) => { const actual = diff --git a/src/cli/replay-test/__tests__/session-test-reporter-values.test.ts b/src/cli/replay-test/__tests__/session-test-reporter-values.test.ts index a5b6705502..3e6f4153c4 100644 --- a/src/cli/replay-test/__tests__/session-test-reporter-values.test.ts +++ b/src/cli/replay-test/__tests__/session-test-reporter-values.test.ts @@ -12,7 +12,7 @@ import { daemonPlatformServicesFixture } from '../../../daemon/__tests__/platfor // ADR 0012 attempts a post-failure screen digest through the narrow snapshot interactor seam; // these fixtures model no runner, so reject that leaf capture deterministically. import { expect, test, vi } from 'vitest'; -import { testCreateCommandSurface } from '../../../daemon/__tests__/command-surface-fixture.ts'; +import { testCreateCommandSurface } from '../../../__tests__/daemon-composition/command-surface-fixture.ts'; vi.mock('../../../daemon/snapshot-interactor-capture.ts', () => ({ captureSnapshotWithInteractor: vi.fn(async () => { diff --git a/src/daemon/__tests__/back-runtime.test.ts b/src/daemon/__tests__/back-runtime.test.ts index dc7b5a52e1..63697502b9 100644 --- a/src/daemon/__tests__/back-runtime.test.ts +++ b/src/daemon/__tests__/back-runtime.test.ts @@ -24,7 +24,7 @@ import type { GenericPlatformExecutionParams } from '../generic-leaf-execution.t import { resolveBoundBackRuntime } from '../back-runtime.ts'; import { expectRefusesUnavailableExactOwnerFact } from './runtime-binding-conformance.ts'; import { createRequestHandler } from './test-device-runtime-gateway.ts'; -import { testCreateCommandSurface } from './command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from './support/command-surface-fake.ts'; // File-scoped id, not the widely shared 'ios-simulator' literal: this owner binding's // `local-family` kind reaches the real on-disk device-claim admission (`require-owner` @@ -144,7 +144,7 @@ test('request router joins back admission to execution, recording, and ref inval activateCompleteRefFrame(session); sessionStore.publish(session.name, session); const handler = createRequestHandler({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, logPath: '/tmp/daemon.log', token: 't', sessionStore, diff --git a/src/daemon/__tests__/daemon-policy.test.ts b/src/daemon/__tests__/daemon-policy.test.ts index c880859841..63b8ea9262 100644 --- a/src/daemon/__tests__/daemon-policy.test.ts +++ b/src/daemon/__tests__/daemon-policy.test.ts @@ -2,7 +2,7 @@ import fs from 'node:fs'; import path from 'node:path'; import { beforeEach, expect, test, vi } from 'vitest'; import { getResolveTargetDeviceMock } from './request-router-dispatch-mocks.ts'; -import { testCreateCommandSurface } from './command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from './support/command-surface-fake.ts'; vi.mock('../device/device-ready.ts', () => ({ ensureDeviceReady: vi.fn(async () => {}) })); @@ -49,7 +49,7 @@ function makeHandler( const bind = vi.fn(lifecycleDeviceRuntimeGateway.bind); const inspectFacts = vi.fn(lifecycleDeviceRuntimeGateway.inspectFacts); const handler = createRequestHandler({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, logPath: path.join(mkdtempForTestSync('daemon-policy'), 'daemon.log'), token: 'test-token', sessionStore, diff --git a/src/daemon/__tests__/daemon-runtime-app-log.test.ts b/src/daemon/__tests__/daemon-runtime-app-log.test.ts index 3bd3e799ad..6126e6cd72 100644 --- a/src/daemon/__tests__/daemon-runtime-app-log.test.ts +++ b/src/daemon/__tests__/daemon-runtime-app-log.test.ts @@ -1,4 +1,4 @@ -import { platformResourceCleanup } from '../../platform-runtime-resource-cleanup.ts'; +import { platformResourceCleanupFixture } from './support/platform-resource-cleanup-fixture.ts'; import fs from 'node:fs'; import path from 'node:path'; import { expect, test, vi } from 'vitest'; @@ -132,7 +132,7 @@ test('daemon shutdown settles fenced app-log cleanup before finalization can rel sessionStore, stderr: { write: () => {} }, - platformCleanup: platformResourceCleanup, + platformCleanup: platformResourceCleanupFixture(), }); await cleanupStarted; diff --git a/src/daemon/__tests__/focus-runtime.test.ts b/src/daemon/__tests__/focus-runtime.test.ts index c4d4503ae2..e6e93b94e9 100644 --- a/src/daemon/__tests__/focus-runtime.test.ts +++ b/src/daemon/__tests__/focus-runtime.test.ts @@ -24,7 +24,7 @@ import type { GenericPlatformExecutionParams } from '../generic-leaf-execution.t import { readFocusPoint, resolveBoundFocusRuntime } from '../focus-runtime.ts'; import { expectRefusesUnavailableExactOwnerFact } from './runtime-binding-conformance.ts'; import { createRequestHandler } from './test-device-runtime-gateway.ts'; -import { testCreateCommandSurface } from './command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from './support/command-surface-fake.ts'; const appleDevice = { id: 'ios-simulator', @@ -196,7 +196,7 @@ test('request router joins focus admission to execution, recording, and ref inva activateCompleteRefFrame(session); sessionStore.publish(session.name, session); const handler = createRequestHandler({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, logPath: '/tmp/daemon.log', token: 't', sessionStore, diff --git a/src/daemon/__tests__/human-control-router-fixture.ts b/src/daemon/__tests__/human-control-router-fixture.ts index 20964f21f6..6d986b41e4 100644 --- a/src/daemon/__tests__/human-control-router-fixture.ts +++ b/src/daemon/__tests__/human-control-router-fixture.ts @@ -8,11 +8,11 @@ import { makeSessionStore } from './support/store-factory.ts'; import { buildSessionLeaseFromRequest } from '../lease-context.ts'; import { LeaseRegistry } from '../lease-registry.ts'; import { createRequestHandler } from '../request-router.ts'; -import { readDaemonProviderCredentials } from '../../provider-credential-fingerprint.ts'; +import { providerCredentialsFixture } from './support/provider-credentials-fixture.ts'; import { tenantScopedSessionName } from '../session-tenant-scope.ts'; import { lifecycleDeviceRuntimeGateway } from './test-device-runtime-gateway.ts'; import { HUMAN_CONTROL_LEASE_REQUEST, humanControlRequest } from './human-control-fixtures.ts'; -import { testCreateCommandSurface } from './command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from './support/command-surface-fake.ts'; export function createHumanControlHarness() { const registry = new LeaseRegistry(); @@ -26,14 +26,14 @@ export function createHumanControlHarness() { }), ); const handleRequest = createRequestHandler({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, logPath: '/tmp/agent-device-human-control.log', platformServices: daemonPlatformServicesFixture(), claimRecoveryGateway: daemonClaimRecoveryGatewayFixture(), token: 'test-token', sessionStore, leaseRegistry: registry, - providerCredentials: readDaemonProviderCredentials({}, '/tmp'), + providerCredentials: providerCredentialsFixture({}, '/tmp'), deviceInventoryGateways: createTestDeviceInventoryGateways(), deviceRuntimeGateway: lifecycleDeviceRuntimeGateway, trackDownloadableArtifact: () => 'artifact-1', diff --git a/src/daemon/__tests__/orientation-runtime.test.ts b/src/daemon/__tests__/orientation-runtime.test.ts index 9c37ac682e..bc97a0abcd 100644 --- a/src/daemon/__tests__/orientation-runtime.test.ts +++ b/src/daemon/__tests__/orientation-runtime.test.ts @@ -1,6 +1,6 @@ import { daemonPlatformServicesFixture } from './platform-services-fixture.ts'; import { expect, test, vi } from 'vitest'; -import { testCreateCommandSurface } from './command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from './support/command-surface-fake.ts'; // `orientation` carries `androidBlockingDialogGuard: true` (like every other generic-route leaf // in this migration), so this file's Android device reaching the real request router below hits @@ -202,7 +202,7 @@ test('request router joins orientation admission to execution and ref invalidati activateCompleteRefFrame(session); sessionStore.publish(session.name, session); const handler = createRequestHandler({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, logPath: '/tmp/daemon.log', token: 't', sessionStore, diff --git a/src/daemon/__tests__/replay-maestro/session-replay-maestro-remote-evalscript.test.ts b/src/daemon/__tests__/replay-maestro/session-replay-maestro-remote-evalscript.test.ts index d4f663f20c..aeaeab97af 100644 --- a/src/daemon/__tests__/replay-maestro/session-replay-maestro-remote-evalscript.test.ts +++ b/src/daemon/__tests__/replay-maestro/session-replay-maestro-remote-evalscript.test.ts @@ -4,7 +4,7 @@ import path from 'node:path'; import { describe, expect, test, vi } from 'vitest'; import { createScreenRecordingAdmissionLedger } from '@agent-device/capture-kit/screen-recording-admission-ledger'; import { LeaseRegistry } from '../../lease-registry.ts'; -import { platformResourceCleanup } from '../../../platform-runtime-resource-cleanup.ts'; +import { platformResourceCleanupFixture } from '../support/platform-resource-cleanup-fixture.ts'; import { SessionStore } from '../../session-store.ts'; import { makeIosSession } from '../support/session-factories.ts'; import { maestroScriptSourceBundleFor } from '../../../__tests__/test-utils/replay-script-source.ts'; @@ -20,7 +20,7 @@ import { } from '../../handlers/session-replay-command.ts'; import type { SessionCommandParams } from '../../handlers/session-command-input.ts'; import * as maestro from '@agent-device/maestro'; -import { testCreateCommandSurface } from '../command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from '../support/command-surface-fake.ts'; const spy = vi.spyOn(maestro, 'executeMaestroFlow'); @@ -73,7 +73,7 @@ async function runWithNetworkFlag(publicNetworkOnly: boolean | undefined) { // the asserted path: dropping it in the handler must fail this test, since an // unset field reads as trusted and a remote flow would run evalScript. const response = await handleReplayCommand({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req, sessionName: 'default', @@ -143,7 +143,7 @@ async function runWithTestNetworkFlag(publicNetworkOnly: boolean | undefined) { }, retainDeviceExecutionLock: async () => {}, throwIfCanceled: () => {}, - platformResourceCleanup, + platformResourceCleanup: platformResourceCleanupFixture(), } as unknown as SessionCommandParams); if (!response) throw new Error('Expected replay test response'); diff --git a/src/daemon/__tests__/replay-repair/session-replay-repair-record-exclusion.test.ts b/src/daemon/__tests__/replay-repair/session-replay-repair-record-exclusion.test.ts index a2e84315e5..47ea78118a 100644 --- a/src/daemon/__tests__/replay-repair/session-replay-repair-record-exclusion.test.ts +++ b/src/daemon/__tests__/replay-repair/session-replay-repair-record-exclusion.test.ts @@ -65,7 +65,7 @@ import { bindLifecycleRuntime, inspectLifecycleRuntimeFacts, } from '../application-lifecycle-runtime-harness.ts'; -import { platformResourceCleanup } from '../../../platform-runtime-resource-cleanup.ts'; +import { platformResourceCleanupFixture } from '../support/platform-resource-cleanup-fixture.ts'; import { captureSnapshotThroughLegacyDispatchFixture, legacyDispatchCapture, @@ -79,7 +79,7 @@ function handleCloseCommand( ) { return handleProductionCloseCommand({ ...params, - platformResourceCleanup, + platformResourceCleanup: platformResourceCleanupFixture(), inspectFacts: inspectLifecycleRuntimeFacts, bindDevice: bindLifecycleRuntime, }); diff --git a/src/daemon/__tests__/replay-repair/session-replay-repair-transaction.fixtures.ts b/src/daemon/__tests__/replay-repair/session-replay-repair-transaction.fixtures.ts index 9938252300..c0f3e362e3 100644 --- a/src/daemon/__tests__/replay-repair/session-replay-repair-transaction.fixtures.ts +++ b/src/daemon/__tests__/replay-repair/session-replay-repair-transaction.fixtures.ts @@ -12,7 +12,7 @@ import { bindLifecycleRuntime, inspectLifecycleRuntimeFacts, } from '../application-lifecycle-runtime-harness.ts'; -import { platformResourceCleanup } from '../../../platform-runtime-resource-cleanup.ts'; +import { platformResourceCleanupFixture } from '../support/platform-resource-cleanup-fixture.ts'; import { freshEvidence } from './session-replay-repair.fixtures.ts'; /** @@ -50,7 +50,7 @@ export function handleCloseCommand( ) { return handleProductionCloseCommand({ ...params, - platformResourceCleanup, + platformResourceCleanup: platformResourceCleanupFixture(), inspectFacts: inspectLifecycleRuntimeFacts, bindDevice: bindLifecycleRuntime, }); diff --git a/src/daemon/__tests__/replay-suite/session-test-fail-fast.test.ts b/src/daemon/__tests__/replay-suite/session-test-fail-fast.test.ts index c437075e0c..0f92172295 100644 --- a/src/daemon/__tests__/replay-suite/session-test-fail-fast.test.ts +++ b/src/daemon/__tests__/replay-suite/session-test-fail-fast.test.ts @@ -7,7 +7,7 @@ import { makeSessionStore } from '../support/store-factory.ts'; import { handleSessionCommands } from '../../handlers/__tests__/session-command-harness.ts'; import { mkdtempForTestSync } from '@agent-device/test-kit/tmp-dir'; -import { testCreateCommandSurface } from '../command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from '../support/command-surface-fake.ts'; test('test --fail-fast continues after passing scripts', async () => { const root = mkdtempForTestSync('agent-device-test-fail-fast-pass-'); @@ -16,7 +16,7 @@ test('test --fail-fast continues after passing scripts', async () => { const invokedPaths: string[] = []; const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', diff --git a/src/daemon/__tests__/replay-suite/session-test-runner.test.ts b/src/daemon/__tests__/replay-suite/session-test-runner.test.ts index 149534c36f..5613fad4b3 100644 --- a/src/daemon/__tests__/replay-suite/session-test-runner.test.ts +++ b/src/daemon/__tests__/replay-suite/session-test-runner.test.ts @@ -14,7 +14,7 @@ import type { DaemonRequest } from '../../daemon-request.ts'; import { handleSessionCommands } from '../../handlers/__tests__/session-command-harness.ts'; import { mkdtempForTestSync } from '@agent-device/test-kit/tmp-dir'; -import { testCreateCommandSurface } from '../command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from '../support/command-surface-fake.ts'; // Opening a Simulator schedules a best-effort runner prewarm that outlives the request; a real one // would spawn xcodebuild after this file finished and land in whichever file the worker runs next. @@ -68,7 +68,7 @@ test('session_list includes device_udid and ios_simulator_device_set for iOS ses ); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', session: 'default', command: 'session_list', positionals: [] }, sessionName: 'default', @@ -105,7 +105,7 @@ test('test filters replay scripts by context platform and skips untyped files', const invoked: DaemonRequest[] = []; const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -177,7 +177,7 @@ test('test binds each replay script to its declared platform metadata', async () let response; try { response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -217,7 +217,7 @@ test('test cleans up suite-owned sessions after each executed script', async () fs.writeFileSync(path.join(root, '01-android.ad'), 'context platform=android\nopen "Demo"\n'); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -258,7 +258,7 @@ test('test retries failed scripts with fresh suite-owned sessions', async () => const invoked: DaemonRequest[] = []; const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -313,7 +313,7 @@ test('test applies per-script timeout and writes attempt artifacts', async () => let invocationCount = 0; const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -382,7 +382,7 @@ test('open does not retain a session when the request was canceled before comple markRequestCanceled(requestId); try { const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -415,7 +415,7 @@ test('test returns invalid args when no replay scripts match the platform filter fs.writeFileSync(path.join(root, '01-ios.ad'), 'context platform=ios\nopen "Settings"\n'); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -446,7 +446,7 @@ test('test rejects duplicate replay test metadata in the context header', async ); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', diff --git a/src/daemon/__tests__/replay-suite/session-test-suite-infrastructure.test.ts b/src/daemon/__tests__/replay-suite/session-test-suite-infrastructure.test.ts index a43c124d9b..70ca0e383b 100644 --- a/src/daemon/__tests__/replay-suite/session-test-suite-infrastructure.test.ts +++ b/src/daemon/__tests__/replay-suite/session-test-suite-infrastructure.test.ts @@ -8,7 +8,7 @@ import type { DaemonResponse } from '../../daemon-request.ts'; import { handleSessionCommands } from '../../handlers/__tests__/session-command-harness.ts'; import { expectOkData, makeSessionStore } from './session-test-suite.fixtures.ts'; import { mkdtempForTestSync } from '@agent-device/test-kit/tmp-dir'; -import { testCreateCommandSurface } from '../command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from '../support/command-surface-fake.ts'; vi.mock('../../snapshot-interactor-capture.ts', () => ({ captureSnapshotWithInteractor: vi.fn(async () => { @@ -23,7 +23,7 @@ test('test --json marks a typed live device claim as infrastructure without retr let attempts = 0; const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -72,7 +72,7 @@ test('test --json retries DEVICE_IN_USE without typed device-claim provenance', let attempts = 0; const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', diff --git a/src/daemon/__tests__/replay-suite/session-test-suite.test.ts b/src/daemon/__tests__/replay-suite/session-test-suite.test.ts index 290b75e4c0..05518921b3 100644 --- a/src/daemon/__tests__/replay-suite/session-test-suite.test.ts +++ b/src/daemon/__tests__/replay-suite/session-test-suite.test.ts @@ -1,7 +1,7 @@ import { daemonPlatformServicesFixture } from '../platform-services-fixture.ts'; import type { RequestProgressEvent } from '@agent-device/contracts/progress'; import { test, expect, vi } from 'vitest'; -import { testCreateCommandSurface } from '../command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from '../support/command-surface-fake.ts'; // ADR 0012 migration step 2: every replay step failure now attempts a // post-failure screen digest capture + suggestion re-resolution through the @@ -62,7 +62,7 @@ test('test does not retry infrastructure startup failures and stops the suite', const invoked: DaemonRequest[] = []; const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -111,7 +111,7 @@ test('test --fail-fast stops the suite after the first failure and leaves the re const invoked: DaemonRequest[] = []; const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -159,7 +159,7 @@ test('test surfaces a suite-level failure when a source fails to parse', async ( const invoked: DaemonRequest[] = []; const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -195,7 +195,7 @@ test('test discovers Maestro YAML suites when replay backend is set', async () = const invoked: DaemonRequest[] = []; const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -232,7 +232,7 @@ test('test emits progress when attempts retry and pass', async () => { (event) => events.push(event), async () => await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -341,7 +341,7 @@ test('test stops before retrying when a rejected close leaves the prior macOS se let replayAttempts = 0; const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -394,7 +394,7 @@ test('test stops retrying after maxAttempts when every attempt fails', async () let attemptCount = 0; const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -439,7 +439,7 @@ test('test emits skip progress without synthetic duration', async () => { (event) => events.push(event), async () => await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -493,7 +493,7 @@ test('test aggregates snapshot diagnostics from replay session samples', async ( let captures = 0; const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -553,7 +553,7 @@ test('test aggregates snapshot diagnostics from failed replay session samples', fs.writeFileSync(path.join(root, '01-fail.ad'), 'context platform=android\nopen "Demo"\n'); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -627,7 +627,7 @@ test('test stops the suite when the parent request is canceled during an active (event) => events.push(event), async () => await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -694,7 +694,7 @@ test('test --shard-all runs each runnable entry on each selected device', async async () => [ANDROID_ONE, ANDROID_TWO], async () => await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -771,7 +771,7 @@ test('test --shard-split distributes runnable entries by modulo and keeps skips async () => [ANDROID_TWO, ANDROID_ONE], async () => await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -821,7 +821,7 @@ test('test sharding rejects mutually exclusive shard modes', async () => { fs.writeFileSync(path.join(root, '01-a.ad'), 'context platform=android\nopen "Demo"\n'); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -849,7 +849,7 @@ test('test sharding rejects non-positive shard counts', async () => { fs.writeFileSync(path.join(root, '01-a.ad'), 'context platform=android\nopen "Demo"\n'); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -880,7 +880,7 @@ test('test sharding rejects fewer matched devices than requested shards', async async () => [ANDROID_ONE], async () => await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -916,7 +916,7 @@ test('test sharding does not require devices when every entry is skipped', async }, async () => await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', diff --git a/src/daemon/__tests__/request-handler-catalog.test.ts b/src/daemon/__tests__/request-handler-catalog.test.ts index b64cf5abee..9fce2657c6 100644 --- a/src/daemon/__tests__/request-handler-catalog.test.ts +++ b/src/daemon/__tests__/request-handler-catalog.test.ts @@ -29,7 +29,7 @@ import { mkdtempForTestSync } from '@agent-device/test-kit/tmp-dir'; import { createAudioProbeAdmissionLedger } from '@agent-device/capture-kit/audio-probe-admission-ledger'; import { createPerfCaptureAdmissionLedger } from '@agent-device/capture-kit/perf-capture-admission-ledger'; import { createScreenRecordingAdmissionLedger } from '@agent-device/capture-kit/screen-recording-admission-ledger'; -import { testCreateCommandSurface } from './command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from './support/command-surface-fake.ts'; const SPECIALIZED_ROUTES = [ 'humanControl', @@ -508,7 +508,7 @@ async function runCatalogCommandThroughHandlerChain( async () => [], async () => await runRequestHandlerChain({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req, sessionName: req.session, diff --git a/src/daemon/__tests__/request-handler-chain-provider-scope.test.ts b/src/daemon/__tests__/request-handler-chain-provider-scope.test.ts index 23de378959..c905f74699 100644 --- a/src/daemon/__tests__/request-handler-chain-provider-scope.test.ts +++ b/src/daemon/__tests__/request-handler-chain-provider-scope.test.ts @@ -3,7 +3,7 @@ import { daemonPlatformServicesFixture } from './platform-services-fixture.ts'; // through the neutral providerScope, and that an empty scope forwards none. import assert from 'node:assert/strict'; import { test, vi } from 'vitest'; -import { testCreateCommandSurface } from './command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from './support/command-surface-fake.ts'; const handleSessionCommandsMock = vi.fn(async (_params: unknown) => ({ ok: true, data: {} })); vi.mock('../handlers/session.ts', () => ({ @@ -77,7 +77,7 @@ test('the android adb executor from the generic provider scope reaches the sessi }); await runRequestHandlerChain({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), ...baseChainParams('provider-scope-test'), providerScope: { androidAdbExecutor }, @@ -94,7 +94,7 @@ test('an empty provider scope forwards no android adb executor to the session ha handleSessionCommandsMock.mockClear(); await runRequestHandlerChain({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), ...baseChainParams('provider-scope-empty'), providerScope: {}, diff --git a/src/daemon/__tests__/request-router-apps-admission.test.ts b/src/daemon/__tests__/request-router-apps-admission.test.ts index 9b293042b3..0b87c7c99b 100644 --- a/src/daemon/__tests__/request-router-apps-admission.test.ts +++ b/src/daemon/__tests__/request-router-apps-admission.test.ts @@ -9,7 +9,7 @@ import { LeaseRegistry } from '../lease-registry.ts'; import type { DaemonRequest } from '../daemon-request.ts'; import { createRequestHandler } from './test-device-runtime-gateway.ts'; import { mkdtempForTestSync } from '@agent-device/test-kit/tmp-dir'; -import { testCreateCommandSurface } from './command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from './support/command-surface-fake.ts'; function createAppsAdmissionHarness(apps: readonly string[] = []) { const listProviderApps = vi.fn(async () => apps); @@ -24,7 +24,7 @@ function createAppsAdmissionHarness(apps: readonly string[] = []) { throw new Error('apps catalog must not bind a device'); }); const handler = createRequestHandler({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, logPath: path.join(mkdtempForTestSync('daemon'), 'daemon.log'), token: 'test-token', sessionStore: makeSessionStore('agent-device-apps-admission-'), diff --git a/src/daemon/__tests__/request-router-artifacts-web.test.ts b/src/daemon/__tests__/request-router-artifacts-web.test.ts index 73881053c7..4132fd662a 100644 --- a/src/daemon/__tests__/request-router-artifacts-web.test.ts +++ b/src/daemon/__tests__/request-router-artifacts-web.test.ts @@ -12,7 +12,7 @@ import { WEB_DESKTOP_DEVICE } from '@agent-device/test-kit/device-fixtures'; import { cleanupDownloadableArtifact, trackDownloadableArtifact } from '../artifact-tracking.ts'; import { mkdtempForTestSync } from '@agent-device/test-kit/tmp-dir'; -import { testCreateCommandSurface } from './command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from './support/command-surface-fake.ts'; // #1900: `artifacts` (`handlers/lease.ts`) lists daemon-tracked artifacts by tenant scope with no // device or platform involvement at all — `listArtifactsForRequest` never reads `device.platform`. @@ -32,7 +32,7 @@ test('artifacts lists a daemon-tracked artifact produced during a web session', try { const handler = createRequestHandler({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, logPath: path.join(mkdtempForTestSync('daemon'), 'daemon.log'), token: 'test-token', sessionStore, diff --git a/src/daemon/__tests__/request-router-cost.test.ts b/src/daemon/__tests__/request-router-cost.test.ts index 46dd403584..0037f5c7d1 100644 --- a/src/daemon/__tests__/request-router-cost.test.ts +++ b/src/daemon/__tests__/request-router-cost.test.ts @@ -2,7 +2,7 @@ import { createTestDeviceInventoryGateways } from '../../__tests__/test-utils/de import { test, expect, vi, beforeEach } from 'vitest'; import path from 'node:path'; -import { testCreateCommandSurface } from './command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from './support/command-surface-fake.ts'; vi.mock('@agent-device/platform-apple/runner/operations', async (importOriginal) => { const actual = @@ -55,7 +55,7 @@ function makeHandler(sessionStore = makeSessionStore('agent-device-router-cost-' return { sessionStore, handler: createRequestHandler({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, logPath: path.join(mkdtempForTestSync('daemon'), 'daemon.log'), token: 'test-token', sessionStore, diff --git a/src/daemon/__tests__/request-router-custom-action-flags.test.ts b/src/daemon/__tests__/request-router-custom-action-flags.test.ts index 4eb1118e1e..14771d8dd1 100644 --- a/src/daemon/__tests__/request-router-custom-action-flags.test.ts +++ b/src/daemon/__tests__/request-router-custom-action-flags.test.ts @@ -13,11 +13,11 @@ import { createRequestHandler } from './test-device-runtime-gateway.ts'; import { LeaseRegistry } from '../lease-registry.ts'; import { makeSessionStore } from './support/store-factory.ts'; import { mkdtempForTestSync } from '@agent-device/test-kit/tmp-dir'; -import { testCreateCommandSurface } from './command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from './support/command-surface-fake.ts'; function createHandler() { return createRequestHandler({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, logPath: path.join(mkdtempForTestSync('daemon'), 'daemon.log'), token: 'test-token', sessionStore: makeSessionStore('agent-device-router-custom-action-flags-'), diff --git a/src/daemon/__tests__/request-router-developer-dir.test.ts b/src/daemon/__tests__/request-router-developer-dir.test.ts index ad73fcbd18..73513b5f36 100644 --- a/src/daemon/__tests__/request-router-developer-dir.test.ts +++ b/src/daemon/__tests__/request-router-developer-dir.test.ts @@ -6,7 +6,7 @@ import { makeSessionStore } from './support/store-factory.ts'; import { LeaseRegistry } from '../lease-registry.ts'; import { createRequestHandler } from './test-device-runtime-gateway.ts'; import { mkdtempForTestSync } from '@agent-device/test-kit/tmp-dir'; -import { testCreateCommandSurface } from './command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from './support/command-surface-fake.ts'; test( 'a request spawns its commands with its own DEVELOPER_DIR, else the daemon one', @@ -14,7 +14,7 @@ test( async () => { const seen: string[] = []; const handler = createRequestHandler({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, logPath: path.join(mkdtempForTestSync('agent-device-router-developer-dir-'), 'daemon.log'), token: 'test-token', sessionStore: makeSessionStore('agent-device-router-developer-dir-store-'), diff --git a/src/daemon/__tests__/request-router-error-redaction.test.ts b/src/daemon/__tests__/request-router-error-redaction.test.ts index 9f63ba3ec5..db1e92b841 100644 --- a/src/daemon/__tests__/request-router-error-redaction.test.ts +++ b/src/daemon/__tests__/request-router-error-redaction.test.ts @@ -22,7 +22,7 @@ import { createTestDeviceInventoryGateways } from '../../__tests__/test-utils/de import { makeIosAppSession } from './support/session-factories.ts'; import { makeSessionStore } from './support/store-factory.ts'; import { mkdtempForTestSync } from '@agent-device/test-kit/tmp-dir'; -import { testCreateCommandSurface } from './command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from './support/command-surface-fake.ts'; import { LeaseRegistry } from '../lease-registry.ts'; import { createRequestHandler, @@ -62,7 +62,7 @@ test('a Maestro replay error comes back unchanged after its inputText registered const flowPath = path.join(root, 'flow.yaml'); fs.writeFileSync(flowPath, 'appId: com.example.app\n---\n- inputText: "1"\n'); const handler = createRequestHandler({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, logPath: path.join(root, 'daemon.log'), token: 'test-token', sessionStore, diff --git a/src/daemon/__tests__/request-router-events.test.ts b/src/daemon/__tests__/request-router-events.test.ts index 185e265cf6..2faa781ff0 100644 --- a/src/daemon/__tests__/request-router-events.test.ts +++ b/src/daemon/__tests__/request-router-events.test.ts @@ -9,7 +9,7 @@ import { makeSessionStore } from './support/store-factory.ts'; import { makeIosSession, makeSession } from './support/session-factories.ts'; import { WEB_DESKTOP_DEVICE } from '@agent-device/test-kit/device-fixtures'; import { mkdtempForTestSync } from '@agent-device/test-kit/tmp-dir'; -import { testCreateCommandSurface } from './command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from './support/command-surface-fake.ts'; test('events reads the daemon-owned session timeline without appending poll noise', async () => { const sessionStore = makeSessionStore('agent-device-router-events-'); @@ -22,7 +22,7 @@ test('events reads the daemon-owned session timeline without appending poll nois const eventLogPath = sessionStore.resolveEventLogPath('events-session'); const handler = createRequestHandler({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, logPath: path.join(mkdtempForTestSync('daemon'), 'daemon.log'), token: 'test-token', sessionStore, @@ -67,7 +67,7 @@ test('events accepts a blank limit placeholder for cursor-only reads', async () }); const handler = createRequestHandler({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, logPath: path.join(mkdtempForTestSync('daemon'), 'daemon.log'), token: 'test-token', sessionStore, @@ -107,7 +107,7 @@ test('events returns structured errors for invalid limit and cursor', async () = }); const handler = createRequestHandler({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, logPath: path.join(mkdtempForTestSync('daemon'), 'daemon.log'), token: 'test-token', sessionStore, @@ -155,7 +155,7 @@ test('events flushes pending event writes before reading', async () => { }); const handler = createRequestHandler({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, logPath: path.join(mkdtempForTestSync('daemon'), 'daemon.log'), token: 'test-token', sessionStore, @@ -193,7 +193,7 @@ test('events reads the daemon-owned session timeline for a web-backed session', }); const handler = createRequestHandler({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, logPath: path.join(mkdtempForTestSync('daemon'), 'daemon.log'), token: 'test-token', sessionStore, @@ -227,7 +227,7 @@ test('request timeline records thrown request failures after scope creation', as sessionStore.publish('events-session', makeIosSession('events-session')); const handler = createRequestHandler({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, logPath: path.join(mkdtempForTestSync('daemon'), 'daemon.log'), token: 'test-token', sessionStore, @@ -267,7 +267,7 @@ test('request timeline records setup failures after start is appended', async () const sessionStore = makeSessionStore('agent-device-router-events-setup-failure-'); const handler = createRequestHandler({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, logPath: path.join(mkdtempForTestSync('daemon'), 'daemon.log'), token: 'test-token', sessionStore, diff --git a/src/daemon/__tests__/request-router-idle-expired.test.ts b/src/daemon/__tests__/request-router-idle-expired.test.ts index 1f8941a8ca..373c97e566 100644 --- a/src/daemon/__tests__/request-router-idle-expired.test.ts +++ b/src/daemon/__tests__/request-router-idle-expired.test.ts @@ -15,12 +15,12 @@ import type { DaemonRequest } from '../daemon-request.ts'; import { LeaseRegistry } from '../lease-registry.ts'; import { makeSessionStore } from './support/store-factory.ts'; import { mkdtempForTestSync } from '@agent-device/test-kit/tmp-dir'; -import { testCreateCommandSurface } from './command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from './support/command-surface-fake.ts'; function makeHandler(prefix: string) { const sessionStore = makeSessionStore(prefix); const handler = createRequestHandler({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, logPath: path.join(mkdtempForTestSync('daemon'), 'daemon.log'), token: 'test-token', sessionStore, diff --git a/src/daemon/__tests__/request-router-open-claim.test.ts b/src/daemon/__tests__/request-router-open-claim.test.ts index 7ca32b2816..84147da293 100644 --- a/src/daemon/__tests__/request-router-open-claim.test.ts +++ b/src/daemon/__tests__/request-router-open-claim.test.ts @@ -5,7 +5,7 @@ import fs from 'node:fs'; import path from 'node:path'; import crypto from 'node:crypto'; import { getResolveTargetDeviceMock } from './request-router-dispatch-mocks.ts'; -import { testCreateCommandSurface } from './command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from './support/command-surface-fake.ts'; vi.mock('../device/device-ready.ts', () => ({ ensureDeviceReady: vi.fn(async () => {}) })); vi.mock('@agent-device/host-kit/process', async (importOriginal) => { @@ -83,7 +83,7 @@ function createOpenHandler( leaseRegistry = new LeaseRegistry(), ) { return createRequestHandler({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, logPath: path.join(mkdtempForTestSync('daemon'), 'daemon.log'), token: 'test-token', sessionStore, diff --git a/src/daemon/__tests__/request-router-open.test.ts b/src/daemon/__tests__/request-router-open.test.ts index 022617de97..79b0430fa6 100644 --- a/src/daemon/__tests__/request-router-open.test.ts +++ b/src/daemon/__tests__/request-router-open.test.ts @@ -11,7 +11,7 @@ import path from 'node:path'; import { getResolveTargetDeviceMock } from './request-router-dispatch-mocks.ts'; import { replayScriptSourceBundleFor } from '../../__tests__/test-utils/replay-script-source.ts'; -import { testCreateCommandSurface } from './command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from './support/command-surface-fake.ts'; vi.mock('../device/device-ready.ts', () => ({ ensureDeviceReady: vi.fn(async () => {}) })); vi.mock('@agent-device/host-kit/process', async (importOriginal) => { @@ -77,7 +77,7 @@ import { lifecycleDeviceRuntimeGateway, } from './test-device-runtime-gateway.ts'; import { createRequestHandler as createProductionRequestHandler } from '../request-router.ts'; -import { readDaemonProviderCredentials } from '../../provider-credential-fingerprint.ts'; +import { providerCredentialsFixture } from './support/provider-credentials-fixture.ts'; import { resolveRequestExecutionLockPlan } from '../request-binding.ts'; import { LeaseRegistry } from '../lease-registry.ts'; import { ensureDeviceReady } from '../device/device-ready.ts'; @@ -121,7 +121,7 @@ function createOpenHandler( leaseRegistry = new LeaseRegistry(), ) { return createRequestHandler({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, logPath: path.join(mkdtempForTestSync('daemon'), 'daemon.log'), token: 'test-token', sessionStore, @@ -500,14 +500,14 @@ test('close fails synchronously when root composition omits platform resource cl actions: [], }); const handler = createProductionRequestHandler({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, logPath: path.join(mkdtempForTestSync('daemon'), 'daemon.log'), platformServices: daemonPlatformServicesFixture(), claimRecoveryGateway: daemonClaimRecoveryGatewayFixture(), token: 'test-token', sessionStore, leaseRegistry: new LeaseRegistry(), - providerCredentials: readDaemonProviderCredentials({}, '/tmp'), + providerCredentials: providerCredentialsFixture({}, '/tmp'), deviceRuntimeGateway: lifecycleDeviceRuntimeGateway, deviceInventoryGateways: createTestDeviceInventoryGateways(), trackDownloadableArtifact: () => 'artifact-id', diff --git a/src/daemon/__tests__/request-router-record-flags.test.ts b/src/daemon/__tests__/request-router-record-flags.test.ts index 928155a0c1..c4b2ccea8c 100644 --- a/src/daemon/__tests__/request-router-record-flags.test.ts +++ b/src/daemon/__tests__/request-router-record-flags.test.ts @@ -13,11 +13,11 @@ import { createRequestHandler } from './test-device-runtime-gateway.ts'; import { LeaseRegistry } from '../lease-registry.ts'; import { makeSessionStore } from './support/store-factory.ts'; import { mkdtempForTestSync } from '@agent-device/test-kit/tmp-dir'; -import { testCreateCommandSurface } from './command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from './support/command-surface-fake.ts'; function createHandler() { return createRequestHandler({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, logPath: path.join(mkdtempForTestSync('daemon'), 'daemon.log'), token: 'test-token', sessionStore: makeSessionStore('agent-device-router-record-flags-'), diff --git a/src/daemon/__tests__/request-router-repair-expired.test.ts b/src/daemon/__tests__/request-router-repair-expired.test.ts index ebf2350a67..f83d373fb8 100644 --- a/src/daemon/__tests__/request-router-repair-expired.test.ts +++ b/src/daemon/__tests__/request-router-repair-expired.test.ts @@ -11,7 +11,7 @@ import fs from 'node:fs'; import path from 'node:path'; import { getResolveTargetDeviceMock } from './request-router-dispatch-mocks.ts'; -import { testCreateCommandSurface } from './command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from './support/command-surface-fake.ts'; vi.mock('../device/device-ready.ts', () => ({ ensureDeviceReady: vi.fn(async () => {}) })); @@ -31,7 +31,7 @@ const mockResolveTargetDevice = vi.mocked(getResolveTargetDeviceMock()); function makeHandler(prefix: string) { const sessionStore = makeSessionStore(prefix); const handler = createRequestHandler({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, logPath: path.join(mkdtempForTestSync('daemon'), 'daemon.log'), token: 'test-token', sessionStore, diff --git a/src/daemon/__tests__/request-router-replay-env.test.ts b/src/daemon/__tests__/request-router-replay-env.test.ts index 010beb2cd6..c658c386fb 100644 --- a/src/daemon/__tests__/request-router-replay-env.test.ts +++ b/src/daemon/__tests__/request-router-replay-env.test.ts @@ -7,14 +7,14 @@ import { LeaseRegistry } from '../lease-registry.ts'; import { createRequestHandler } from './test-device-runtime-gateway.ts'; import { mkdtempForTestSync } from '@agent-device/test-kit/tmp-dir'; import { replayScriptSourceBundleFor } from '../../__tests__/test-utils/replay-script-source.ts'; -import { testCreateCommandSurface } from './command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from './support/command-surface-fake.ts'; function createHarness() { const root = mkdtempForTestSync('agent-device-router-replay-env-'); return { root, handler: createRequestHandler({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, logPath: path.join(root, 'daemon.log'), token: 'test-token', sessionStore: makeSessionStore('agent-device-router-replay-env-store-'), diff --git a/src/daemon/__tests__/request-router-response-level.test.ts b/src/daemon/__tests__/request-router-response-level.test.ts index 2b4df5f482..40ca7dc34b 100644 --- a/src/daemon/__tests__/request-router-response-level.test.ts +++ b/src/daemon/__tests__/request-router-response-level.test.ts @@ -2,7 +2,7 @@ import { createTestDeviceInventoryGateways } from '../../__tests__/test-utils/de import { test, expect, vi, beforeEach } from 'vitest'; import path from 'node:path'; -import { testCreateCommandSurface } from './command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from './support/command-surface-fake.ts'; vi.mock('@agent-device/platform-apple/runner/operations', async (importOriginal) => { const actual = @@ -69,7 +69,7 @@ function makeHandler() { return { sessionStore, handler: createRequestHandler({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, logPath: path.join(mkdtempForTestSync('daemon'), 'daemon.log'), token: 'test-token', sessionStore, diff --git a/src/daemon/__tests__/request-router-session-address.test.ts b/src/daemon/__tests__/request-router-session-address.test.ts index caaded426b..f2b35b5a92 100644 --- a/src/daemon/__tests__/request-router-session-address.test.ts +++ b/src/daemon/__tests__/request-router-session-address.test.ts @@ -4,7 +4,7 @@ import { test, expect, vi, beforeEach } from 'vitest'; import path from 'node:path'; import { getResolveTargetDeviceMock } from './request-router-dispatch-mocks.ts'; -import { testCreateCommandSurface } from './command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from './support/command-surface-fake.ts'; vi.mock('../device/device-ready.ts', () => ({ ensureDeviceReady: vi.fn(async () => {}) })); vi.mock('@agent-device/host-kit/process', async (importOriginal) => { @@ -62,7 +62,7 @@ function makeIosDevice(id: string): DeviceInfo { function createHandler(sessionStore: ReturnType) { return createRequestHandler({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, logPath: path.join(mkdtempForTestSync('daemon'), 'daemon.log'), token: 'test-token', sessionStore, diff --git a/src/daemon/__tests__/request-router-typed-error.test.ts b/src/daemon/__tests__/request-router-typed-error.test.ts index 86b3be5551..774d8862ea 100644 --- a/src/daemon/__tests__/request-router-typed-error.test.ts +++ b/src/daemon/__tests__/request-router-typed-error.test.ts @@ -4,7 +4,7 @@ import { test, expect, vi, beforeEach } from 'vitest'; import fs from 'node:fs'; import path from 'node:path'; -import { testCreateCommandSurface } from './command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from './support/command-surface-fake.ts'; vi.mock('@agent-device/platform-apple/runner/operations', async (importOriginal) => { const actual = @@ -65,7 +65,7 @@ function makeHandler(sessionStore = makeSessionStore('agent-device-router-typed- return { sessionStore, handler: createRequestHandler({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, logPath: path.join(mkdtempForTestSync('daemon'), 'daemon.log'), token: 'test-token', sessionStore, diff --git a/src/daemon/__tests__/request-runtime-binding-router.test.ts b/src/daemon/__tests__/request-runtime-binding-router.test.ts index 059e00c2a2..342009c6b3 100644 --- a/src/daemon/__tests__/request-runtime-binding-router.test.ts +++ b/src/daemon/__tests__/request-runtime-binding-router.test.ts @@ -14,7 +14,7 @@ import { unavailableDeploymentSnapshotAndShutdownOperationFacts } from '@agent-d import { makeSessionStore } from './support/store-factory.ts'; import { LeaseRegistry } from '../lease-registry.ts'; import { createRequestHandler } from './test-device-runtime-gateway.ts'; -import { testCreateCommandSurface } from './command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from './support/command-surface-fake.ts'; test('request binding disposes once after response while adopted app-log handle survives', async () => { const runtime = makeGateway(); @@ -61,7 +61,7 @@ function makeHandler(gateway: DeviceRuntimeGateway) { return { sessionStore, handler: createRequestHandler({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, logPath: '/tmp/daemon.log', token: 'token', sessionStore, diff --git a/src/daemon/__tests__/request-save-script-transports.test.ts b/src/daemon/__tests__/request-save-script-transports.test.ts index 3278b7b2b9..7e4ae3b329 100644 --- a/src/daemon/__tests__/request-save-script-transports.test.ts +++ b/src/daemon/__tests__/request-save-script-transports.test.ts @@ -34,7 +34,7 @@ import { } from '@agent-device/test-kit/loopback'; import { mkdtempForTestSync } from '@agent-device/test-kit/tmp-dir'; import { flushSessionEventLogWrites } from '@agent-device/session-journal/session-event-log'; -import { testCreateCommandSurface } from './command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from './support/command-surface-fake.ts'; const TOKEN = 'save-script-transport-token'; const SESSION = 'save-script-transport'; @@ -71,7 +71,7 @@ function setup(): Harness { const session = makeIosSession(SESSION); sessionStore.publish(SESSION, session); const handleRequest = createRequestHandler({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, logPath: path.join(root, 'daemon.log'), token: TOKEN, sessionStore, diff --git a/src/daemon/__tests__/runtime-binding-conformance.ts b/src/daemon/__tests__/runtime-binding-conformance.ts index 08ea23b2c1..f7f5294998 100644 --- a/src/daemon/__tests__/runtime-binding-conformance.ts +++ b/src/daemon/__tests__/runtime-binding-conformance.ts @@ -36,7 +36,7 @@ import { resolveBoundTvRemoteRuntime } from '../tv-remote-runtime.ts'; import { resolveBoundTypeTextRuntime } from '../type-text-runtime.ts'; import { resolveBoundViewportRuntime } from '../viewport-runtime.ts'; import type { DaemonFailureResponse } from '@agent-device/kernel/contracts'; -import { testCreateCommandSurface } from './command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from './support/command-surface-fake.ts'; type RuntimeOperation = RuntimeOperationKey; @@ -152,7 +152,7 @@ export const conformedRuntimeBindings = { const session = makeSession('diff-runtime', { device, appBundleId: 'com.example.app' }); sessionStore.publish(session.name, session); const response = await dispatchSnapshotDiffViaRuntime({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, req: { command: 'diff', positionals: ['snapshot'], diff --git a/src/daemon/__tests__/selector-capture-binding.test.ts b/src/daemon/__tests__/selector-capture-binding.test.ts index a0f5453319..eea4a2fca3 100644 --- a/src/daemon/__tests__/selector-capture-binding.test.ts +++ b/src/daemon/__tests__/selector-capture-binding.test.ts @@ -7,7 +7,7 @@ import { withTestDeviceInventory } from '../../__tests__/test-utils/device-inven import { resolveBoundSelectorCapture } from '../selector-capture-binding.ts'; import { createBoundSelectorRuntime } from '../selector-runtime-backend.ts'; import { selectorCaptureFixture } from './selector-capture-fixture.ts'; -import { testCreateCommandSurface } from './command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from './support/command-surface-fake.ts'; // The seam every selector unit consumes. `find` landed it; `get`, `is`, and `wait` migrate by // naming their command, so these are the guarantees they inherit rather than re-derive. @@ -144,7 +144,7 @@ test('the bound construction path admits and binds before it builds a runtime', const resolved = await createBoundSelectorRuntime( { - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', session: 'bound', command: 'get', positionals: [], flags: {} }, sessionName: 'bound', @@ -170,7 +170,7 @@ test('the bound construction path refuses an unavailable operation without build const resolved = await createBoundSelectorRuntime( { - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', session: 'bound', command: 'is', positionals: [], flags: {} }, sessionName: 'bound', diff --git a/src/daemon/__tests__/snapshot-custom-actions-platform-guard.test.ts b/src/daemon/__tests__/snapshot-custom-actions-platform-guard.test.ts index 9e93c0a95e..ebf2fec7ff 100644 --- a/src/daemon/__tests__/snapshot-custom-actions-platform-guard.test.ts +++ b/src/daemon/__tests__/snapshot-custom-actions-platform-guard.test.ts @@ -22,7 +22,7 @@ import { } from '@agent-device/contracts/platform-runtime-operations'; import { snapshotRuntimeFixture } from './snapshot-runtime-fixture.ts'; import { mkdtempForTestSync } from '@agent-device/test-kit/tmp-dir'; -import { testCreateCommandSurface } from './command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from './support/command-surface-fake.ts'; function snapshotDeviceRuntimeGateway(): DeviceRuntimeGateway { const runtime = snapshotRuntimeFixture(); @@ -51,7 +51,7 @@ function handlerForDevice(device: DeviceInfo) { appBundleId: 'com.example.app', } as SessionState); return createRequestHandler({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, logPath: path.join(mkdtempForTestSync('daemon'), 'daemon.log'), token: 'test-token', sessionStore, diff --git a/src/daemon/__tests__/snapshot-runtime-binding.test.ts b/src/daemon/__tests__/snapshot-runtime-binding.test.ts index 64ca4f20f5..4c5d6b6ad0 100644 --- a/src/daemon/__tests__/snapshot-runtime-binding.test.ts +++ b/src/daemon/__tests__/snapshot-runtime-binding.test.ts @@ -13,7 +13,7 @@ import { import type { DaemonRequest } from '../daemon-request.ts'; import { snapshotRuntimeFixture } from './snapshot-runtime-fixture.ts'; import { ensureDeviceReady } from '../device/device-ready.ts'; -import { testCreateCommandSurface } from './command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from './support/command-surface-fake.ts'; vi.mock('../device/device-ready.ts', () => ({ ensureDeviceReady: vi.fn(async () => {}) })); @@ -44,7 +44,7 @@ test('the owning interface binds exactly the session device the facts were admit const resolved = await resolveBoundSnapshotCaptureRuntime( { - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req, sessionName: 'bind-test', diff --git a/src/daemon/__tests__/support/command-surface-fake.ts b/src/daemon/__tests__/support/command-surface-fake.ts new file mode 100644 index 0000000000..8531652b1e --- /dev/null +++ b/src/daemon/__tests__/support/command-surface-fake.ts @@ -0,0 +1,65 @@ +import { vi } from 'vitest'; +import type { + CreateDaemonCommandSurface, + DaemonCommandSurface, +} from '@agent-device/contracts/daemon-command-surface'; + +/** + * The `CreateDaemonCommandSurface` port as the daemon-policy suites need it. Router and handler + * suites assert the daemon's own decisions — admission, locking, session policy, response + * shaping — and mock one level below the surface (bound operations, capture doubles), so this + * fake answers with inert shapes and refuses the selector reads loudly: a suite whose request + * starts executing real selector code depends on root command behavior and belongs under + * `src/__tests__/daemon-composition/` behind the real `testCreateCommandSurface`, where its + * assertions keep their meaning. + */ +const fakeCommandSurface: DaemonCommandSurface = { + capture: { + screenshot: vi.fn(async () => ({ path: '/tmp/fake-screenshot.png' })), + snapshot: vi.fn(async () => ({ nodes: [] })), + diffSnapshot: vi.fn(async () => ({ + mode: 'snapshot' as const, + baselineInitialized: false, + summary: { additions: 0, removals: 0, unchanged: 0 }, + lines: [], + })), + }, + selectors: { + find: vi.fn(async () => { + throw new Error('fake command surface: selector `find` must not run in daemon-policy tests'); + }), + get: vi.fn(async () => { + throw new Error('fake command surface: selector `get` must not run in daemon-policy tests'); + }), + is: vi.fn(async () => { + throw new Error('fake command surface: selector `is` must not run in daemon-policy tests'); + }), + wait: vi.fn(async () => { + throw new Error('fake command surface: `wait` must not run in daemon-policy tests'); + }), + waitForText: vi.fn(async () => { + throw new Error('fake command surface: `waitForText` must not run in daemon-policy tests'); + }), + }, + interactions: { + click: vi.fn(async () => undefined as never), + press: vi.fn(async () => undefined as never), + fill: vi.fn(async () => undefined as never), + longPress: vi.fn(async () => undefined as never), + hover: vi.fn(async () => undefined as never), + gesture: vi.fn( + async () => + ({ + kind: 'fling', + durationMs: 1, + pointerCount: 1, + from: { x: 0, y: 0 }, + to: { x: 1, y: 1 }, + }) as never, + ), + settleObservation: vi.fn(async () => ({ stable: true, waitedMs: 0 }) as never), + }, +}; + +/** The port value the daemon-policy suites inject; see {@link fakeCommandSurface}. */ +export const fakeCreateCommandSurface: CreateDaemonCommandSurface = async () => fakeCommandSurface; diff --git a/src/daemon/__tests__/support/platform-resource-cleanup-fixture.ts b/src/daemon/__tests__/support/platform-resource-cleanup-fixture.ts new file mode 100644 index 0000000000..c97551d7f5 --- /dev/null +++ b/src/daemon/__tests__/support/platform-resource-cleanup-fixture.ts @@ -0,0 +1,31 @@ +import { vi, type Mock } from 'vitest'; +import type { PlatformResourceCleanup } from '../../platform-resource-cleanup.ts'; + +/** Every member observable as a spy, which is how the daemon suites read the fixture back. */ +export type PlatformResourceCleanupFixture = { + [K in keyof PlatformResourceCleanup]: Mock; +}; + +/** + * The `PlatformResourceCleanup` port as the daemon suites need it. Daemon tests assert which + * finalization the neutral orchestration asked for and with which arguments — snapshot-helper + * stop on close, managed-browser close on web teardown, host retention on shutdown — never how + * a platform performs it; the concrete snapshot-helper, managed-browser, and runner-host + * teardown mechanics belong to the platform packages and are asserted root-owned under + * `src/__tests__/daemon-composition/`. Each member is a `vi.fn`, so a suite both injects and + * observes it: read calls off the returned members. An override replaces one capability's + * behavior (a rejection, a specific retention answer) and stays spy-visible — the same shape + * production wiring takes when it composes a different capability. + */ +export function platformResourceCleanupFixture( + overrides: Partial = {}, +): PlatformResourceCleanupFixture { + return Object.freeze({ + stopSnapshotHelper: vi.fn(overrides.stopSnapshotHelper ?? (async () => {})), + closeManagedBrowser: vi.fn(overrides.closeManagedBrowser ?? (async () => {})), + cleanupSessionlessExecutionHost: vi.fn( + overrides.cleanupSessionlessExecutionHost ?? (async () => {}), + ), + retainExecutionHostAfterClose: vi.fn(overrides.retainExecutionHostAfterClose ?? (() => false)), + }) as PlatformResourceCleanupFixture; +} diff --git a/src/daemon/__tests__/support/provider-credentials-fixture.ts b/src/daemon/__tests__/support/provider-credentials-fixture.ts new file mode 100644 index 0000000000..d3e7adae0e --- /dev/null +++ b/src/daemon/__tests__/support/provider-credentials-fixture.ts @@ -0,0 +1,32 @@ +import type { DaemonProviderCredentials } from '@agent-device/daemon-contracts/provider-credentials'; + +/** + * The `DaemonProviderCredentials` port as the daemon suites need it. The daemon only compares + * the fingerprint a client reports against the one this port computes from the daemon's startup + * environment — the fingerprints are opaque to daemon policy, which asserts refusal, reuse, and + * passthrough, never fingerprint content. So the fake builds a deterministic opaque key from + * the sorted defined pairs rather than reproducing the real reader's digest format (the real + * provider/manifest-aware selection and digest semantics are pinned root-owned in + * request-router-provider-credentials and lease-provider-credentials). Distinct environments + * produce distinct keys and an empty environment produces `undefined` — the whole contract the + * daemon suites observe. + */ +export function providerCredentialsFixture( + env: Readonly> = {}, + stateDir = '/tmp', +): DaemonProviderCredentials { + const startupEnv = { ...env }; + return { + fingerprint: () => opaqueFingerprint(startupEnv), + stateDir, + }; +} + +function opaqueFingerprint( + values: Readonly>, +): string | undefined { + const pairs = Object.entries(values) + .filter((pair): pair is [string, string] => pair[1] !== undefined) + .sort(([left], [right]) => left.localeCompare(right)); + return pairs.length === 0 ? undefined : JSON.stringify(pairs); +} diff --git a/src/daemon/__tests__/support/provider-device-admission-fixture.ts b/src/daemon/__tests__/support/provider-device-admission-fixture.ts new file mode 100644 index 0000000000..6ddbaa6c54 --- /dev/null +++ b/src/daemon/__tests__/support/provider-device-admission-fixture.ts @@ -0,0 +1,24 @@ +import type { ProviderDeviceRuntime } from '@agent-device/contracts/device'; +import type { DeviceInfo } from '@agent-device/kernel/device'; +import { installProviderDeviceAdmission } from '../../provider-device-admission.ts'; + +/** + * Provider ownership as the daemon consumes it: the `ProviderDeviceAdmission` port over a list + * of runtime fakes, installed exactly the way root composition installs the real one. Daemon + * suites flip which devices a provider lease currently owns and assert the daemon's branching + * on that fact; which runtime module answers for a device is root composition's job, owned by + * the provider-admission suites under `src/__tests__/daemon-composition/`. + */ +export function providerDeviceAdmissionFixture(runtimes: ProviderDeviceRuntime[] = []) { + let activeRuntimes = [...runtimes]; + const admission = { + isActive: (device: DeviceInfo) => activeRuntimes.some((runtime) => runtime.ownsDevice(device)), + }; + installProviderDeviceAdmission(admission); + return { + /** Same semantics as the production ambient scope: replaces the active runtime set. */ + setActive: (next: ProviderDeviceRuntime[]) => { + activeRuntimes = [...next]; + }, + }; +} diff --git a/src/daemon/__tests__/system-button-runtime.test.ts b/src/daemon/__tests__/system-button-runtime.test.ts index 45be7a0e0d..e5b138c32e 100644 --- a/src/daemon/__tests__/system-button-runtime.test.ts +++ b/src/daemon/__tests__/system-button-runtime.test.ts @@ -33,7 +33,7 @@ import { systemButtonCommands, } from './runtime-binding-conformance.ts'; import { createRequestHandler } from './test-device-runtime-gateway.ts'; -import { testCreateCommandSurface } from './command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from './support/command-surface-fake.ts'; const macOsDevice = { id: 'macos-host', @@ -175,7 +175,7 @@ test('request router joins home admission to execution, recording, and ref inval activateCompleteRefFrame(session); sessionStore.publish(session.name, session); const handler = createRequestHandler({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, logPath: '/tmp/daemon.log', token: 't', sessionStore, diff --git a/src/daemon/__tests__/test-device-runtime-gateway.ts b/src/daemon/__tests__/test-device-runtime-gateway.ts index a842bb0aba..900f64e8da 100644 --- a/src/daemon/__tests__/test-device-runtime-gateway.ts +++ b/src/daemon/__tests__/test-device-runtime-gateway.ts @@ -28,7 +28,7 @@ import { clearAndroidObservationFixture } from './android-observation-fixture.ts import { daemonPlatformServicesFixture } from './platform-services-fixture.ts'; import { createClaimRecoveryGateway } from '../../platform-runtime-claim-recovery.ts'; import { platformResourceCleanup } from '../../platform-runtime-resource-cleanup.ts'; -import { readDaemonProviderCredentials } from '../../provider-credential-fingerprint.ts'; +import { providerCredentialsFixture } from './support/provider-credentials-fixture.ts'; const unavailable = Object.freeze({ available: false as const, @@ -237,7 +237,7 @@ export function createRequestHandler( ) { const { deviceRuntimeGateway = unavailableDeviceRuntimeGateway, - providerCredentials = readDaemonProviderCredentials({}, path.dirname(deps.logPath)), + providerCredentials = providerCredentialsFixture({}, path.dirname(deps.logPath)), platformServices = daemonPlatformServicesFixture(), claimRecoveryGateway = createClaimRecoveryGateway, ...rest diff --git a/src/daemon/__tests__/tv-remote-runtime.test.ts b/src/daemon/__tests__/tv-remote-runtime.test.ts index aa9bc71d9b..1289fcb584 100644 --- a/src/daemon/__tests__/tv-remote-runtime.test.ts +++ b/src/daemon/__tests__/tv-remote-runtime.test.ts @@ -24,7 +24,7 @@ import type { GenericPlatformExecutionParams } from '../generic-leaf-execution.t import { resolveBoundTvRemoteRuntime } from '../tv-remote-runtime.ts'; import { expectRefusesUnavailableExactOwnerFact } from './runtime-binding-conformance.ts'; import { createRequestHandler } from './test-device-runtime-gateway.ts'; -import { testCreateCommandSurface } from './command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from './support/command-surface-fake.ts'; const vegaVvd = { id: 'vega-vvd', @@ -222,7 +222,7 @@ test('request router joins tv-remote admission to execution and ref invalidation activateCompleteRefFrame(session); sessionStore.publish(session.name, session); const handler = createRequestHandler({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, logPath: '/tmp/daemon.log', token: 't', sessionStore, diff --git a/src/daemon/__tests__/viewport-runtime.test.ts b/src/daemon/__tests__/viewport-runtime.test.ts index 896e3e5c12..ce0b68cd0a 100644 --- a/src/daemon/__tests__/viewport-runtime.test.ts +++ b/src/daemon/__tests__/viewport-runtime.test.ts @@ -24,7 +24,7 @@ import type { GenericPlatformExecutionParams } from '../generic-leaf-execution.t import { resolveBoundViewportRuntime } from '../viewport-runtime.ts'; import { expectRefusesUnavailableExactOwnerFact } from './runtime-binding-conformance.ts'; import { createRequestHandler } from './test-device-runtime-gateway.ts'; -import { testCreateCommandSurface } from './command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from './support/command-surface-fake.ts'; const webDevice = { id: 'web', @@ -171,7 +171,7 @@ test('request router joins viewport admission to execution, recording, and ref i activateCompleteRefFrame(session); sessionStore.publish(session.name, session); const handler = createRequestHandler({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, logPath: '/tmp/daemon.log', token: 't', sessionStore, diff --git a/src/daemon/handlers/__tests__/lease.test.ts b/src/daemon/handlers/__tests__/lease.test.ts index b05cac100a..ee916d6d4e 100644 --- a/src/daemon/handlers/__tests__/lease.test.ts +++ b/src/daemon/handlers/__tests__/lease.test.ts @@ -1,6 +1,4 @@ import assert from 'node:assert/strict'; -import fs from 'node:fs'; -import path from 'node:path'; import { test } from 'vitest'; import { handleLeaseCommands } from '../lease.ts'; import { LeaseRegistry } from '../../lease-registry.ts'; @@ -13,11 +11,6 @@ import { markRequestCanceled, registerRequestAbort, } from '@agent-device/host-kit/request'; -import { - providerCredentialFingerprint, - readDaemonProviderCredentials, -} from '../../../provider-credential-fingerprint.ts'; -import { pluginHome, selectPluginManifest } from '../../../plugins/plugin.fixtures.ts'; import { HUMAN_CONTROL_LEASE_REQUEST, HUMAN_CONTROL_SCOPE, @@ -379,212 +372,6 @@ test('a repeat allocation canceled by its requester releases the reused lease', assert.deepEqual(registry.listActiveLeases(), []); }); -const LIMRUN_ATTACH_ENV = { - LIMRUN_API_KEY: 'lim-key', - LIM_IOS_INSTANCE_URL: 'https://region.limrun.example/v1/ios_x/api', - LIM_IOS_INSTANCE_TOKEN: 'ios-token', -}; -const BROWSERSTACK_ENV = { BROWSERSTACK_USERNAME: 'user', BROWSERSTACK_ACCESS_KEY: 'key-1' }; - -function providerAllocateRequest( - leaseProvider: string, - providerCredentialFingerprint: string | undefined, - leaseBackend: 'ios-instance' | 'android-instance' = 'ios-instance', -): DaemonRequest { - const request = allocateRequest(); - return { - ...request, - meta: { - ...request.meta, - leaseProvider, - leaseBackend, - providerCredentialFingerprint, - }, - }; -} - -async function allocateWithDaemonEnv( - req: DaemonRequest, - daemonEnv: Record, -): Promise<{ allocations: number; error?: AppError }> { - const registry = new LeaseRegistry(); - let allocations = 0; - try { - await handleLeaseCommands({ - req, - sessionName: req.session, - sessionStore: makeSessionStore('agent-device-provider-credentials-'), - leaseRegistry: registry, - providerCredentials: readDaemonProviderCredentials(daemonEnv, '/tmp/agent device state'), - leaseLifecycleProvider: { - allocate: async () => { - allocations += 1; - return {}; - }, - }, - }); - } catch (error) { - assert.deepEqual(registry.listActiveLeases(), []); - return { allocations, error: error as AppError }; - } - return { allocations }; -} - -test('a daemon started with only LIMRUN_API_KEY refuses a shell with instance variables before allocation', async () => { - const outcome = await allocateWithDaemonEnv( - providerAllocateRequest('limrun', providerCredentialFingerprint('limrun', LIMRUN_ATTACH_ENV)), - { LIMRUN_API_KEY: 'lim-key' }, - ); - - assert.equal(outcome.allocations, 0); - assert.equal(outcome.error?.code, 'INVALID_ARGS'); - assert.equal(outcome.error?.details?.reason, 'provider-credentials-changed'); - assert.equal(outcome.error?.details?.provider, 'limrun'); - assert.match( - String(outcome.error?.details?.hint), - /agent-device daemon stop --state-dir '\/tmp\/agent device state'/, - ); -}); - -test('a Limrun lease compares only the leased platform instance variables', async () => { - const daemonEnv = { - ...LIMRUN_ATTACH_ENV, - LIM_ANDROID_INSTANCE_URL: 'https://region.limrun.example/v1/android_x/api', - LIM_ANDROID_INSTANCE_TOKEN: 'android-token', - LIM_ANDROID_INSTANCE_ADB_URL: 'wss://region.limrun.example/v1/android_x/adb', - }; - const shellEnv = { ...daemonEnv, LIM_ANDROID_INSTANCE_TOKEN: 'android-token-2' }; - const allocate = async (leaseBackend: 'ios-instance' | 'android-instance') => - await allocateWithDaemonEnv( - providerAllocateRequest( - 'limrun', - providerCredentialFingerprint('limrun', shellEnv, leaseBackend), - leaseBackend, - ), - daemonEnv, - ); - - assert.equal((await allocate('ios-instance')).error, undefined); - assert.equal( - (await allocate('android-instance')).error?.details?.reason, - 'provider-credentials-changed', - ); -}); - -test('a daemon holding rotated BrowserStack keys refuses before allocation', async () => { - const outcome = await allocateWithDaemonEnv( - providerAllocateRequest( - 'browserstack', - providerCredentialFingerprint('browserstack', { - ...BROWSERSTACK_ENV, - BROWSERSTACK_ACCESS_KEY: 'key-2', - }), - ), - BROWSERSTACK_ENV, - ); - - assert.equal(outcome.allocations, 0); - assert.equal(outcome.error?.details?.reason, 'provider-credentials-changed'); - assert.equal(outcome.error?.details?.provider, 'browserstack'); -}); - -test.for([ - ['limrun', LIMRUN_ATTACH_ENV], - ['browserstack', BROWSERSTACK_ENV], -] as const)( - 'a daemon holding the %s credentials of the shell allocates', - async ([provider, env]) => { - const outcome = await allocateWithDaemonEnv( - providerAllocateRequest(provider, providerCredentialFingerprint(provider, env)), - env, - ); - - assert.equal(outcome.error, undefined); - assert.equal(outcome.allocations, 1); - }, -); - -test('a daemon holding credentials allocates for a shell with none', async () => { - const outcome = await allocateWithDaemonEnv( - providerAllocateRequest('limrun', providerCredentialFingerprint('limrun', {})), - { LIMRUN_API_KEY: 'lim-key' }, - ); - - assert.equal(outcome.error, undefined); - assert.equal(outcome.allocations, 1); -}); - -test('a daemon started without BrowserStack credentials refuses a shell that has them', async () => { - const outcome = await allocateWithDaemonEnv( - providerAllocateRequest( - 'browserstack', - providerCredentialFingerprint('browserstack', BROWSERSTACK_ENV), - ), - {}, - ); - - assert.equal(outcome.allocations, 0); - assert.equal(outcome.error?.details?.reason, 'provider-credentials-changed'); - assert.match(String(outcome.error?.message), /started without the browserstack credentials/); -}); - -function testMuPluginEnv(): Record { - const manifest = path.resolve( - import.meta.dirname, - '../../../../packages/provider-testmu/package.json', - ); - const { home, env } = pluginHome(); - selectPluginManifest(home, JSON.parse(fs.readFileSync(manifest, 'utf8'))); - return env; -} - -test('a daemon holding other TestMu AI credentials refuses before allocation', async () => { - const home = testMuPluginEnv(); - const daemonEnv = { ...home, LT_USERNAME: 'user', LT_ACCESS_KEY: 'key-1' }; - const outcome = await allocateWithDaemonEnv( - providerAllocateRequest( - 'testmu', - providerCredentialFingerprint('testmu', { ...daemonEnv, LT_ACCESS_KEY: 'key-2' }), - ), - daemonEnv, - ); - - assert.equal(outcome.allocations, 0); - assert.equal(outcome.error?.code, 'INVALID_ARGS'); - assert.equal(outcome.error?.details?.reason, 'provider-credentials-changed'); - assert.equal(outcome.error?.details?.provider, 'testmu'); -}); - -test('a daemon holding the TestMu AI credentials of the shell allocates', async () => { - const env = { ...testMuPluginEnv(), LT_USERNAME: 'user', LT_ACCESS_KEY: 'key-1' }; - const outcome = await allocateWithDaemonEnv( - providerAllocateRequest('testmu', providerCredentialFingerprint('testmu', env)), - env, - ); - - assert.equal(outcome.error, undefined); - assert.equal(outcome.allocations, 1); -}); - -test('a daemon started without TestMu AI credentials refuses a shell that has them', async () => { - const home = testMuPluginEnv(); - const outcome = await allocateWithDaemonEnv( - providerAllocateRequest( - 'testmu', - providerCredentialFingerprint('testmu', { - ...home, - LT_USERNAME: 'user', - LT_ACCESS_KEY: 'key-1', - }), - ), - home, - ); - - assert.equal(outcome.allocations, 0); - assert.equal(outcome.error?.details?.reason, 'provider-credentials-changed'); - assert.match(String(outcome.error?.message), /started without the testmu credentials/); -}); - test('a tenant cannot allocate a macos-app lease', async () => { const registry = new LeaseRegistry(); const request: DaemonRequest = { diff --git a/src/daemon/handlers/__tests__/react-native.test.ts b/src/daemon/handlers/__tests__/react-native.test.ts index 8b7dd20441..c2bf743cbd 100644 --- a/src/daemon/handlers/__tests__/react-native.test.ts +++ b/src/daemon/handlers/__tests__/react-native.test.ts @@ -11,7 +11,7 @@ import { resetGetRuntimeFixture, } from '../../__tests__/interaction-get-runtime-fixture.ts'; import { refFrameState } from '../../ref-frame.ts'; -import { testCreateCommandSurface } from '../../__tests__/command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from '../../__tests__/support/command-surface-fake.ts'; vi.mock('../../snapshot-capture.ts', () => ({ captureSnapshot: vi.fn(), @@ -64,7 +64,7 @@ test('react-native dismiss-overlay taps collapsed warning close affordance inste }); const response = await handleReactNativeCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, req: { token: 't', session: sessionName, @@ -123,7 +123,7 @@ test('react-native dismiss-overlay prefers non-trailing collapsed warning close }); const response = await handleReactNativeCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, req: { token: 't', session: sessionName, @@ -192,7 +192,7 @@ test('react-native dismiss-overlay does not confuse app dismiss buttons with ove }); const response = await handleReactNativeCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, req: { token: 't', session: sessionName, @@ -243,7 +243,7 @@ test('react-native dismiss-overlay rejects unsafe collapsed warning coordinate f }); const response = await handleReactNativeCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, req: { token: 't', session: sessionName, @@ -306,7 +306,7 @@ test('react-native dismiss-overlay dismisses RedBox error overlays instead of mi }); const response = await handleReactNativeCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, req: { token: 't', session: sessionName, @@ -373,7 +373,7 @@ test('react-native dismiss-overlay reports unverified dismiss when RedBox contro .mockResolvedValueOnce(fullRedBoxSnapshot); const response = await handleReactNativeCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, req: { token: 't', session: sessionName, @@ -426,7 +426,7 @@ test('react-native dismiss-overlay uses Dismiss when RedBox Minimize is absent', }); const response = await handleReactNativeCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, req: { token: 't', session: sessionName, @@ -478,7 +478,7 @@ test('react-native dismiss-overlay accepts RedBox control labels with keyboard s }); const response = await handleReactNativeCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, req: { token: 't', session: sessionName, @@ -538,7 +538,7 @@ test('react-native dismiss-overlay prefers concrete RedBox buttons over labeled }); const response = await handleReactNativeCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, req: { token: 't', session: sessionName, @@ -602,7 +602,7 @@ test('react-native dismiss-overlay reports verified success after a clean post-d }); const response = await handleReactNativeCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, req: { token: 't', session: sessionName, @@ -667,7 +667,7 @@ test('react-native dismiss-overlay reports sparse verdict instead of no overlay }); const response = await handleReactNativeCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, req: { token: 't', session: sessionName, @@ -740,7 +740,7 @@ test('react-native dismiss-overlay reports unverified dismiss when post-dismiss }); const response = await handleReactNativeCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, req: { token: 't', session: sessionName, @@ -791,7 +791,7 @@ test('react-native dismiss-overlay reports still-visible overlays with recovery mockCaptureSnapshot.mockResolvedValueOnce(overlaySnapshot).mockResolvedValueOnce(overlaySnapshot); const response = await handleReactNativeCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, req: { token: 't', session: sessionName, @@ -835,7 +835,7 @@ test('react-native dismiss-overlay ignores app copy that only mentions RN overla }); const response = await handleReactNativeCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, req: { token: 't', session: sessionName, diff --git a/src/daemon/handlers/__tests__/session-appstate-input.test.ts b/src/daemon/handlers/__tests__/session-appstate-input.test.ts index 7239c0cf6f..badd02449c 100644 --- a/src/daemon/handlers/__tests__/session-appstate-input.test.ts +++ b/src/daemon/handlers/__tests__/session-appstate-input.test.ts @@ -29,7 +29,7 @@ import { type RuntimeFacts, } from '@agent-device/contracts/platform-runtime'; import type { BindDeviceRuntime } from '../../request-runtime-binding.ts'; -import { testCreateCommandSurface } from '../../__tests__/command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from '../../__tests__/support/command-surface-fake.ts'; test('appstate on iOS requires active session on selected device', async () => { const sessionStore = makeSessionStore(); @@ -56,7 +56,7 @@ test('appstate on iOS requires active session on selected device', async () => { mockDispatch.mockRejectedValue(new Error('snapshot dispatch should not run')); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -104,7 +104,7 @@ test('appstate returns session appName when bundle id is unavailable', async () mockDispatch.mockRejectedValue(new Error('snapshot dispatch should not run')); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -155,7 +155,7 @@ test('appstate fails when iOS session has no tracked app', async () => { mockResolveTargetDevice.mockResolvedValue(selectedDevice); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -190,7 +190,7 @@ test('appstate without session on iOS selector returns SESSION_NOT_FOUND', async mockResolveTargetDevice.mockResolvedValue(selectedDevice); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -215,7 +215,7 @@ test('appstate without session on iOS selector returns SESSION_NOT_FOUND', async test('appstate with explicit missing session returns SESSION_NOT_FOUND', async () => { const sessionStore = makeSessionStore(); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -242,7 +242,7 @@ test('appstate with explicit missing session returns SESSION_NOT_FOUND', async ( test('clipboard requires an active session or explicit device selector', async () => { const sessionStore = makeSessionStore(); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -284,7 +284,7 @@ test('clipboard rejects unsupported iOS physical devices', async () => { mockDispatch.mockRejectedValue(new Error('dispatch should not run for unsupported targets')); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -371,7 +371,7 @@ test('appstate on iOS reads the session app state from the runner when its owner }); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: iosSessionRequest(sessionName), sessionName, @@ -404,7 +404,7 @@ test('appstate on iOS keeps the session answer, with no state, when no runner is const runtime = appleAppStateRuntime(async () => ({})); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: iosSessionRequest(sessionName), sessionName, @@ -435,7 +435,7 @@ test('appstate on iOS keeps the session answer, with no state, when the runner c }); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: iosSessionRequest(sessionName), sessionName, diff --git a/src/daemon/handlers/__tests__/session-boot-warmup.test.ts b/src/daemon/handlers/__tests__/session-boot-warmup.test.ts index 9dc700aa65..fea012e006 100644 --- a/src/daemon/handlers/__tests__/session-boot-warmup.test.ts +++ b/src/daemon/handlers/__tests__/session-boot-warmup.test.ts @@ -7,7 +7,7 @@ import { } from './session-test-harness.ts'; import { expect, test } from 'vitest'; import { handleSessionCommands } from './session-command-harness.ts'; -import { testCreateCommandSurface } from '../../__tests__/command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from '../../__tests__/support/command-surface-fake.ts'; test('boot leaves Apple keep-hot policy inside the platform runtime', async () => { mockResolveTargetDevice.mockResolvedValue({ @@ -21,7 +21,7 @@ test('boot leaves Apple keep-hot policy inside the platform runtime', async () = }); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', diff --git a/src/daemon/handlers/__tests__/session-boot.test.ts b/src/daemon/handlers/__tests__/session-boot.test.ts index 2eaca00dc4..f573c2ac2c 100644 --- a/src/daemon/handlers/__tests__/session-boot.test.ts +++ b/src/daemon/handlers/__tests__/session-boot.test.ts @@ -22,12 +22,12 @@ import { mockInspectDeviceRuntimeFacts, } from './session-command-harness.ts'; import { mkdtempForTestSync } from '@agent-device/test-kit/tmp-dir'; -import { testCreateCommandSurface } from '../../__tests__/command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from '../../__tests__/support/command-surface-fake.ts'; test('boot requires session or explicit selector', async () => { const sessionStore = makeSessionStore(); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -71,7 +71,7 @@ test('boot prefers explicit device selector over active session device', async ( mockResolveTargetDevice.mockResolvedValue(selectedDevice); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -117,7 +117,7 @@ test('boot --timeout forwards a startup deadline to bootTarget (#3004)', async ( const beforeMs = Date.now(); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -152,7 +152,7 @@ test('boot without --timeout leaves the startup deadline unset', async () => { mockResolveTargetDevice.mockResolvedValue(selectedDevice); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -189,7 +189,7 @@ test('boot --headless admits a stopped Android emulator through facts and binds booted: true, }); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -235,7 +235,7 @@ test('boot rejects the macOS host boot cell after one facts inspection and befor mockResolveTargetDevice.mockResolvedValue(device); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -273,7 +273,7 @@ test('boot admits a stopped Android emulator through normal readiness', async () booted: true, }); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -312,7 +312,7 @@ test('boot forwards Android serial admission policy to readiness', async () => { }); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -348,7 +348,7 @@ test('boot --headless requires avd selector when device cannot be resolved', asy const sessionStore = makeSessionStore(); mockResolveTargetDevice.mockRejectedValue(new AppError('DEVICE_NOT_FOUND', 'No device found')); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -385,7 +385,7 @@ test('boot --headless rejects non-Android selectors', async () => { booted: false, }); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -420,7 +420,7 @@ test('boot keeps --target validation before facts inspection', async () => { booted: false, }); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', diff --git a/src/daemon/handlers/__tests__/session-command-harness.ts b/src/daemon/handlers/__tests__/session-command-harness.ts index 3e1a46d387..9600a43f45 100644 --- a/src/daemon/handlers/__tests__/session-command-harness.ts +++ b/src/daemon/handlers/__tests__/session-command-harness.ts @@ -25,7 +25,7 @@ import { beforeEach, vi } from 'vitest'; import { applicationLifecycleRuntimeFixture } from '../../__tests__/application-lifecycle-runtime-fixture.ts'; import { withClientReplayScriptSources } from '../../../__tests__/test-utils/replay-script-source.ts'; import { createUnavailableRuntimeFactsForTest } from '@agent-device/test-kit/runtime-operation-facts'; -import { platformResourceCleanup } from '../../../platform-runtime-resource-cleanup.ts'; +import { platformResourceCleanupFixture } from '../../__tests__/support/platform-resource-cleanup-fixture.ts'; const unavailable = Object.freeze({ available: false, @@ -101,7 +101,7 @@ export async function handleSessionCommands( req: await withClientReplayScriptSources(params.req), inspectFacts: params.inspectFacts ?? mockInspectDeviceRuntimeFacts, bindDevice: params.bindDevice ?? mockBindDeviceRuntime, - platformResourceCleanup: params.platformResourceCleanup ?? platformResourceCleanup, + platformResourceCleanup: params.platformResourceCleanup ?? platformResourceCleanupFixture(), reconcileOrphanedDeviceClaim: async () => ({ status: 'retained', reason: 'test-harness-has-no-exact-owner-recovery', diff --git a/src/daemon/handlers/__tests__/session-command-replay.test.ts b/src/daemon/handlers/__tests__/session-command-replay.test.ts index 3ed65a5758..099b8272c9 100644 --- a/src/daemon/handlers/__tests__/session-command-replay.test.ts +++ b/src/daemon/handlers/__tests__/session-command-replay.test.ts @@ -8,7 +8,7 @@ import type { DaemonRequest } from '../../daemon-request.ts'; import { replayScriptSourceBundleFor } from '../../../__tests__/test-utils/replay-script-source.ts'; import { mkdtempForTestSync } from '@agent-device/test-kit/tmp-dir'; -import { testCreateCommandSurface } from '../../__tests__/command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from '../../__tests__/support/command-surface-fake.ts'; test('replay parses open --relaunch flag and replays open with relaunch semantics', async () => { const sessionStore = makeSessionStore(); @@ -18,7 +18,7 @@ test('replay parses open --relaunch flag and replays open with relaunch semantic const invoked: DaemonRequest[] = []; const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -58,7 +58,7 @@ test('replay parses runtime set flags and replays runtime command', async () => const invoked: DaemonRequest[] = []; const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -99,7 +99,7 @@ test('replay parses inline open runtime flags and replays open with runtime payl const invoked: DaemonRequest[] = []; const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -145,7 +145,7 @@ test('replay delivers scroll --until and wait --raw flags to the dispatched step const invoked: DaemonRequest[] = []; const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -182,7 +182,7 @@ test('replay inherits parent device selectors for each invoked step', async () = const invoked: DaemonRequest[] = []; const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -223,7 +223,7 @@ test('replay inherits the parent web platform selector for each invoked step', a const invoked: DaemonRequest[] = []; const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -268,7 +268,7 @@ test('test --platform web reports no matching scripts, typed or untyped, because fs.writeFileSync(path.join(root, '02-android.ad'), 'context platform=android\nopen "Demo"\n'); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', diff --git a/src/daemon/handlers/__tests__/session-device-claims.test.ts b/src/daemon/handlers/__tests__/session-device-claims.test.ts index 2c1d1b00e8..9bd6075363 100644 --- a/src/daemon/handlers/__tests__/session-device-claims.test.ts +++ b/src/daemon/handlers/__tests__/session-device-claims.test.ts @@ -4,7 +4,7 @@ import fs from 'node:fs'; import path from 'node:path'; import { afterEach, test, vi } from 'vitest'; import { mkdtempForTestSync } from '@agent-device/test-kit/tmp-dir'; -import { testCreateCommandSurface } from '../../__tests__/command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from '../../__tests__/support/command-surface-fake.ts'; vi.mock('@agent-device/device-selection/dispatch-resolve', async (importOriginal) => { const actual = @@ -67,7 +67,7 @@ import { inspectProviderLifecycleRuntimeFacts, inspectLifecycleRuntimeFacts, } from '../../__tests__/application-lifecycle-runtime-harness.ts'; -import { platformResourceCleanup } from '../../../platform-runtime-resource-cleanup.ts'; +import { platformResourceCleanupFixture } from '../../__tests__/support/platform-resource-cleanup-fixture.ts'; const mockDispatch = vi.mocked(dispatchApplicationLifecycleEffect); const mockDiscoverReadyAndroidEmulators = vi.mocked(discoverReadyAndroidEmulators); @@ -96,7 +96,7 @@ function handleCloseCommand( ) { return handleProductionCloseCommand({ ...params, - platformResourceCleanup, + platformResourceCleanup: platformResourceCleanupFixture(), inspectFacts: inspectLifecycleRuntimeFacts, bindDevice: bindLifecycleRuntime, }); @@ -145,7 +145,7 @@ test('failed local open before device setup rolls its device claim back', async await assert.rejects( async () => handleOpenCommand({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { command: 'open', @@ -174,7 +174,7 @@ test('failed local open after dispatch retains its device claim for recovery', a await assert.rejects( async () => handleOpenCommand({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { command: 'open', @@ -206,7 +206,7 @@ test('failed local runtime-hint setup retains its device claim before open dispa await assert.rejects( async () => handleOpenCommand({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { command: 'open', @@ -234,7 +234,7 @@ test('failed local open response rolls its device claim back', async () => { mockResolveTargetDevice.mockResolvedValue(android); const response = await handleOpenCommand({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { command: 'open', @@ -262,7 +262,7 @@ test('cancellation after local device setup retains the device claim for recover try { const response = await handleOpenCommand({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { command: 'open', @@ -295,7 +295,7 @@ test('a canceled attempt lets the next attempt of the same suite open the device markRequestCanceled(requestId); try { const timedOut = await handleOpenCommand({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { command: 'open', @@ -316,7 +316,7 @@ test('a canceled attempt lets the next attempt of the same suite open the device assert.equal(store.get('suite:1-gesture-pan-duration:attempt-1'), undefined); const retry = await handleOpenCommand({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { command: 'open', @@ -346,7 +346,7 @@ test('provider-owned open creates no host-local device claim from its selected o mockDispatch.mockResolvedValue(undefined); const response = await handleOpenCommand({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { command: 'open', @@ -384,7 +384,7 @@ test('a foreign live claim rejects open before platform preparation or mutation' if (acquired.status !== 'acquired') return; const response = await handleOpenCommand({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { command: 'open', @@ -559,7 +559,7 @@ test('an open under a macos-app lease holds only its app, beside other claims on }); const response = await handleOpenCommand({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { command: 'open', diff --git a/src/daemon/handlers/__tests__/session-install-source-ref-frame.test.ts b/src/daemon/handlers/__tests__/session-install-source-ref-frame.test.ts index 79dae6075c..e9bf6e62d8 100644 --- a/src/daemon/handlers/__tests__/session-install-source-ref-frame.test.ts +++ b/src/daemon/handlers/__tests__/session-install-source-ref-frame.test.ts @@ -12,7 +12,7 @@ import { mockMaterializeAppSourceRuntime, } from './session-command-harness.ts'; import { activateCompleteRefFrame, refFrameState } from '../../ref-frame.ts'; -import { testCreateCommandSurface } from '../../__tests__/command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from '../../__tests__/support/command-surface-fake.ts'; const invoke = async (): Promise => { throw new Error('install_source ref-frame tests must stay on the runtime route'); @@ -116,7 +116,7 @@ async function dispatchInstallSource(params: { meta: { installSource: { kind: 'path', path: '/tmp/App.apk' } }, }; return await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req, sessionName: 'default', diff --git a/src/daemon/handlers/__tests__/session-push-ref-frame.test.ts b/src/daemon/handlers/__tests__/session-push-ref-frame.test.ts index 40dc7c2465..3c0e220351 100644 --- a/src/daemon/handlers/__tests__/session-push-ref-frame.test.ts +++ b/src/daemon/handlers/__tests__/session-push-ref-frame.test.ts @@ -11,7 +11,7 @@ import { mockPushNotificationRuntime, } from './session-command-harness.ts'; import { activateCompleteRefFrame, refFrameState } from '../../ref-frame.ts'; -import { testCreateCommandSurface } from '../../__tests__/command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from '../../__tests__/support/command-surface-fake.ts'; const invoke = async (): Promise => { throw new Error('push ref-frame tests must stay on the runtime route'); @@ -91,7 +91,7 @@ async function dispatchPush(params: { flags: {}, }; return await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req, sessionName: 'default', diff --git a/src/daemon/handlers/__tests__/session-push.test.ts b/src/daemon/handlers/__tests__/session-push.test.ts index cc0ee82be6..9627e7a7ee 100644 --- a/src/daemon/handlers/__tests__/session-push.test.ts +++ b/src/daemon/handlers/__tests__/session-push.test.ts @@ -17,7 +17,7 @@ import { mockInspectDeviceRuntimeFacts, mockPushNotificationRuntime, } from './session-command-harness.ts'; -import { testCreateCommandSurface } from '../../__tests__/command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from '../../__tests__/support/command-surface-fake.ts'; const invoke = async (_req: DaemonRequest): Promise => { return { @@ -29,7 +29,7 @@ const invoke = async (_req: DaemonRequest): Promise => { test('push requires active session or explicit device selector', async () => { const sessionStore = makeSessionStore('agent-device-session-push-'); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -68,7 +68,7 @@ test('push validates payload before runtime facts admission', async () => { await expect( handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -110,7 +110,7 @@ test('push runs readiness and notification through one admitted runtime binding' }); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -177,7 +177,7 @@ test('push treats an existing brace-prefixed payload as a file before inline JSO try { const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -217,7 +217,7 @@ test('push stops at unavailable facts without binding', async () => { }); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -273,7 +273,7 @@ test('push fails closed before binding when a provider owner lacks readiness', a }; const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', diff --git a/src/daemon/handlers/__tests__/session-reinstall.test.ts b/src/daemon/handlers/__tests__/session-reinstall.test.ts index 7dcfef44bc..28c27eb420 100644 --- a/src/daemon/handlers/__tests__/session-reinstall.test.ts +++ b/src/daemon/handlers/__tests__/session-reinstall.test.ts @@ -11,7 +11,7 @@ import type { import { SessionStore } from '../../session-store.ts'; import type { DaemonRequest, DaemonResponse } from '../../daemon-request.ts'; import type { SessionState } from '../../session-state.ts'; -import { testCreateCommandSurface } from '../../__tests__/command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from '../../__tests__/support/command-surface-fake.ts'; vi.mock('@agent-device/device-selection/dispatch-resolve', async (importOriginal) => { const actual = @@ -50,7 +50,7 @@ beforeEach(() => { test('reinstall requires active session or explicit device selector', async () => { const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -86,7 +86,7 @@ test('reinstall validates required args before runtime admission', async () => { }), ); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -124,7 +124,7 @@ test('install binds the deployment use exactly once after one facts admission', }); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -189,7 +189,7 @@ test('install fails closed before binding when its provider owner lacks deployme }; const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -235,7 +235,7 @@ test('reinstall cleans an uploaded artifact after the request-scoped operation', vi.mocked(resolveTargetDevice).mockResolvedValue(session.device); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -271,7 +271,7 @@ test('HarmonyOS reinstall updates the active session identity from the runtime r mockDeployAppRuntime.mockResolvedValue({ packageName: 'com.example.application' }); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -322,7 +322,7 @@ test.each(['rebuild', 'retire'] as const)( return { packageName: 'com.example.updated' }; }); const running = handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', diff --git a/src/daemon/handlers/__tests__/session-relaunch-close.test.ts b/src/daemon/handlers/__tests__/session-relaunch-close.test.ts index dc8263b1e7..cf4dacf64b 100644 --- a/src/daemon/handlers/__tests__/session-relaunch-close.test.ts +++ b/src/daemon/handlers/__tests__/session-relaunch-close.test.ts @@ -1,16 +1,12 @@ import { test, expect, vi, beforeEach } from 'vitest'; import * as path from 'node:path'; import { LeaseRegistry } from '../../lease-registry.ts'; -import { - isActiveProviderDevice, - setActiveProviderDeviceRuntimes, -} from '../../../provider-device-runtime.ts'; -import { installProviderDeviceAdmission } from '../../provider-device-admission.ts'; -import { testCreateCommandSurface } from '../../__tests__/command-surface-fixture.ts'; - -// The daemon reads provider ownership through its own typed admission seam; production -// installs it from root composition, and these tests compose it the same way. -installProviderDeviceAdmission({ isActive: isActiveProviderDevice }); +import { providerDeviceAdmissionFixture } from '../../__tests__/support/provider-device-admission-fixture.ts'; +import { fakeCreateCommandSurface } from '../../__tests__/support/command-surface-fake.ts'; + +// The daemon reads provider ownership through its own typed admission seam; these suites +// install the seam over runtime fakes, the way root composition installs the real one. +const providerAdmission = providerDeviceAdmissionFixture(); import { createTestDeviceInventoryGateways } from '../../../__tests__/test-utils/device-inventory-gateways.ts'; import { makeSessionStore } from '../../__tests__/support/store-factory.ts'; import { makeSession } from '../../__tests__/support/session-factories.ts'; @@ -122,7 +118,7 @@ function createHandler( leaseRegistry: LeaseRegistry = new LeaseRegistry(), ) { return createRequestHandler({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, logPath: path.join(mkdtempForTestSync('daemon'), 'daemon.log'), token: 'test-token', sessionStore, @@ -238,7 +234,7 @@ test('open --relaunch does not let an ambient provider claim suppress a local pr kind: 'emulator' as const, booted: true, }; - setActiveProviderDeviceRuntimes([ + providerAdmission.setActive([ { provider: 'fake-provider', leaseLifecycle: {}, @@ -270,7 +266,7 @@ test('open --relaunch does not let an ambient provider claim suppress a local pr { command: 'open', positionals: ['com.example.app'] }, ]); } finally { - setActiveProviderDeviceRuntimes([]); + providerAdmission.setActive([]); } }); diff --git a/src/daemon/handlers/__tests__/session-relaunch-guards.test.ts b/src/daemon/handlers/__tests__/session-relaunch-guards.test.ts index 9a72660520..c47a1e74ba 100644 --- a/src/daemon/handlers/__tests__/session-relaunch-guards.test.ts +++ b/src/daemon/handlers/__tests__/session-relaunch-guards.test.ts @@ -12,12 +12,12 @@ import { import { handleSessionCommands } from './session-command-harness.ts'; import { makeTestScreenRecordingResource } from '../../__tests__/support/screen-recording-live-handle.ts'; import { mkdtempForTestSync } from '@agent-device/test-kit/tmp-dir'; -import { testCreateCommandSurface } from '../../__tests__/command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from '../../__tests__/support/command-surface-fake.ts'; test('open --relaunch rejects URL targets', async () => { const sessionStore = makeSessionStore(); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -43,7 +43,7 @@ test('open --relaunch rejects URL targets', async () => { test('open --relaunch fails without app when no session exists', async () => { const sessionStore = makeSessionStore(); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -69,7 +69,7 @@ test('open --relaunch fails without app when no session exists', async () => { test('open --relaunch rejects Android app binary paths', async () => { const sessionStore = makeSessionStore(); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -93,7 +93,7 @@ test('open --relaunch rejects Android app binary paths', async () => { test('open --relaunch rejects bare Android app binary filenames', async () => { const sessionStore = makeSessionStore(); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -128,7 +128,7 @@ test('open --relaunch rejects Android app binary paths for active sessions', asy sessionStore.publish('default', session); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -152,7 +152,7 @@ test('open --relaunch rejects Android app binary paths for active sessions', asy test('open --relaunch rejects Android app binary paths before resolving a new device', async () => { const sessionStore = makeSessionStore(); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -197,7 +197,7 @@ test('open on in-use device returns DEVICE_IN_USE before readiness checks', asyn }); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -253,7 +253,7 @@ test('open on device owned by recording session returns recording recovery hint' }); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', diff --git a/src/daemon/handlers/__tests__/session-replay-command.test.ts b/src/daemon/handlers/__tests__/session-replay-command.test.ts index 9734ff8cad..395c5478ff 100644 --- a/src/daemon/handlers/__tests__/session-replay-command.test.ts +++ b/src/daemon/handlers/__tests__/session-replay-command.test.ts @@ -6,18 +6,18 @@ import { unavailableBindExactDevice, } from '../../__tests__/test-device-runtime-gateway.ts'; import { createScreenRecordingAdmissionLedger } from '@agent-device/capture-kit/screen-recording-admission-ledger'; -import { platformResourceCleanup } from '../../../platform-runtime-resource-cleanup.ts'; +import { platformResourceCleanupFixture } from '../../__tests__/support/platform-resource-cleanup-fixture.ts'; import type { SessionCommandParams } from '../session-command-input.ts'; import { handleReplayTestCommand } from '../session-replay-command.ts'; import { daemonPlatformServicesFixture } from '../../__tests__/platform-services-fixture.ts'; import { makeSessionStore } from './session-test-harness.ts'; import { mkdtempForTestSync } from '@agent-device/test-kit/tmp-dir'; -import { testCreateCommandSurface } from '../../__tests__/command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from '../../__tests__/support/command-surface-fake.ts'; test('replay test handler threads the complete video owner into the application command', async () => { const root = mkdtempForTestSync('agent-device-replay-handler-video-'); const params: SessionCommandParams = { - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, req: { token: 'token', session: 'default', @@ -46,7 +46,7 @@ test('replay test handler threads the complete video owner into the application status: 'retained' as const, reason: 'handler-test' as const, }), - platformResourceCleanup, + platformResourceCleanup: platformResourceCleanupFixture(), }; const response = await handleReplayTestCommand(params); diff --git a/src/daemon/handlers/__tests__/session-runtime-command.test.ts b/src/daemon/handlers/__tests__/session-runtime-command.test.ts index 498407c62d..64108a82f6 100644 --- a/src/daemon/handlers/__tests__/session-runtime-command.test.ts +++ b/src/daemon/handlers/__tests__/session-runtime-command.test.ts @@ -22,7 +22,7 @@ import { } from '../../__tests__/test-device-runtime-gateway.ts'; import { refFrameState } from '../../ref-frame.ts'; import { mkdtempForTestSync } from '@agent-device/test-kit/tmp-dir'; -import { testCreateCommandSurface } from '../../__tests__/command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from '../../__tests__/support/command-surface-fake.ts'; test('runtime set/show/clear manages session-scoped runtime hints before open', async () => { const sessionStore = makeSessionStore(); @@ -32,7 +32,7 @@ test('runtime set/show/clear manages session-scoped runtime hints before open', } satisfies Pick; const setResponse = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { ...baseRequest, @@ -53,7 +53,7 @@ test('runtime set/show/clear manages session-scoped runtime hints before open', expect(setResponse?.ok).toBe(true); const showResponse = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { ...baseRequest, @@ -79,7 +79,7 @@ test('runtime set/show/clear manages session-scoped runtime hints before open', } const clearResponse = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { ...baseRequest, @@ -116,7 +116,7 @@ test('runtime clear removes applied transport hints for the active app', async ( }); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -167,7 +167,7 @@ test('runtime clear expires the ref frame at the admitted hint mutation boundary }); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -222,7 +222,7 @@ test('runtime clear rejects a false runtime-hints fact before its one implementa }); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -274,7 +274,7 @@ test('runtime gesture-viewport admits and binds the exact viewport operation onc gestureRuntimeSpies.gestureViewport.mockClear(); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -344,7 +344,7 @@ for (const phase of ['admission', 'effect'] as const) { } await expect( handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -387,7 +387,7 @@ test('runtime clear expires and uses the latest matching record after admission' return lifecycleRuntimeFacts(target); }); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', diff --git a/src/daemon/handlers/__tests__/session-selector-dispatch.test.ts b/src/daemon/handlers/__tests__/session-selector-dispatch.test.ts index 505eeb7f10..464129e73a 100644 --- a/src/daemon/handlers/__tests__/session-selector-dispatch.test.ts +++ b/src/daemon/handlers/__tests__/session-selector-dispatch.test.ts @@ -31,7 +31,7 @@ import { refFrameState } from '../../ref-frame.ts'; import { mkdtempForTestSync } from '@agent-device/test-kit/tmp-dir'; import { makeIosSession } from '../../__tests__/support/session-factories.ts'; import { createUnavailableRuntimeFactsForTest } from '@agent-device/test-kit/runtime-operation-facts'; -import { testCreateCommandSurface } from '../../__tests__/command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from '../../__tests__/support/command-surface-fake.ts'; const available = Object.freeze({ available: true } as const); const keyboardFamilyDenial = Object.freeze({ @@ -77,7 +77,7 @@ test.each(['rebuild', 'retire'] as const)( [Symbol.asyncDispose]: async () => {}, }; const running = handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -179,7 +179,7 @@ test('keyboard dismiss crosses the ADR 0014 seam while keyboard status preserves // dismiss mutates the device → frame expires. const dismissRef = sessionStore.publish(sessionName, makeSession(sessionName, device)); await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -201,7 +201,7 @@ test('keyboard dismiss crosses the ADR 0014 seam while keyboard status preserves sessionStore.retire(dismissRef); sessionStore.publish(sessionName, makeSession(sessionName, device)); await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -246,7 +246,7 @@ test('keyboard dismiss expires the frame before the invocation runs, even when i sessionStore.publish(sessionName, makeSession(sessionName, device)); await expect( handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -269,7 +269,7 @@ test('keyboard dismiss expires the frame before the invocation runs, even when i test('keyboard requires an active session or explicit device selector', async () => { const sessionStore = makeSessionStore(); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -298,7 +298,7 @@ test('keyboard dismiss requires active iOS session for explicit selectors', asyn const sessionStore = makeSessionStore(); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', diff --git a/src/daemon/handlers/__tests__/session-shutdown.test.ts b/src/daemon/handlers/__tests__/session-shutdown.test.ts index 2be602b6cd..c4429b692a 100644 --- a/src/daemon/handlers/__tests__/session-shutdown.test.ts +++ b/src/daemon/handlers/__tests__/session-shutdown.test.ts @@ -16,7 +16,7 @@ import { mockShutdownTargetRuntime, } from './session-command-harness.ts'; import { mkdtempForTestSync } from '@agent-device/test-kit/tmp-dir'; -import { testCreateCommandSurface } from '../../__tests__/command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from '../../__tests__/support/command-surface-fake.ts'; test('shutdown turns off selected iOS simulator', async () => { const sessionStore = makeSessionStore(); @@ -31,7 +31,7 @@ test('shutdown turns off selected iOS simulator', async () => { mockResolveTargetDevice.mockResolvedValue(selectedDevice); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -79,7 +79,7 @@ test('shutdown rejects active session device and points to close --shutdown', as mockResolveTargetDevice.mockResolvedValue(selectedDevice); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -120,7 +120,7 @@ test('shutdown turns off selected Android emulator', async () => { }); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -169,7 +169,7 @@ test('shutdown rejects unsupported physical devices', async () => { }); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -214,7 +214,7 @@ test('shutdown returns an error response when selected target shutdown fails', a }); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', diff --git a/src/daemon/handlers/__tests__/session-trigger.test.ts b/src/daemon/handlers/__tests__/session-trigger.test.ts index d383de850b..043878706f 100644 --- a/src/daemon/handlers/__tests__/session-trigger.test.ts +++ b/src/daemon/handlers/__tests__/session-trigger.test.ts @@ -4,7 +4,7 @@ import { test, expect } from 'vitest'; import { handleSessionCommands } from './session-command-harness.ts'; import type { DaemonRequest, DaemonResponse } from '../../daemon-request.ts'; import { makeSessionStore } from '../../__tests__/support/store-factory.ts'; -import { testCreateCommandSurface } from '../../__tests__/command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from '../../__tests__/support/command-surface-fake.ts'; const invoke = async (_req: DaemonRequest): Promise => { return { @@ -16,7 +16,7 @@ const invoke = async (_req: DaemonRequest): Promise => { test('trigger-app-event requires active session or explicit device selector', async () => { const sessionStore = makeSessionStore('agent-device-session-trigger-'); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', diff --git a/src/daemon/handlers/__tests__/session.test.ts b/src/daemon/handlers/__tests__/session.test.ts index 71b20c26f7..c193940715 100644 --- a/src/daemon/handlers/__tests__/session.test.ts +++ b/src/daemon/handlers/__tests__/session.test.ts @@ -4,7 +4,7 @@ import * as path from 'node:path'; import { handleSessionCommands } from './session-command-harness.ts'; import { makeSessionStore } from '../../__tests__/support/store-factory.ts'; import { mkdtempForTestSync } from '@agent-device/test-kit/tmp-dir'; -import { testCreateCommandSurface } from '../../__tests__/command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from '../../__tests__/support/command-surface-fake.ts'; import type { DaemonRequest } from '../../daemon-request.ts'; function request(command: string): DaemonRequest { @@ -13,7 +13,7 @@ function request(command: string): DaemonRequest { async function dispatch(command: string) { return await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: request(command), sessionName: 'default', diff --git a/src/daemon/handlers/__tests__/snapshot-alert.test.ts b/src/daemon/handlers/__tests__/snapshot-alert.test.ts index 9d4e4a0a7b..94e66d07ba 100644 --- a/src/daemon/handlers/__tests__/snapshot-alert.test.ts +++ b/src/daemon/handlers/__tests__/snapshot-alert.test.ts @@ -8,7 +8,7 @@ import { withAppleRunnerProvider } from '@agent-device/platform-apple/runner'; import { runAppleRunnerCommand } from '@agent-device/platform-apple/runner/operations'; import { mkdtempForTestSync } from '@agent-device/test-kit/tmp-dir'; import path from 'node:path'; -import { testCreateCommandSurface } from '../../__tests__/command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from '../../__tests__/support/command-surface-fake.ts'; vi.mock('@agent-device/platform-apple/runner/operations', async (importOriginal) => { const actual = @@ -41,7 +41,7 @@ async function handleSnapshotCommands( ): Promise>> { return await withAppleRunnerProvider(mockRunnerCommand, { deviceId: iosSimulatorDevice.id }, () => handleProductionSnapshotCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, req: { token: 't', session: sessionName, command: 'alert', positionals, flags: {} }, sessionName, logPath: '/tmp/daemon.log', diff --git a/src/daemon/handlers/__tests__/snapshot-handler.fixtures.ts b/src/daemon/handlers/__tests__/snapshot-handler.fixtures.ts index 20e0eec256..a5d350f263 100644 --- a/src/daemon/handlers/__tests__/snapshot-handler.fixtures.ts +++ b/src/daemon/handlers/__tests__/snapshot-handler.fixtures.ts @@ -13,7 +13,7 @@ import { SessionStore } from '../../session-store.ts'; import type { DaemonRequest } from '../../daemon-request.ts'; import type { SessionState } from '../../session-state.ts'; import { handleSnapshotCommands as handleProductionSnapshotCommands } from '../snapshot.ts'; -import { platformResourceCleanup } from '../../../platform-runtime-resource-cleanup.ts'; +import { platformResourceCleanupFixture } from '../../__tests__/support/platform-resource-cleanup-fixture.ts'; export function makeSessionStore(): SessionStore { const root = mkdtempForTestSync('agent-device-snapshot-handler-'); @@ -221,7 +221,7 @@ export function handleSnapshotCommands( if (!SNAPSHOT_ROUTE_RUNTIME_COMMANDS.has(params.req.command)) { return handleProductionSnapshotCommands({ ...params, - platformResourceCleanup: params.platformResourceCleanup ?? platformResourceCleanup, + platformResourceCleanup: params.platformResourceCleanup ?? platformResourceCleanupFixture(), }); } const runtime = snapshotRuntimeFixture(params.req.meta?.requestId); @@ -229,6 +229,6 @@ export function handleSnapshotCommands( ...params, inspectFacts: params.inspectFacts ?? runtime.inspectFacts, bindDevice: params.bindDevice ?? runtime.bindDevice, - platformResourceCleanup: params.platformResourceCleanup ?? platformResourceCleanup, + platformResourceCleanup: params.platformResourceCleanup ?? platformResourceCleanupFixture(), }); } diff --git a/src/daemon/handlers/__tests__/snapshot-settings-handler.test.ts b/src/daemon/handlers/__tests__/snapshot-settings-handler.test.ts index 0ba62d3a17..e9fb476c19 100644 --- a/src/daemon/handlers/__tests__/snapshot-settings-handler.test.ts +++ b/src/daemon/handlers/__tests__/snapshot-settings-handler.test.ts @@ -2,17 +2,13 @@ import { daemonPlatformServicesFixture } from '../../__tests__/platform-services import { test, expect, vi, afterEach, beforeEach } from 'vitest'; import { legacyDispatchCapture } from '../../__tests__/legacy-snapshot-capture-fixture.ts'; import { handleSnapshotCommands as handleProductionSnapshotCommands } from '../snapshot.ts'; -import { - isActiveProviderDevice, - setActiveProviderDeviceRuntimes, -} from '../../../provider-device-runtime.ts'; -import { installProviderDeviceAdmission } from '../../provider-device-admission.ts'; -import { testCreateCommandSurface } from '../../__tests__/command-surface-fixture.ts'; - -// The daemon reads provider ownership through its own typed admission seam; production -// installs it from root composition, and these tests compose it the same way. -installProviderDeviceAdmission({ isActive: isActiveProviderDevice }); -import { platformResourceCleanup } from '../../../platform-runtime-resource-cleanup.ts'; +import { providerDeviceAdmissionFixture } from '../../__tests__/support/provider-device-admission-fixture.ts'; +import { fakeCreateCommandSurface } from '../../__tests__/support/command-surface-fake.ts'; + +// The daemon reads provider ownership through its own typed admission seam; these suites +// install the seam over runtime fakes, the way root composition installs the real one. +const providerAdmission = providerDeviceAdmissionFixture(); +import { platformResourceCleanupFixture } from '../../__tests__/support/platform-resource-cleanup-fixture.ts'; import { fixtureSettingsMutations, fixtureSettingsReads, @@ -63,12 +59,12 @@ function handleSnapshotCommands( ...params, inspectFacts: params.inspectFacts ?? runtime.inspectFacts, bindDevice: params.bindDevice ?? runtime.bindDevice, - platformResourceCleanup: params.platformResourceCleanup ?? platformResourceCleanup, + platformResourceCleanup: params.platformResourceCleanup ?? platformResourceCleanupFixture(), }); } afterEach(() => { - setActiveProviderDeviceRuntimes([]); + providerAdmission.setActive([]); }); beforeEach(() => { @@ -96,7 +92,7 @@ test('settings rejects unsupported iOS physical devices', async () => { ); const response = await handleSnapshotCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: snapshotRequest(sessionName, 'settings', { positionals: ['wifi', 'on'] }), sessionName, @@ -118,7 +114,7 @@ test('settings clear-app-state dispatches explicit app id without an active app sessionStore.publish(sessionName, makeSession(sessionName, iosSimulatorDevice)); const response = await handleSnapshotCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: snapshotRequest(sessionName, 'settings', { positionals: ['clear-app-state', 'org.reactnavigation.playground'], @@ -142,7 +138,7 @@ test('settings clear-app-state rejects missing app id when no app session is bou sessionStore.publish(sessionName, makeSession(sessionName, iosSimulatorDevice)); const response = await handleSnapshotCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: snapshotRequest(sessionName, 'settings', { positionals: ['clear-app-state'] }), sessionName, @@ -166,7 +162,7 @@ test('settings reset-keychain dispatches without an app id or active app session sessionStore.publish(sessionName, makeSession(sessionName, iosSimulatorDevice)); const response = await handleSnapshotCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: snapshotRequest(sessionName, 'settings', { positionals: ['reset-keychain', 'clear'], @@ -189,7 +185,7 @@ test('settings reset-keychain rejects an extra app argument instead of dropping sessionStore.publish(sessionName, makeSession(sessionName, iosSimulatorDevice)); const response = await handleSnapshotCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: snapshotRequest(sessionName, 'settings', { positionals: ['reset-keychain', 'clear', 'com.example.app'], @@ -212,7 +208,7 @@ test('settings text-size reads the category the owner holds without mutating any sessionStore.publish(sessionName, makeSession(sessionName, iosSimulatorDevice)); const response = await handleSnapshotCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: snapshotRequest(sessionName, 'settings', { positionals: ['text-size'] }), sessionName, @@ -237,7 +233,7 @@ test('settings text-size refuses the macOS host on both legs with the same code' sessionStore.publish(sessionName, makeSession(sessionName, macOsDevice)); const read = await handleSnapshotCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: snapshotRequest(sessionName, 'settings', { positionals: ['text-size'] }), sessionName, @@ -245,7 +241,7 @@ test('settings text-size refuses the macOS host on both legs with the same code' sessionStore, }); const write = await handleSnapshotCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: snapshotRequest(sessionName, 'settings', { positionals: ['text-size', 'large'] }), sessionName, @@ -272,7 +268,7 @@ test('settings text-size applies a ladder category through the write leg', async sessionStore.publish(sessionName, session); const response = await handleSnapshotCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: snapshotRequest(sessionName, 'settings', { positionals: ['text-size', 'accessibility-extra-large'], @@ -306,7 +302,7 @@ test('settings text-size refuses an Apple leaf with no content size before it ex for (const positionals of [['text-size'], ['text-size', 'large']]) { const response = await handleSnapshotCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: snapshotRequest(sessionName, 'settings', { positionals }), sessionName, @@ -333,7 +329,7 @@ test('settings text-size refuses an off-ladder category with the whole ladder', sessionStore.publish(sessionName, makeSession(sessionName, iosSimulatorDevice)); const response = await handleSnapshotCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: snapshotRequest(sessionName, 'settings', { positionals: ['text-size', 'gigantic'] }), sessionName, @@ -357,7 +353,7 @@ test('settings text-size refuses an off-ladder category with the whole ladder', test('settings usage hint documents canonical faceid states', async () => { const sessionStore = makeSessionStore(); const response = await handleSnapshotCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: snapshotRequest('default', 'settings'), sessionName: 'default', @@ -382,7 +378,7 @@ test('settings on macOS rejects wifi before dispatch with explicit subset guidan sessionStore.publish(sessionName, makeSession(sessionName, macOsDevice)); const response = await handleSnapshotCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: snapshotRequest(sessionName, 'settings', { positionals: ['wifi', 'on'] }), sessionName, @@ -414,7 +410,7 @@ test('settings permission grant targets an explicit app with no session app boun sessionStore.publish(sessionName, makeSession(sessionName, iosSimulatorDevice)); const response = await handleSnapshotCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: snapshotRequest(sessionName, 'settings', { positionals: ['permission', 'grant', 'camera'], @@ -445,7 +441,7 @@ test('settings permission grant keeps the session app when no app is named', asy ); const response = await handleSnapshotCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: snapshotRequest(sessionName, 'settings', { positionals: ['permission', 'grant', 'camera'], @@ -470,7 +466,7 @@ test('settings permission grant prefers an explicit app over the session app', a ); const response = await handleSnapshotCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: snapshotRequest(sessionName, 'settings', { positionals: ['permission', 'grant', 'camera'], @@ -491,7 +487,7 @@ test('settings location on targets an explicit app on an iOS simulator', async ( sessionStore.publish(sessionName, makeSession(sessionName, iosSimulatorDevice)); const response = await handleSnapshotCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: snapshotRequest(sessionName, 'settings', { positionals: ['location', 'on'], @@ -516,7 +512,7 @@ test('settings Android permission grant targets an explicit app with no session sessionStore.publish(sessionName, makeSession(sessionName, androidDevice)); const response = await handleSnapshotCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: snapshotRequest(sessionName, 'settings', { positionals: ['permission', 'grant', 'camera'], @@ -543,7 +539,7 @@ test('settings Android location on refuses a named app before reaching the owner sessionStore.publish(sessionName, makeSession(sessionName, androidDevice)); const response = await handleSnapshotCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: snapshotRequest(sessionName, 'settings', { positionals: ['location', 'on'], @@ -577,7 +573,7 @@ test('settings iOS location 1 targets an explicit app over the session app', asy ); const response = await handleSnapshotCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: snapshotRequest(sessionName, 'settings', { positionals: ['location', '1'], @@ -602,7 +598,7 @@ test('settings Android location true refuses a named app before reaching the own sessionStore.publish(sessionName, makeSession(sessionName, androidDevice)); const response = await handleSnapshotCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: snapshotRequest(sessionName, 'settings', { positionals: ['location', 'true'], @@ -627,7 +623,7 @@ test('settings Android location 0 refuses a named app before reaching the owner' sessionStore.publish(sessionName, makeSession(sessionName, androidDevice)); const response = await handleSnapshotCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: snapshotRequest(sessionName, 'settings', { positionals: ['location', '0'], @@ -654,7 +650,7 @@ test('settings iOS location set refuses a named app before reaching the owner', sessionStore.publish(sessionName, makeSession(sessionName, iosSimulatorDevice)); const response = await handleSnapshotCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: snapshotRequest(sessionName, 'settings', { positionals: ['location', 'set', '37.7', '-122.4'], @@ -682,7 +678,7 @@ test('settings macOS permission grant refuses a named app before reaching the ow sessionStore.publish(sessionName, makeSession(sessionName, macOsDevice)); const response = await handleSnapshotCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: snapshotRequest(sessionName, 'settings', { positionals: ['permission', 'grant', 'screen-recording'], diff --git a/src/daemon/handlers/snapshot-runtime-route.test.ts b/src/daemon/handlers/snapshot-runtime-route.test.ts index 5a1a914404..f2abc611d6 100644 --- a/src/daemon/handlers/snapshot-runtime-route.test.ts +++ b/src/daemon/handlers/snapshot-runtime-route.test.ts @@ -1,6 +1,6 @@ import { daemonPlatformServicesFixture } from '../__tests__/platform-services-fixture.ts'; import { beforeEach, expect, test, vi } from 'vitest'; -import { testCreateCommandSurface } from '../__tests__/command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from '../__tests__/support/command-surface-fake.ts'; const { dispatchSnapshotDiffViaRuntime, dispatchSnapshotViaRuntime } = vi.hoisted(() => ({ dispatchSnapshotDiffViaRuntime: vi.fn(), @@ -39,7 +39,7 @@ test('snapshot route forwards the request runtime facts and binding seams exactl const platformServices = daemonPlatformServicesFixture(); await handleSnapshotCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices, req, sessionName: 'snapshot-route', @@ -51,7 +51,7 @@ test('snapshot route forwards the request runtime facts and binding seams exactl expect(dispatchSnapshotViaRuntime).toHaveBeenCalledOnce(); expect(dispatchSnapshotViaRuntime).toHaveBeenCalledWith({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, req, sessionName: 'snapshot-route', logPath: '/tmp/snapshot-route.log', @@ -76,7 +76,7 @@ test('diff route forwards the request runtime facts and binding seams exactly on const platformServices = daemonPlatformServicesFixture(); await handleSnapshotCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices, req, sessionName: 'diff-route', @@ -88,7 +88,7 @@ test('diff route forwards the request runtime facts and binding seams exactly on expect(dispatchSnapshotDiffViaRuntime).toHaveBeenCalledOnce(); expect(dispatchSnapshotDiffViaRuntime).toHaveBeenCalledWith({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, req, sessionName: 'diff-route', logPath: '/tmp/diff-route.log', diff --git a/src/daemon/interaction/internal/__tests__/find-handler-fixture.ts b/src/daemon/interaction/internal/__tests__/find-handler-fixture.ts index d5cddc5d4b..5b26c59892 100644 --- a/src/daemon/interaction/internal/__tests__/find-handler-fixture.ts +++ b/src/daemon/interaction/internal/__tests__/find-handler-fixture.ts @@ -2,7 +2,8 @@ import type { SessionStore } from '../../../session-store.ts'; import type { DaemonRequest, DaemonResponse } from '../../../daemon-request.ts'; import { handleFindCommands } from '../find.ts'; import { getRuntimeBindings } from '../../../__tests__/interaction-get-runtime-fixture.ts'; -import { testCreateCommandSurface } from '../../../__tests__/command-surface-fixture.ts'; +import type { CreateDaemonCommandSurface } from '@agent-device/contracts/daemon-command-surface'; +import { fakeCreateCommandSurface } from '../../../__tests__/support/command-surface-fake.ts'; /** * One `handleFindCommands` invocation shape. @@ -12,15 +13,16 @@ import { testCreateCommandSurface } from '../../../__tests__/command-surface-fix * rather than in any one `find*.test.ts` file, because several of those files share it. */ export function invokeFindHandler(params: { + createCommandSurface?: CreateDaemonCommandSurface; sessionName: string; sessionStore: SessionStore; positionals: string[]; flags?: DaemonRequest['flags']; invoke: (req: DaemonRequest) => Promise; }) { - const { sessionName, sessionStore, positionals, flags } = params; + const { sessionName, sessionStore, positionals, flags, createCommandSurface } = params; return handleFindCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: createCommandSurface ?? fakeCreateCommandSurface, req: { token: 't', session: sessionName, command: 'find', positionals, flags: flags ?? {} }, sessionName, logPath: '/tmp/test.log', diff --git a/src/daemon/interaction/internal/__tests__/find-target-activation-disclosure.test.ts b/src/daemon/interaction/internal/__tests__/find-target-activation-disclosure.test.ts index f5c593a42f..d686d53bef 100644 --- a/src/daemon/interaction/internal/__tests__/find-target-activation-disclosure.test.ts +++ b/src/daemon/interaction/internal/__tests__/find-target-activation-disclosure.test.ts @@ -9,7 +9,7 @@ import { getRuntimeBindings } from '../../../__tests__/interaction-get-runtime-f import { handleFindCommands } from '../../index.ts'; import { markDeferredInteractionOutcome } from '../../../deferred-interaction-outcome.ts'; import { formatPostGestureOutcomeWarning } from '@agent-device/capture-kit/post-gesture-stability'; -import { testCreateCommandSurface } from '../../../__tests__/command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from '../../../__tests__/support/command-surface-fake.ts'; vi.mock('../../../snapshot-interactor-capture.ts', async () => { const fixture = await import('../../../__tests__/legacy-snapshot-capture-fixture.ts'); @@ -91,7 +91,7 @@ async function findClick(captures: Record[] | CaptureScript, af ); const response = await handleFindCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, req: { token: 't', session: 'default', diff --git a/src/daemon/interaction/internal/__tests__/find-touch-runtime-fixture.ts b/src/daemon/interaction/internal/__tests__/find-touch-runtime-fixture.ts index 20663ac5d3..4c2ee94934 100644 --- a/src/daemon/interaction/internal/__tests__/find-touch-runtime-fixture.ts +++ b/src/daemon/interaction/internal/__tests__/find-touch-runtime-fixture.ts @@ -12,6 +12,7 @@ import { makeSessionStore } from '../../../__tests__/support/store-factory.ts'; import { makeIosSession as makeSession } from '../../../__tests__/support/session-factories.ts'; import type { DaemonRequest, DaemonResponse } from '../../../daemon-request.ts'; import type { SessionState } from '../../../session-state.ts'; +import type { CreateDaemonCommandSurface } from '@agent-device/contracts/daemon-command-surface'; import type { handleFindCommands } from '../find.ts'; import { invokeFindHandler } from './find-handler-fixture.ts'; @@ -61,6 +62,7 @@ export async function runFindClickScenario(options: { nodes?: Array>; flags?: DaemonRequest['flags']; session?: SessionState; + createCommandSurface?: CreateDaemonCommandSurface; invoke?: (req: DaemonRequest) => Promise>; }): Promise<{ response: NonNullable>>; @@ -83,6 +85,7 @@ export async function runFindClickScenario(options: { const invokeCalls: DaemonRequest[] = []; const response = await invokeFindHandler({ + createCommandSurface: options.createCommandSurface, sessionName, sessionStore, positionals: options.positionals, diff --git a/src/daemon/interaction/internal/__tests__/interaction-touch-fixtures.ts b/src/daemon/interaction/internal/__tests__/interaction-touch-fixtures.ts index b8b418f9c9..c9fbad50d5 100644 --- a/src/daemon/interaction/internal/__tests__/interaction-touch-fixtures.ts +++ b/src/daemon/interaction/internal/__tests__/interaction-touch-fixtures.ts @@ -7,12 +7,8 @@ import { } from '../../../__tests__/support/session-factories.ts'; import { makeTestScreenRecordingResource } from '../../../__tests__/support/screen-recording-live-handle.ts'; import { activateCompleteRefFrame } from '../../../ref-frame.ts'; -import type { SessionStore } from '../../../session-store.ts'; import type { SessionState } from '../../../session-state.ts'; -import { handleInteractionCommands } from '../../index.ts'; -import { getRuntimeBindings } from '../../../__tests__/interaction-get-runtime-fixture.ts'; import { buildSnapshotState } from '@agent-device/capture-kit/snapshot-state'; -import { testCreateCommandSurface } from '../../../__tests__/command-surface-fixture.ts'; /** * Shared factories for the interaction touch handler tests. Named pure @@ -120,23 +116,6 @@ export function makeStaleRefSession(sessionName: string): SessionState { return session; } -export async function runInteraction( - sessionStore: SessionStore, - sessionName: string, - command: string, - positionals: string[], - flags: Record = {}, -) { - return await handleInteractionCommands({ - createCommandSurface: testCreateCommandSurface, - req: { token: 't', session: sessionName, command, positionals, flags }, - sessionName, - sessionStore, - contextFromFlags, - ...getRuntimeBindings(), - }); -} - // #1654: the tree a mutating `find` matched against, deliberately NOT the tree // stored on the session. `@e2` names the "Continue" button in both trees, but // at a distinctive point here and at (60, 40) in the session frame tree — so @@ -164,28 +143,6 @@ export function findResolvedTarget( return { ref, node: preresolved.node, nodes: preresolved.nodes }; } -export async function runFindInternalClick( - sessionStore: SessionStore, - sessionName: string, - internal: Record, -) { - return await handleInteractionCommands({ - createCommandSurface: testCreateCommandSurface, - req: { - token: 't', - session: sessionName, - command: 'click', - positionals: ['@e2'], - flags: { noRecord: true }, - internal, - }, - sessionName, - sessionStore, - contextFromFlags, - ...getRuntimeBindings(), - }); -} - /** The coordinates the leaf handed to the bound point-tap operation. */ export function readPressPoint(mockTapPoint: { mock: { calls: unknown[][] }; diff --git a/src/daemon/interaction/internal/__tests__/interaction-type-android-readiness.test.ts b/src/daemon/interaction/internal/__tests__/interaction-type-android-readiness.test.ts index e927766077..fe3edf0530 100644 --- a/src/daemon/interaction/internal/__tests__/interaction-type-android-readiness.test.ts +++ b/src/daemon/interaction/internal/__tests__/interaction-type-android-readiness.test.ts @@ -10,7 +10,7 @@ import { mockTypeText, resetGetRuntimeFixture, } from '../../../__tests__/interaction-get-runtime-fixture.ts'; -import { testCreateCommandSurface } from '../../../__tests__/command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from '../../../__tests__/support/command-surface-fake.ts'; vi.mock('@agent-device/platform-android/mechanics', async (importOriginal) => { const actual = await importOriginal(); @@ -48,7 +48,7 @@ test('type continues and composes the recording readiness warning', async () => sessionStore.publish(sessionName, session); const response = await handleInteractionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, req: { token: 't', session: sessionName, diff --git a/src/daemon/server/daemon-runtime-device-claims.test.ts b/src/daemon/server/daemon-runtime-device-claims.test.ts index 55f97cd979..f530246768 100644 --- a/src/daemon/server/daemon-runtime-device-claims.test.ts +++ b/src/daemon/server/daemon-runtime-device-claims.test.ts @@ -2,7 +2,7 @@ import fs from 'node:fs'; import path from 'node:path'; import { afterEach, expect, test, vi } from 'vitest'; import { mkdtempForTestSync } from '@agent-device/test-kit/tmp-dir'; -import { platformResourceCleanup } from '../../platform-runtime-resource-cleanup.ts'; +import { platformResourceCleanupFixture } from '../__tests__/support/platform-resource-cleanup-fixture.ts'; vi.mock('../session-teardown.ts', async (importOriginal) => { const actual = await importOriginal(); @@ -51,7 +51,7 @@ test('does not clear a claim after shutdown teardown rejects', async () => { sessionStore, stderr: { write: () => {} }, afterSuccessfulTeardown, - platformCleanup: platformResourceCleanup, + platformCleanup: platformResourceCleanupFixture(), }); expect(afterSuccessfulTeardown).not.toHaveBeenCalled(); @@ -69,7 +69,7 @@ test('does not clear a claim after shutdown teardown times out', async () => { sessionStore, stderr: { write: () => {} }, afterSuccessfulTeardown, - platformCleanup: platformResourceCleanup, + platformCleanup: platformResourceCleanupFixture(), }); await vi.advanceTimersByTimeAsync(5_000); await teardown; diff --git a/src/daemon/session-lifecycle/__tests__/application.test.ts b/src/daemon/session-lifecycle/__tests__/application.test.ts index 469c8541d2..7f4836431e 100644 --- a/src/daemon/session-lifecycle/__tests__/application.test.ts +++ b/src/daemon/session-lifecycle/__tests__/application.test.ts @@ -3,7 +3,7 @@ import { beforeEach, expect, test, vi } from 'vitest'; import type { DaemonRequest, DaemonResponse } from '../../daemon-request.ts'; import { makeSessionStore } from '../../__tests__/support/store-factory.ts'; import { sessionOrDeviceSelectorRequiredDetails } from '@agent-device/kernel/errors'; -import { testCreateCommandSurface } from '../../__tests__/command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from '../../__tests__/support/command-surface-fake.ts'; vi.mock('@agent-device/device-selection/device-inventory-context', async (importOriginal) => { const actual = @@ -52,7 +52,7 @@ function request(command: DaemonRequest['command']): DaemonRequest { async function run(command: DaemonRequest['command']): Promise { return await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: request(command), sessionName: 'default', diff --git a/src/daemon/session-lifecycle/internal/__tests__/session-capabilities-install-projection.test.ts b/src/daemon/session-lifecycle/internal/__tests__/session-capabilities-install-projection.test.ts index 6bfaa53944..c1d1440dd8 100644 --- a/src/daemon/session-lifecycle/internal/__tests__/session-capabilities-install-projection.test.ts +++ b/src/daemon/session-lifecycle/internal/__tests__/session-capabilities-install-projection.test.ts @@ -12,7 +12,7 @@ import type { import { createCapabilitiesAdmissionRuntime } from './session-capabilities.fixtures.ts'; import { handleSessionCommands } from '../../../handlers/__tests__/session-command-harness.ts'; import { mkdtempForTestSync } from '@agent-device/test-kit/tmp-dir'; -import { testCreateCommandSurface } from '../../../__tests__/command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from '../../../__tests__/support/command-surface-fake.ts'; test('capabilities projects the install family from exactly one facts inspection', async () => { const { sessionName, sessionStore } = createAndroidCapabilitiesSession('install-family'); @@ -155,7 +155,7 @@ async function dispatchCapabilities(params: { inspectFacts: InspectDeviceRuntimeFacts; }) { return await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', diff --git a/src/daemon/session-lifecycle/internal/__tests__/session-capabilities.test.ts b/src/daemon/session-lifecycle/internal/__tests__/session-capabilities.test.ts index 641cdbe75e..1a923ae3dd 100644 --- a/src/daemon/session-lifecycle/internal/__tests__/session-capabilities.test.ts +++ b/src/daemon/session-lifecycle/internal/__tests__/session-capabilities.test.ts @@ -27,7 +27,7 @@ import type { } from '../../../request-runtime-binding.ts'; import { handleSessionCommands } from '../../../handlers/__tests__/session-command-harness.ts'; import { mkdtempForTestSync } from '@agent-device/test-kit/tmp-dir'; -import { testCreateCommandSurface } from '../../../__tests__/command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from '../../../__tests__/support/command-surface-fake.ts'; /** The system leaves this owner refuses: the retired fallback listed them unconditionally. */ const ANDROID_REFUSED_SYSTEM_COMMANDS = ['clipboard', 'alert', 'settings', 'app-switcher']; @@ -56,7 +56,7 @@ async function projectAndroidCapabilities(sessionName: string) { providerMode: 'local', }); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -140,7 +140,7 @@ test('capabilities excludes logs from an unavailable provider-mode XCTest runtim }); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -185,7 +185,7 @@ test('capabilities excludes network when the runtime fact is unavailable', async }); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -231,7 +231,7 @@ test('capabilities includes apps for the available HarmonyOS runtime fact', asyn async (request) => (request.platform === 'harmonyos' ? [harmonyDevice] : []), async () => await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -311,7 +311,7 @@ test.each(APPS_UNAVAILABLE_CAPABILITY_CASES)( }); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -347,7 +347,7 @@ test('capabilities excludes appstate when its runtime fact is unavailable', asyn }); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -382,7 +382,7 @@ test('capabilities excludes appstate when its readiness fact is unavailable', as }); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -459,7 +459,7 @@ test.each([ async () => [device], async () => await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -497,7 +497,7 @@ test('capabilities accepts a stopped Android AVD placeholder for explicit platfo async (request) => (request.platform === 'android' ? [stoppedAvd] : []), async () => await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', diff --git a/src/daemon/session-lifecycle/internal/__tests__/session-close-cwd-scoped-resources.test.ts b/src/daemon/session-lifecycle/internal/__tests__/session-close-cwd-scoped-resources.test.ts index 2d1a85be4d..5571ba2093 100644 --- a/src/daemon/session-lifecycle/internal/__tests__/session-close-cwd-scoped-resources.test.ts +++ b/src/daemon/session-lifecycle/internal/__tests__/session-close-cwd-scoped-resources.test.ts @@ -16,7 +16,7 @@ import { } from './session-close-shutdown.fixtures.ts'; import { mkdtempForTestSync } from '@agent-device/test-kit/tmp-dir'; import { encodeHostAudioProbeDescriptor } from '@agent-device/capture-kit/audio-probe-descriptor-fixtures'; -import { testCreateCommandSurface } from '../../../__tests__/command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from '../../../__tests__/support/command-surface-fake.ts'; const { handleSessionCommands, @@ -53,7 +53,7 @@ const IOS_SIM: SessionState['device'] = { async function closeAtAddress(sessionStore: ReturnType) { return await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', session: ADDRESS, command: 'close', positionals: [], flags: {} }, sessionName: ADDRESS, diff --git a/src/daemon/session-lifecycle/internal/__tests__/session-close-error-precedence.test.ts b/src/daemon/session-lifecycle/internal/__tests__/session-close-error-precedence.test.ts index 34a798add2..d42b087ca0 100644 --- a/src/daemon/session-lifecycle/internal/__tests__/session-close-error-precedence.test.ts +++ b/src/daemon/session-lifecycle/internal/__tests__/session-close-error-precedence.test.ts @@ -4,7 +4,7 @@ import { sessionCloseShutdownFixture, type SessionState, } from './session-close-shutdown.fixtures.ts'; -import { testCreateCommandSurface } from '../../../__tests__/command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from '../../../__tests__/support/command-surface-fake.ts'; const { acquireDeviceClaim, @@ -50,7 +50,7 @@ test('targeted close preserves the platform-close AppError and still runs later await expect( handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -130,7 +130,7 @@ test('a failed platform close retains the device claim and reports it', async () let caught: unknown; try { await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -245,7 +245,7 @@ test('a failing best-effort cleanup also retains the device claim and reports it let caught: unknown; try { await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -332,7 +332,7 @@ test('a successful close clears the device claim', async () => { sessionStore.publish(sessionName, session); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -386,7 +386,7 @@ test('targeted close skips platform dispatch and preserves the error when the re await expect( handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', diff --git a/src/daemon/session-lifecycle/internal/__tests__/session-close-lifecycle-runtime.test.ts b/src/daemon/session-lifecycle/internal/__tests__/session-close-lifecycle-runtime.test.ts index efeaa88143..f16b245015 100644 --- a/src/daemon/session-lifecycle/internal/__tests__/session-close-lifecycle-runtime.test.ts +++ b/src/daemon/session-lifecycle/internal/__tests__/session-close-lifecycle-runtime.test.ts @@ -10,7 +10,7 @@ import { readSessionRuntimeRevision, refFrameState, } from '../../../ref-frame.ts'; -import { testCreateCommandSurface } from '../../../__tests__/command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from '../../../__tests__/support/command-surface-fake.ts'; const runtimeHintsModule = vi.hoisted(() => ({ evaluated: false, @@ -65,7 +65,7 @@ async function close(params: { internal?: DaemonRequest['internal']; }) { return await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: closeRequest(params.sessionName, params.positionals ?? [], params.internal), sessionName: params.sessionName, diff --git a/src/daemon/session-lifecycle/internal/__tests__/session-close-resource-cleanup.test.ts b/src/daemon/session-lifecycle/internal/__tests__/session-close-resource-cleanup.test.ts index d8ce18ef35..873f09817c 100644 --- a/src/daemon/session-lifecycle/internal/__tests__/session-close-resource-cleanup.test.ts +++ b/src/daemon/session-lifecycle/internal/__tests__/session-close-resource-cleanup.test.ts @@ -9,7 +9,8 @@ import { } from './session-close-shutdown.fixtures.ts'; import { mkdtempForTestSync } from '@agent-device/test-kit/tmp-dir'; import { encodeHostAudioProbeDescriptor } from '@agent-device/capture-kit/audio-probe-descriptor-fixtures'; -import { testCreateCommandSurface } from '../../../__tests__/command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from '../../../__tests__/support/command-surface-fake.ts'; +import { platformResourceCleanupFixture } from '../../../__tests__/support/platform-resource-cleanup-fixture.ts'; const { AppError, @@ -19,7 +20,6 @@ const { makeSession, makeSessionStore, mockDispatchCommand, - mockStopAndroidSnapshotHelperSessionForDevice, noopInvoke, path, resetSessionCloseShutdownMocks, @@ -42,10 +42,12 @@ test('close stops Android snapshot helper session before deleting session', asyn ...makeSession(sessionName, device), appBundleId: 'com.example.app', }); + const platformCleanup = platformResourceCleanupFixture(); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), + platformResourceCleanup: platformCleanup, req: { token: 't', session: sessionName, @@ -60,7 +62,7 @@ test('close stops Android snapshot helper session before deleting session', asyn }); expect(response?.ok).toBe(true); - expect(mockStopAndroidSnapshotHelperSessionForDevice).toHaveBeenCalledWith(device); + expect(platformCleanup.stopSnapshotHelper).toHaveBeenCalledWith(device); expect(sessionStore.get(sessionName)).toBeUndefined(); }); @@ -141,7 +143,7 @@ test('close stops active host audio probe before deleting session', async () => ); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -167,7 +169,7 @@ test('close dispatches web session cleanup without a positional target', async ( sessionStore.publish(sessionName, makeSession(sessionName, WEB_DESKTOP_DEVICE)); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -220,7 +222,7 @@ test('close preserves the session and lease when provider release fails so it ca let releaseAttempts = 0; const request = { - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, req: { token: 't', session: sessionName, @@ -300,7 +302,7 @@ test('close cannot retire a replacement session while its provider release waits return { releasedBy: 'provider' }; }); const closing = handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', session: address, command: 'close', positionals: [], flags: {} }, sessionName: address, diff --git a/src/daemon/session-lifecycle/internal/__tests__/session-close-save-script.test.ts b/src/daemon/session-lifecycle/internal/__tests__/session-close-save-script.test.ts index d679df56da..c05838d429 100644 --- a/src/daemon/session-lifecycle/internal/__tests__/session-close-save-script.test.ts +++ b/src/daemon/session-lifecycle/internal/__tests__/session-close-save-script.test.ts @@ -2,7 +2,7 @@ import { daemonPlatformServicesFixture } from '../../../__tests__/platform-servi import { beforeEach, expect, test } from 'vitest'; import { sessionCloseShutdownFixture } from './session-close-shutdown.fixtures.ts'; import { mkdtempForTestSync } from '@agent-device/test-kit/tmp-dir'; -import { testCreateCommandSurface } from '../../../__tests__/command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from '../../../__tests__/support/command-surface-fake.ts'; const { fs, @@ -38,7 +38,7 @@ test('close --save-script on a never-armed session is rejected before teardown, await expect( handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -74,7 +74,7 @@ test('close --save-script on a never-armed session is rejected before teardown, // A plain close (no --save-script) still closes the same session cleanly afterward, and now // teardown genuinely does run: the recorder is signaled and the session deleted. const plainClose = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -115,7 +115,7 @@ test('close --save-script on a session with an active .ad repair transaction is sessionStore.publish(sessionName, session); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', diff --git a/src/daemon/session-lifecycle/internal/__tests__/session-close-shutdown-platform.test.ts b/src/daemon/session-lifecycle/internal/__tests__/session-close-shutdown-platform.test.ts index a751656cd1..8479aeb2cb 100644 --- a/src/daemon/session-lifecycle/internal/__tests__/session-close-shutdown-platform.test.ts +++ b/src/daemon/session-lifecycle/internal/__tests__/session-close-shutdown-platform.test.ts @@ -6,7 +6,7 @@ import { type PlatformRuntimeOperations, } from './session-close-shutdown.fixtures.ts'; import { mkdtempForTestSync } from '@agent-device/test-kit/tmp-dir'; -import { testCreateCommandSurface } from '../../../__tests__/command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from '../../../__tests__/support/command-surface-fake.ts'; const { handleSessionCommands, @@ -73,7 +73,7 @@ test('close --shutdown calls shutdownSimulator for iOS simulator and includes re }); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -140,7 +140,7 @@ test('close --shutdown keeps a selected provider-owned iOS simulator off local s }); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -184,7 +184,7 @@ test('close --shutdown calls shutdownAndroidEmulator for Android emulator and in }); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -229,7 +229,7 @@ test('close --shutdown is ignored for non-simulator iOS devices', async () => { ); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -269,7 +269,7 @@ test('close --shutdown is ignored for Android devices', async () => { ); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -317,7 +317,7 @@ test('close --shutdown returns success and failure payload when shutdownAndroidE }); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -359,7 +359,7 @@ test('close --shutdown returns success and failure payload when shutdownSimulato }); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', diff --git a/src/daemon/session-lifecycle/internal/__tests__/session-close-shutdown.fixtures.ts b/src/daemon/session-lifecycle/internal/__tests__/session-close-shutdown.fixtures.ts index 9586f65e11..a30981c43a 100644 --- a/src/daemon/session-lifecycle/internal/__tests__/session-close-shutdown.fixtures.ts +++ b/src/daemon/session-lifecycle/internal/__tests__/session-close-shutdown.fixtures.ts @@ -38,7 +38,6 @@ vi.mock('@agent-device/platform-android/mechanics', async (importOriginal) => { return { ...actual, cleanupAndroidNativePerfSession: vi.fn(async () => {}), - stopAndroidSnapshotHelperSessionForDevice: vi.fn(async () => {}), }; }); vi.mock('@agent-device/capture-kit/recording-video', () => ({ @@ -52,17 +51,14 @@ import { mockShutdownTargetRuntime, } from '../../../handlers/__tests__/session-command-harness.ts'; import { teardownSessionResources as teardownProductionSessionResources } from '../../../session-teardown.ts'; -import { platformResourceCleanup } from '../../../../platform-runtime-resource-cleanup.ts'; +import { platformResourceCleanupFixture } from '../../../__tests__/support/platform-resource-cleanup-fixture.ts'; import { LeaseRegistry } from '../../../lease-registry.ts'; import { runCmd } from '@agent-device/host-kit/command'; import { flushDiagnosticsToSessionFile, withDiagnosticsScope, } from '@agent-device/host-kit/diagnostics'; -import { - cleanupAndroidNativePerfSession, - stopAndroidSnapshotHelperSessionForDevice, -} from '@agent-device/platform-android/mechanics'; +import { cleanupAndroidNativePerfSession } from '@agent-device/platform-android/mechanics'; import { releaseIosRunnerOnClose, stopIosRunnerSession, @@ -92,9 +88,6 @@ const mockRunCmd = vi.mocked(runCmd); const mockDispatchCommand = vi.mocked(dispatchApplicationLifecycleEffect); const mockCleanupAppleXctracePerfCapture = vi.mocked(cleanupAppleXctracePerfCapture); const mockCleanupAndroidNativePerfSession = vi.mocked(cleanupAndroidNativePerfSession); -const mockStopAndroidSnapshotHelperSessionForDevice = vi.mocked( - stopAndroidSnapshotHelperSessionForDevice, -); const mockStopIosRunnerSession = vi.mocked(stopIosRunnerSession); const mockReleaseRunnerOnClose = vi.mocked(releaseIosRunnerOnClose); @@ -103,7 +96,7 @@ const teardownSessionResources = ( ) => teardownProductionSessionResources({ ...request, - platformCleanup: request.platformCleanup ?? platformResourceCleanup, + platformCleanup: request.platformCleanup ?? platformResourceCleanupFixture(), }); const noopInvoke = async (_req: DaemonRequest): Promise => ({ @@ -263,7 +256,6 @@ export const sessionCloseShutdownFixture = Object.freeze({ mockInspectDeviceRuntimeFacts, mockShutdownTargetRuntime, mockRunCmd, - mockStopAndroidSnapshotHelperSessionForDevice, mockReleaseRunnerOnClose, mockStopIosRunnerSession, narrowDeviceBinding, diff --git a/src/daemon/session-lifecycle/internal/__tests__/session-devices-batch-runtime.test.ts b/src/daemon/session-lifecycle/internal/__tests__/session-devices-batch-runtime.test.ts index 3dfe4eb9bd..56592b2925 100644 --- a/src/daemon/session-lifecycle/internal/__tests__/session-devices-batch-runtime.test.ts +++ b/src/daemon/session-lifecycle/internal/__tests__/session-devices-batch-runtime.test.ts @@ -2,7 +2,7 @@ import { daemonPlatformServicesFixture } from '../../../__tests__/platform-servi import { test, expect, vi } from 'vitest'; import * as fs from 'node:fs'; import * as path from 'node:path'; -import { testCreateCommandSurface } from '../../../__tests__/command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from '../../../__tests__/support/command-surface-fake.ts'; vi.mock('../../../materialized-path-registry.ts', async (importOriginal) => { const actual = await importOriginal(); @@ -390,7 +390,7 @@ test('close clears retained materialized install paths bound to the session', as mockCleanupRetainedMaterializedPaths.mockImplementation(realCleanup); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', session: sessionName, command: 'close', positionals: [], flags: {} }, sessionName, diff --git a/src/daemon/session-lifecycle/internal/__tests__/session-open-execution-runtime.test.ts b/src/daemon/session-lifecycle/internal/__tests__/session-open-execution-runtime.test.ts index 12ee6c9410..2e2641a5bc 100644 --- a/src/daemon/session-lifecycle/internal/__tests__/session-open-execution-runtime.test.ts +++ b/src/daemon/session-lifecycle/internal/__tests__/session-open-execution-runtime.test.ts @@ -15,7 +15,7 @@ import { clearRequestAbortRegistration, } from '@agent-device/host-kit/request'; import { AppError } from '@agent-device/kernel/errors'; -import { testCreateCommandSurface } from '../../../__tests__/command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from '../../../__tests__/support/command-surface-fake.ts'; const { mockResolveTargetDevice, mockPrewarmRunnerSession } = vi.hoisted(() => ({ mockResolveTargetDevice: vi.fn(), @@ -140,7 +140,7 @@ test('open runtime payload replaces stored session runtime atomically', async () }); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -221,7 +221,7 @@ test('open runtime payload clears stale applied transport hints before launch', }); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -274,7 +274,7 @@ test('open runtime payload rejects invalid metro port before app launch', async }); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -316,7 +316,7 @@ test('open runtime payload rejects malformed runtime objects without mutating se mockResolveTargetDevice.mockResolvedValue(makeAndroidEmulator()); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -361,7 +361,7 @@ test('open runtime payload does not persist replacement when launch fails', asyn await expect( handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -404,7 +404,7 @@ test('a first open keeps both positionals so the deep link still reaches the app }); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -450,7 +450,7 @@ test('open reports the launch confirmation its platform answered', async () => { }); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -493,7 +493,7 @@ async function openReportingObservation( }); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -570,7 +570,7 @@ function invokeHeldOpen( req?: Partial, ) { return handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', diff --git a/src/daemon/session-lifecycle/internal/__tests__/session-open-existing.test.ts b/src/daemon/session-lifecycle/internal/__tests__/session-open-existing.test.ts index c2f4fb7e4a..3f63694342 100644 --- a/src/daemon/session-lifecycle/internal/__tests__/session-open-existing.test.ts +++ b/src/daemon/session-lifecycle/internal/__tests__/session-open-existing.test.ts @@ -17,7 +17,7 @@ import { import type { SessionState } from '../../../session-state.ts'; import { handleSessionCommands } from '../../../handlers/__tests__/session-command-harness.ts'; import { mkdtempForTestSync } from '@agent-device/test-kit/tmp-dir'; -import { testCreateCommandSurface } from '../../../__tests__/command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from '../../../__tests__/support/command-surface-fake.ts'; test('open web URL on iOS device session without active app falls back to Safari', async () => { const sessionStore = makeSessionStore(); @@ -40,7 +40,7 @@ test('open web URL on iOS device session without active app falls back to Safari }); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -92,7 +92,7 @@ test('open web URL on iOS simulator session without active app falls back to Saf }); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -139,7 +139,7 @@ test('open app and URL on existing iOS device session keeps app context', async }); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -188,7 +188,7 @@ test('open app on existing macOS session resolves and stores bundle id', async ( }); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -222,7 +222,7 @@ test('open rejects --surface on non-macOS devices', async () => { }); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -275,7 +275,7 @@ test('open on existing macOS frontmost-app session preserves surface without --s try { const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -345,7 +345,7 @@ test('open on existing iOS session refreshes unavailable simulator by name', asy const response = await withMockedPlatform('darwin', async () => handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -396,7 +396,7 @@ test('open app on existing Android session resolves and stores package id', asyn mockResolveAndroidPackage.mockResolvedValue('org.reactjs.native.example.RNCLI83'); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -442,7 +442,7 @@ test('open intent target on existing Android session clears stale package contex mockResolveAndroidPackage.mockResolvedValue(undefined); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -497,7 +497,7 @@ test('open on existing Android session preserves a comparable freshness baseline mockResolveAndroidPackage.mockResolvedValue('com.android.settings'); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', diff --git a/src/daemon/session-lifecycle/internal/__tests__/session-open-foreground.test.ts b/src/daemon/session-lifecycle/internal/__tests__/session-open-foreground.test.ts index e0421d1beb..135a2015e7 100644 --- a/src/daemon/session-lifecycle/internal/__tests__/session-open-foreground.test.ts +++ b/src/daemon/session-lifecycle/internal/__tests__/session-open-foreground.test.ts @@ -1,6 +1,6 @@ import { daemonPlatformServicesFixture } from '../../../__tests__/platform-services-fixture.ts'; import { beforeEach, expect, test, vi } from 'vitest'; -import { testCreateCommandSurface } from '../../../__tests__/command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from '../../../__tests__/support/command-surface-fake.ts'; const dispatchSnapshotViaRuntime = vi.hoisted(() => vi.fn()); @@ -152,7 +152,7 @@ const failedOpenResponse: DaemonResponse = { test('passes a failed open response through untouched', async () => { const result = await composeOpenWithInitialSnapshot({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: baseRequest({ flags: { foreground: true } }), ref, @@ -169,7 +169,7 @@ test('passes a failed open response through untouched', async () => { test('leaves a successful open response untouched when --foreground was not requested', async () => { const result = await composeOpenWithInitialSnapshot({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: baseRequest(), ref, @@ -189,7 +189,7 @@ test('attaches the initial INTERACTIVE snapshot by delegating to the existing sn const req = baseRequest({ flags: { foreground: true }, positionals: ['xyz.blueskyweb.app'] }); const result = await composeOpenWithInitialSnapshot({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req, ref, @@ -203,7 +203,7 @@ test('attaches the initial INTERACTIVE snapshot by delegating to the existing sn // #1670 P1: the composed dispatch must BE the `snapshot -i` path — the CLI // maps `-i` to snapshotInteractiveOnly, the key the snapshot runtime reads. expect(dispatchSnapshotViaRuntime).toHaveBeenCalledWith({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, req: { ...req, command: 'snapshot', @@ -243,7 +243,7 @@ test('a snapshot-capture failure never masks the successful open', async () => { dispatchSnapshotViaRuntime.mockResolvedValue(snapshotFailure); const result = await composeOpenWithInitialSnapshot({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: baseRequest({ flags: { foreground: true } }), ref, @@ -287,7 +287,7 @@ test('a THROWN snapshot-capture failure never masks the successful open either', ); const result = await composeOpenWithInitialSnapshot({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: baseRequest({ flags: { foreground: true } }), ref, diff --git a/src/daemon/session-lifecycle/internal/__tests__/session-open-runtime.test.ts b/src/daemon/session-lifecycle/internal/__tests__/session-open-runtime.test.ts index fd8e52b5f6..5f721a8f76 100644 --- a/src/daemon/session-lifecycle/internal/__tests__/session-open-runtime.test.ts +++ b/src/daemon/session-lifecycle/internal/__tests__/session-open-runtime.test.ts @@ -2,7 +2,7 @@ import { daemonPlatformServicesFixture } from '../../../__tests__/platform-servi import { test, expect, vi, beforeEach } from 'vitest'; import path from 'node:path'; -import { testCreateCommandSurface } from '../../../__tests__/command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from '../../../__tests__/support/command-surface-fake.ts'; const mockResolveTargetDevice = vi.hoisted(() => vi.fn()); @@ -125,7 +125,7 @@ test('open applies stored runtime launchUrl and reports runtime hints', async () }); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -190,7 +190,7 @@ test('open rejects a false runtime-hints fact before its one implementation bind }); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -243,7 +243,7 @@ test('open applies launch-only flags only to the direct app launch before runtim }); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -287,7 +287,7 @@ test('open --metro-port alone defaults the host to 10.0.2.2 on an Android emulat }); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -320,7 +320,7 @@ test('open --metro-port alone defaults the host to 127.0.0.1 on an iOS simulator }); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -353,7 +353,7 @@ test('open --metro-port alone stays host-ambiguous on a physical Android device' }); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -386,7 +386,7 @@ test('open --relaunch allows Android package names ending with apk-like suffix', }); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', diff --git a/src/daemon/session-lifecycle/internal/__tests__/session-open-url-prewarm.test.ts b/src/daemon/session-lifecycle/internal/__tests__/session-open-url-prewarm.test.ts index 239979f969..893efe1b5a 100644 --- a/src/daemon/session-lifecycle/internal/__tests__/session-open-url-prewarm.test.ts +++ b/src/daemon/session-lifecycle/internal/__tests__/session-open-url-prewarm.test.ts @@ -1,7 +1,7 @@ import { test, expect, vi, beforeEach } from 'vitest'; import * as path from 'node:path'; import { AppError } from '@agent-device/kernel/errors'; -import { testCreateCommandSurface } from '../../../__tests__/command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from '../../../__tests__/support/command-surface-fake.ts'; vi.mock('node:timers/promises', async (importOriginal) => { const actual = await importOriginal(); @@ -103,7 +103,7 @@ function createHandler( deviceRuntimeGateway = lifecycleDeviceRuntimeGateway, ) { return createRequestHandler({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, logPath: path.join(mkdtempForTestSync('daemon'), 'daemon.log'), token: 'test-token', sessionStore, diff --git a/src/daemon/session-lifecycle/internal/__tests__/session-teardown-resources.test.ts b/src/daemon/session-lifecycle/internal/__tests__/session-teardown-resources.test.ts index 8bde83cf86..10a5ce772a 100644 --- a/src/daemon/session-lifecycle/internal/__tests__/session-teardown-resources.test.ts +++ b/src/daemon/session-lifecycle/internal/__tests__/session-teardown-resources.test.ts @@ -4,9 +4,9 @@ import { sessionCloseShutdownFixture, type SessionState, } from './session-close-shutdown.fixtures.ts'; -import { installFakeManagedAgentBrowser } from '@agent-device/test-kit/web-managed-agent-browser'; import { mkdtempForTestSync } from '@agent-device/test-kit/tmp-dir'; -import { testCreateCommandSurface } from '../../../__tests__/command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from '../../../__tests__/support/command-surface-fake.ts'; +import { platformResourceCleanupFixture } from '../../../__tests__/support/platform-resource-cleanup-fixture.ts'; const { AppError, @@ -14,9 +14,7 @@ const { makeIosSimulatorRecordingSession, makeSession, makeSessionStore, - mockRunCmd, mockReleaseRunnerOnClose, - mockStopAndroidSnapshotHelperSessionForDevice, mockStopIosRunnerSession, mockStopIosRunnerSession: stopIosRunnerSession, noopInvoke, @@ -31,10 +29,6 @@ const { beforeEach(resetSessionCloseShutdownMocks); -function agentBrowserJsonResult(value: unknown, exitCode = 0) { - return { stdout: JSON.stringify(value), stderr: '', exitCode }; -} - test('close finalizes an active iOS simulator recording before deleting the session', async () => { const sessionStore = makeSessionStore(); const sessionName = 'ios-active-recording-close-session'; @@ -43,7 +37,7 @@ test('close finalizes an active iOS simulator recording before deleting the sess sessionStore.publish(sessionName, session); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -83,7 +77,7 @@ test('close surfaces a recording finalization failure through the cleanup-failur await expect( handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -209,9 +203,15 @@ test('daemon session teardown stops Android snapshot helper session', async () = const sessionStore = makeSessionStore(); const ref = sessionStore.publish(sessionName, session); - await teardownSessionResources({ appLog: 'already-settled', ref, sessionStore }); + const platformCleanup = platformResourceCleanupFixture(); + await teardownSessionResources({ + appLog: 'already-settled', + ref, + sessionStore, + platformCleanup, + }); - expect(mockStopAndroidSnapshotHelperSessionForDevice).toHaveBeenCalledWith(session.device); + expect(platformCleanup.stopSnapshotHelper).toHaveBeenCalledWith(session.device); }); test('daemon session teardown attempts every resource after an earlier cleanup rejects', async () => { @@ -236,12 +236,14 @@ test('daemon session teardown attempts every resource after an earlier cleanup r // Perf cleanup runs before the snapshot-helper cleanup. const sessionStore = makeSessionStore(); sessionStore.publish(sessionName, session); + const platformCleanup = platformResourceCleanupFixture(); await expect( teardownSessionResources({ appLog: 'already-settled', ref: sessionStore.lookup(sessionName)!, sessionStore, + platformCleanup, }), ).rejects.toMatchObject({ code: 'COMMAND_FAILED', @@ -252,7 +254,7 @@ test('daemon session teardown attempts every resource after an earlier cleanup r }); // The later resource still runs despite the earlier rejection. - expect(mockStopAndroidSnapshotHelperSessionForDevice).toHaveBeenCalledWith(session.device); + expect(platformCleanup.stopSnapshotHelper).toHaveBeenCalledWith(session.device); }); function attachPerfCapture( @@ -280,45 +282,50 @@ function attachPerfCapture( test('daemon session teardown closes an open web session immediately, not on agent-browser idle timeout', async () => { const sessionName = 'web-active-session-teardown-session'; const sessionStore = makeSessionStore(); - await installFakeManagedAgentBrowser(sessionStore.resolveDaemonStateDir()); const session = makeSession(sessionName, WEB_DESKTOP_DEVICE); // Teardown always runs while the session it is tearing down is still in the store (session // deletion happens after), which is what keeps the provider-startup orphan sweep from treating // this session's own browser as an orphan and scanning real host processes for it. sessionStore.publish(sessionName, session); - mockRunCmd.mockResolvedValue(agentBrowserJsonResult({ success: true, data: {} })); + const platformCleanup = platformResourceCleanupFixture(); await teardownSessionResources({ appLog: 'already-settled', ref: sessionStore.lookup(sessionName)!, sessionStore, + platformCleanup, }); - // A SIGTERM daemon shutdown (or an expired-session reap) tells agent-browser to close its - // fleet right away, the same way an explicit `session close` does, instead of leaving the - // Chrome processes to agent-browser's own multi-minute idle timer. - expect(mockRunCmd).toHaveBeenCalledTimes(1); - const [cmd, args] = mockRunCmd.mock.calls[0] as [string, string[]]; - // `node close ...`: the managed backend never runs through its `.bin` shim (#2022). - expect(cmd).toBe(process.execPath); - expect(args.slice(1)).toEqual(['close', '--json', '--session', sessionName]); + // A SIGTERM daemon shutdown (or an expired-session reap) asks the platform to close the + // session's browser right away, the same way an explicit `session close` does, instead of + // leaving the Chrome processes to agent-browser's own multi-minute idle timer. That the close + // reaches the agent-browser process is real mechanics, pinned root-owned in + // daemon-composition/server/daemon-runtime-web-close-teardown. + expect(platformCleanup.closeManagedBrowser).toHaveBeenCalledWith({ + device: WEB_DESKTOP_DEVICE, + sessionName, + stateDir: sessionStore.resolveDaemonStateDir(), + openSessionNames: expect.any(Function), + }); }); test('daemon session teardown surfaces a web close failure through the cleanup-failure channel', async () => { const sessionName = 'web-close-failure-teardown-session'; const sessionStore = makeSessionStore(); - await installFakeManagedAgentBrowser(sessionStore.resolveDaemonStateDir()); const session = makeSession(sessionName, WEB_DESKTOP_DEVICE); sessionStore.publish(sessionName, session); - mockRunCmd.mockResolvedValue( - agentBrowserJsonResult({ success: false, error: 'no active browser session' }), - ); + const platformCleanup = platformResourceCleanupFixture({ + closeManagedBrowser: async () => { + throw new AppError('COMMAND_FAILED', 'no active browser session'); + }, + }); await expect( teardownSessionResources({ appLog: 'already-settled', ref: sessionStore.lookup(sessionName)!, sessionStore, + platformCleanup, }), ).rejects.toMatchObject({ code: 'COMMAND_FAILED', @@ -328,24 +335,3 @@ test('daemon session teardown surfaces a web close failure through the cleanup-f }), }); }); - -test('daemon session teardown never dispatches a web close for a non-web session', async () => { - const sessionName = 'android-non-web-teardown-session'; - const session = makeSession(sessionName, { - platform: 'android', - id: 'emulator-5554', - name: 'Pixel', - kind: 'emulator', - booted: true, - }); - - const sessionStore = makeSessionStore(); - const ref = sessionStore.publish(sessionName, session); - await teardownSessionResources({ - appLog: 'already-settled', - ref, - sessionStore, - }); - - expect(mockRunCmd).not.toHaveBeenCalled(); -}); diff --git a/src/daemon/session-observability/__tests__/application.test.ts b/src/daemon/session-observability/__tests__/application.test.ts index 8a03a567e3..3107767a34 100644 --- a/src/daemon/session-observability/__tests__/application.test.ts +++ b/src/daemon/session-observability/__tests__/application.test.ts @@ -2,7 +2,7 @@ import { daemonPlatformServicesFixture } from '../../__tests__/platform-services import { beforeEach, expect, test, vi } from 'vitest'; import type { DaemonRequest, DaemonResponse } from '../../daemon-request.ts'; import { makeSessionStore } from '../../__tests__/support/store-factory.ts'; -import { testCreateCommandSurface } from '../../__tests__/command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from '../../__tests__/support/command-surface-fake.ts'; vi.mock('../index.ts', async (importOriginal) => { const actual = await importOriginal(); @@ -33,7 +33,7 @@ function request(command: DaemonRequest['command']): DaemonRequest { async function run(command: DaemonRequest['command']): Promise { return await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: request(command), sessionName: 'default', diff --git a/src/daemon/session-observability/internal/__tests__/session-logs.test.ts b/src/daemon/session-observability/internal/__tests__/session-logs.test.ts index 6d3fdc8298..034f16919c 100644 --- a/src/daemon/session-observability/internal/__tests__/session-logs.test.ts +++ b/src/daemon/session-observability/internal/__tests__/session-logs.test.ts @@ -29,7 +29,7 @@ import { makeTestAppLogResource, noopInvoke, } from '../../../handlers/__tests__/session-test-harness.ts'; -import { testCreateCommandSurface } from '../../../__tests__/command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from '../../../__tests__/support/command-surface-fake.ts'; const DEVICE: DeviceInfo = { platform: 'apple', @@ -298,7 +298,7 @@ async function runLogs( throwIfCanceled?: () => void, ) { return await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', session: sessionName, command: 'logs', positionals, flags }, sessionName, diff --git a/src/daemon/session-observability/internal/__tests__/session-network-runtime-parity.test.ts b/src/daemon/session-observability/internal/__tests__/session-network-runtime-parity.test.ts index ed73795f27..7bf36d1551 100644 --- a/src/daemon/session-observability/internal/__tests__/session-network-runtime-parity.test.ts +++ b/src/daemon/session-observability/internal/__tests__/session-network-runtime-parity.test.ts @@ -12,7 +12,7 @@ import { } from '../../../handlers/__tests__/session-test-harness.ts'; import { NETWORK_RUNTIME_PROJECTION_PARITY } from './session-network-runtime-parity-fixtures.ts'; import { createNetworkRuntime, emptyAppLogResult } from './network-runtime-harness.ts'; -import { testCreateCommandSurface } from '../../../__tests__/command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from '../../../__tests__/support/command-surface-fake.ts'; test.each(NETWORK_RUNTIME_PROJECTION_PARITY)( 'network $action preserves the $include projection through the request runtime', @@ -61,7 +61,7 @@ test.each(NETWORK_RUNTIME_PROJECTION_PARITY)( const runtime = createNetworkRuntime(session.device, async () => result); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -116,7 +116,7 @@ test('network admission remains fail-closed before parsing invalid input', async }); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -215,7 +215,7 @@ async function runNetwork( bindDevice: BindDeviceRuntime, ) { return await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', diff --git a/src/daemon/session-observability/internal/__tests__/session-network.test.ts b/src/daemon/session-observability/internal/__tests__/session-network.test.ts index 78d1407223..e9e0473236 100644 --- a/src/daemon/session-observability/internal/__tests__/session-network.test.ts +++ b/src/daemon/session-observability/internal/__tests__/session-network.test.ts @@ -8,13 +8,13 @@ import { makeSessionStore, noopInvoke, } from '../../../handlers/__tests__/session-test-harness.ts'; -import { testCreateCommandSurface } from '../../../__tests__/command-surface-fixture.ts'; +import { fakeCreateCommandSurface } from '../../../__tests__/support/command-surface-fake.ts'; test('network requires an active session before requesting a runtime binding', async () => { const sessionStore = makeSessionStore(); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', @@ -49,7 +49,7 @@ test('network validates the legacy limit after runtime-fact admission', async () ); const response = await handleSessionCommands({ - createCommandSurface: testCreateCommandSurface, + createCommandSurface: fakeCreateCommandSurface, platformServices: daemonPlatformServicesFixture(), req: { token: 't', diff --git a/test/integration/provider-scenarios/harness.ts b/test/integration/provider-scenarios/harness.ts index c4b5c7d705..c3a46626d1 100644 --- a/test/integration/provider-scenarios/harness.ts +++ b/test/integration/provider-scenarios/harness.ts @@ -52,7 +52,7 @@ import { getInteractor } from '../../../src/core/interactors.ts'; import { unavailableDeviceRuntimeGateway } from '../../../src/daemon/__tests__/test-device-runtime-gateway.ts'; import { openWebSessionNames } from '../../../src/daemon/web-session-names.ts'; -import { testCreateCommandSurface } from '../../../src/daemon/__tests__/command-surface-fixture.ts'; +import { testCreateCommandSurface } from '../../../src/__tests__/daemon-composition/command-surface-fixture.ts'; // Match daemon composition (src/daemon-composition.ts): the daemon decides on provider // ownership through its own admission seam, which root composition installs.