Skip to content

Commit 95198cd

Browse files
committed
test: move managed automation scenarios to integration lane
1 parent 7a33fc3 commit 95198cd

5 files changed

Lines changed: 200 additions & 198 deletions

src/platform-runtime-gateway.fixtures.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ export function gatewayFixture(registrations: readonly PlatformRuntimeProviderRe
8585
});
8686
}
8787

88-
export const MANAGED_RETAINED_OPERATION = 'setSetting';
88+
export const REVIEWED_MANAGED_OPERATION = 'setSetting';
8989

9090
export type LocalFamilyRuntimeFixture = Readonly<{
9191
module: PlatformRuntimeModule;

src/platform-runtime-gateway.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ import {
3232
LIFECYCLE_FACETS,
3333
limrunTestDependencies,
3434
localFamilyRuntimeFixture,
35-
MANAGED_RETAINED_OPERATION,
35+
REVIEWED_MANAGED_OPERATION,
3636
managedGatewayScope,
3737
providerLifecycleOwnerFixture as providerLifecycleOwner,
3838
providerRuntimeFixture as providerRuntime,
@@ -660,7 +660,7 @@ describe('managed local owner registration', () => {
660660
available: false,
661661
reason: 'owner-capability-missing',
662662
});
663-
expect(binding.facts.operations[MANAGED_RETAINED_OPERATION]).toEqual({ available: true });
663+
expect(binding.facts.operations[REVIEWED_MANAGED_OPERATION]).toEqual({ available: true });
664664
});
665665

666666
test('leaves ordinary selection on the local family owner while a managed owner is registered', async () => {

src/platform-runtime-managed-owner.test.ts

Lines changed: 6 additions & 185 deletions
Original file line numberDiff line numberDiff line change
@@ -16,180 +16,23 @@ import {
1616
type PlatformRuntimeHost,
1717
} from '@agent-device/contracts/platform-runtime-operations';
1818
import { deployAppUse } from '@agent-device/contracts/app-deployment-runtime-plan';
19-
import { describe, expect, test, vi } from 'vitest';
20-
import fs from 'node:fs';
21-
import path from 'node:path';
22-
import { runCmd } from '@agent-device/host-kit/command';
23-
import { sleep } from '@agent-device/host-kit/retry';
24-
import { withAppleToolProvider } from '@agent-device/platform-apple/tool-provider';
25-
import { createRecordingAppleToolProvider } from '../test/integration/provider-scenarios/providers.ts';
26-
import { createDemoIosApp } from '../test/integration/provider-scenarios/fixtures.ts';
27-
import {
28-
AUTOMATION_APP_ID,
29-
AUTOMATION_PNG,
30-
managedAutomationBinding,
31-
managedAutomationApk,
32-
withManagedAdbFixture,
33-
} from './platform-runtime-managed-owner.fixtures.ts';
19+
import { describe, expect, test } from 'vitest';
3420
import { createManagedLocalRuntimeOwner } from './platform-runtime-managed-owner.ts';
3521
import {
3622
gatewayFixtureDevice as device,
3723
gatewayFixtureScope as ordinaryScope,
3824
managedGatewayScope,
3925
localFamilyRuntimeFixture,
40-
MANAGED_RETAINED_OPERATION,
26+
REVIEWED_MANAGED_OPERATION,
4127
} from './platform-runtime-gateway.fixtures.ts';
4228

43-
vi.mock('@agent-device/host-kit/retry', async (importOriginal) => ({
44-
...(await importOriginal<typeof import('@agent-device/host-kit/retry')>()),
45-
sleep: vi.fn(async () => {}),
46-
}));
47-
4829
const managed = managedLocalRuntimeOwner('sim-a');
4930
const fence = managedBindingFence({
5031
requesterId: 'requester-a',
5132
requestGeneration: 1,
5233
identityIncarnationId: 'incarnation-a',
5334
});
5435

55-
test('managed iOS delegates deployment and system operations without local readiness or runner startup', async () => {
56-
const app = createDemoIosApp('managed-ios-automation-');
57-
let biometricAttempts = 0;
58-
const native = createRecordingAppleToolProvider({
59-
plist: {
60-
readJson: async () => ({ CFBundleIdentifier: AUTOMATION_APP_ID, CFBundleName: 'Demo' }),
61-
},
62-
simctl: async (args) => {
63-
expect(args.slice(0, 2)).toEqual(['--set', '/managed/set']);
64-
const command = args[2];
65-
if (command === 'list')
66-
return {
67-
stdout: JSON.stringify({
68-
devices: { ios: [{ udid: 'managed-ios', state: 'Shutdown' }] },
69-
}),
70-
stderr: '',
71-
exitCode: 0,
72-
};
73-
expect(['install', 'uninstall', 'pbpaste', 'pbcopy', 'ui', 'biometric', 'push']).toContain(
74-
command,
75-
);
76-
if (command === 'biometric' && ++biometricAttempts === 1)
77-
return { stdout: '', stderr: 'unknown command', exitCode: 1 };
78-
return {
79-
stdout: command === 'pbpaste' ? 'managed clipboard\n' : '',
80-
stderr: '',
81-
exitCode: 0,
82-
};
83-
},
84-
});
85-
try {
86-
await withAppleToolProvider(native.provider, async () => {
87-
const { binding, allocator, admission } = await managedAutomationBinding('ios');
88-
expect(allocator.calls.map(({ method }) => method)).toEqual(['requestLease']);
89-
const ops = binding.operations;
90-
await ops.ensureReady!({});
91-
await ops.deployApp!({
92-
app: AUTOMATION_APP_ID,
93-
appPath: app.appPath,
94-
replaceExisting: false,
95-
});
96-
await ops.deployApp!({ app: AUTOMATION_APP_ID, appPath: app.appPath, replaceExisting: true });
97-
const artifact = await ops.materializeAppSource!({
98-
source: { kind: 'path', path: app.appPath },
99-
});
100-
try {
101-
await ops.deployMaterializedApp!({ artifact });
102-
} finally {
103-
await artifact.cleanup();
104-
}
105-
await ops.sendPushNotification!({ appId: AUTOMATION_APP_ID, payload: {} });
106-
expect(await ops.readClipboard!({})).toBe('managed clipboard');
107-
await ops.writeClipboard!({ text: 'managed' });
108-
await ops.setSetting!({ setting: 'appearance', state: 'dark' });
109-
await ops.setSetting!({ setting: 'faceid', state: 'match' });
110-
expect(biometricAttempts).toBe(2);
111-
expect(native.calls.filter((call) => call[3] === 'install')).toHaveLength(3);
112-
expect(
113-
native.calls.some((call) => ['list', 'boot', 'bootstatus', 'shutdown'].includes(call[3]!)),
114-
).toBe(false);
115-
expect(allocator.calls.map(({ method }) => method)).toEqual(['requestLease', 'renewLease']);
116-
const before = native.calls.length;
117-
admission.fenceBinding('replaced');
118-
await expect(ops.readClipboard!({})).rejects.toMatchObject({
119-
details: { reason: 'teardown-required' },
120-
});
121-
await binding[Symbol.asyncDispose]();
122-
expect(native.calls).toHaveLength(before);
123-
});
124-
} finally {
125-
fs.rmSync(app.tempRoot, { recursive: true, force: true });
126-
}
127-
});
128-
129-
test.skipIf(process.platform === 'win32')(
130-
'managed Android contains bind probes, APK deployment, settings, clipboard and screenshot',
131-
async () => {
132-
await withManagedAdbFixture(async (native) => {
133-
const { binding, host, allocator, admission } = await managedAutomationBinding('android');
134-
expect(native.calls()).toHaveLength(1);
135-
expect(allocator.calls.map(({ method }) => method)).toEqual(['requestLease']);
136-
const ops = binding.operations;
137-
const apkPath = await managedAutomationApk(native.root);
138-
await ops.ensureReady!({});
139-
await ops.deployApp!({ app: AUTOMATION_APP_ID, appPath: apkPath, replaceExisting: false });
140-
await ops.deployApp!({ app: AUTOMATION_APP_ID, appPath: apkPath, replaceExisting: true });
141-
const artifact = await ops.materializeAppSource!({ source: { kind: 'path', path: apkPath } });
142-
try {
143-
await ops.deployMaterializedApp!({ artifact });
144-
} finally {
145-
await artifact.cleanup();
146-
}
147-
await ops.sendPushNotification!({ appId: AUTOMATION_APP_ID, payload: {} });
148-
expect(await ops.readClipboard!({})).toBe('managed clipboard');
149-
await ops.writeClipboard!({ text: 'managed' });
150-
await ops.setSetting!({ setting: 'fingerprint', state: 'match' });
151-
await ops.setSetting!({
152-
setting: 'clear-app-state',
153-
state: 'clear',
154-
appBundleId: AUTOMATION_APP_ID,
155-
});
156-
const outPath = path.join(native.root, 'capture.png');
157-
await ops.captureScreenshot!({ outPath, options: { stabilize: false } });
158-
expect(fs.readFileSync(outPath)).toEqual(AUTOMATION_PNG);
159-
const calls = native.calls();
160-
expect(calls.filter((args) => args[4] === 'install')).toHaveLength(3);
161-
expect(calls.some((args) => args.slice(4).join(' ') === 'emu finger touch 1')).toBe(true);
162-
for (const args of calls)
163-
expect(args.slice(0, 4)).toEqual(['-P', '15037', '-s', 'emulator-15037']);
164-
const bundle = path.join(native.root, 'App.aab');
165-
fs.writeFileSync(bundle, 'bundle');
166-
const archive = path.join(native.root, 'bundle.zip');
167-
await runCmd('zip', ['-q', archive, 'App.aab'], { cwd: native.root });
168-
const commands = vi.spyOn(host.commands, 'run');
169-
for (const replaceExisting of [false, true]) {
170-
await expect(
171-
ops.deployApp!({ app: AUTOMATION_APP_ID, appPath: bundle, replaceExisting }),
172-
).rejects.toMatchObject({ details: { reason: 'managed-bundle-install-unavailable' } });
173-
}
174-
await expect(
175-
ops.deployApp!({ app: AUTOMATION_APP_ID, appPath: archive, replaceExisting: true }),
176-
).rejects.toMatchObject({ details: { reason: 'managed-bundle-install-unavailable' } });
177-
await expect(
178-
ops.deployMaterializedApp!({
179-
artifact: { installablePath: bundle, cleanup: async () => {} },
180-
}),
181-
).rejects.toMatchObject({ details: { reason: 'managed-bundle-install-unavailable' } });
182-
expect(commands).not.toHaveBeenCalled();
183-
expect(native.calls()).toEqual(calls);
184-
admission.fenceBinding('released');
185-
await expect(ops.readClipboard!({})).rejects.toMatchObject({
186-
details: { reason: 'teardown-required' },
187-
});
188-
await binding[Symbol.asyncDispose]();
189-
expect(native.calls()).toEqual(calls);
190-
});
191-
},
192-
);
19336
const scope = managedGatewayScope(device, managed, fence);
19437

19538
function exactly(
@@ -217,28 +60,6 @@ function thrownBy(run: () => unknown): unknown {
21760
throw new Error('expected the runtime use to be refused');
21861
}
21962

220-
test.skipIf(process.platform === 'win32')(
221-
'managed screenshot failure keeps demo-mode cleanup on its private transport',
222-
async () => {
223-
await withManagedAdbFixture(async (native) => {
224-
const { binding } = await managedAutomationBinding('android');
225-
vi.mocked(sleep).mockClear();
226-
fs.writeFileSync(path.join(native.root, 'corrupt-screenshot'), '');
227-
await expect(
228-
binding.operations.captureScreenshot!({ outPath: path.join(native.root, 'bad.png') }),
229-
).rejects.toThrow('valid PNG header');
230-
expect(sleep).toHaveBeenCalledOnce();
231-
const calls = native.calls();
232-
expect(calls.at(-1)?.at(-1)).toBe(
233-
'am broadcast -a com.android.systemui.demo -e command exit',
234-
);
235-
for (const args of calls)
236-
expect(args.slice(0, 4)).toEqual(['-P', '15037', '-s', 'emulator-15037']);
237-
await binding[Symbol.asyncDispose]();
238-
});
239-
},
240-
);
241-
24263
describe('managed local runtime owner', () => {
24364
test('dispatches the real operation inside admission before authority can be fenced', async () => {
24465
const events: string[] = [];
@@ -322,8 +143,8 @@ describe('managed local runtime owner', () => {
322143
});
323144
expect(binding.operations[key]).toBeUndefined();
324145
}
325-
expect(binding.facts.operations[MANAGED_RETAINED_OPERATION]).toEqual({ available: true });
326-
expect(binding.operations[MANAGED_RETAINED_OPERATION]).toBeTypeOf('function');
146+
expect(binding.facts.operations[REVIEWED_MANAGED_OPERATION]).toEqual({ available: true });
147+
expect(binding.operations[REVIEWED_MANAGED_OPERATION]).toBeTypeOf('function');
327148
});
328149

329150
// The exclusion covers binding cells; request-runtime binding owns the separate pre-binding
@@ -391,7 +212,7 @@ describe('managed local runtime owner', () => {
391212
expect(binding.owner).toEqual(managed);
392213
});
393214

394-
test('never claims a device and projects the same withholding onto inspected facts', async () => {
215+
test('never claims a device and leaves unbound inspection entirely unavailable', async () => {
395216
const { owner } = managedOwnerFixture();
396217

397218
expect(owner.ownsDevice(device)).toBe(false);
@@ -400,7 +221,7 @@ describe('managed local runtime owner', () => {
400221
available: false,
401222
reason: 'owner-capability-missing',
402223
});
403-
expect(facts.operations[MANAGED_RETAINED_OPERATION].available).toBe(false);
224+
expect(facts.operations[REVIEWED_MANAGED_OPERATION].available).toBe(false);
404225
});
405226

406227
test('reports the family owner provider mode it was given, unlaundered', async () => {

src/platform-runtime-managed-owner.fixtures.ts renamed to test/integration/provider-scenarios/managed-runtime-automation.fixtures.ts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,20 @@ import type {
77
ManagedLease,
88
ManagedLeasePlatform,
99
} from '@agent-device/contracts/managed-device-allocation';
10-
import { createManagedLeaseReachability } from './managed-device-reachability.ts';
11-
import { createManagedLeaseAdmission } from './daemon/managed-device-allocation/lease-admission.ts';
12-
import { createScriptedManagedDeviceAllocator } from './__tests__/test-utils/managed-device-allocator.fixtures.ts';
10+
import { createManagedLeaseReachability } from '../../../src/managed-device-reachability.ts';
11+
import { createManagedLeaseAdmission } from '../../../src/daemon/managed-device-allocation/lease-admission.ts';
12+
import { createScriptedManagedDeviceAllocator } from '../../../src/__tests__/test-utils/managed-device-allocator.fixtures.ts';
1313
import {
1414
ALLOCATION_GRANTED_STATUS,
1515
ALLOCATION_LEASE,
1616
ALLOCATION_REQUEST,
17-
} from './daemon/managed-device-allocation/__tests__/fixtures.ts';
18-
import { managedGatewayScope } from './platform-runtime-gateway.fixtures.ts';
19-
import { createComposedPlatformRuntimeGateway } from './platform-runtime-gateway.ts';
20-
import { platformRuntimeModules } from './platform-runtime.ts';
21-
import { createPlatformRuntimeHost } from './platform-runtime-operation-host.ts';
22-
import { mkdtempForTestSync } from './__tests__/test-utils/tmp-dir.ts';
23-
import './platform-runtime-android-adb-host.ts';
17+
} from '../../../src/daemon/managed-device-allocation/__tests__/fixtures.ts';
18+
import { managedGatewayScope } from '../../../src/platform-runtime-gateway.fixtures.ts';
19+
import { createComposedPlatformRuntimeGateway } from '../../../src/platform-runtime-gateway.ts';
20+
import { platformRuntimeModules } from '../../../src/platform-runtime.ts';
21+
import { createPlatformRuntimeHost } from '../../../src/platform-runtime-operation-host.ts';
22+
import { mkdtempForTestSync } from '../../../src/__tests__/test-utils/tmp-dir.ts';
23+
import '../../../src/platform-runtime-android-adb-host.ts';
2424

2525
export const AUTOMATION_APP_ID = 'com.example.demo';
2626
export const AUTOMATION_PNG = Buffer.from('89504e470d0a1a0a0000000049454e44ae426082', 'hex');

0 commit comments

Comments
 (0)