Skip to content

Commit 698d0c1

Browse files
test(daemon): cover the shipped perf sampler dispatch path via the facet
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
1 parent f06f66e commit 698d0c1

1 file changed

Lines changed: 57 additions & 0 deletions

File tree

src/daemon/__tests__/perf-plugin-routing-parity.test.ts

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import assert from 'node:assert/strict';
22
import { test } from 'vitest';
3+
import { AppError } from '../../kernel/errors.ts';
34
import {
45
isIosFamily,
56
isMacOs,
@@ -9,6 +10,7 @@ import {
910
type DeviceKind,
1011
type DeviceTarget,
1112
} from '../../kernel/device.ts';
13+
import type { AndroidAdbExecutor } from '../../platforms/android/adb-executor.ts';
1214
import {
1315
ANDROID_EMULATOR,
1416
ANDROID_TV_DEVICE,
@@ -161,3 +163,58 @@ test('buildPerfResponseData routes the support gate through the perf facet', asy
161163
);
162164
}
163165
});
166+
167+
// Shipped-path routing proof for the sampling body (issue #1188). The support-gate test
168+
// above never reaches sampler selection — it uses no `appBundleId`, so execution returns
169+
// through `applyMissingAppPerfMetrics` before `resolvePerfMetricsSampler`. WITH an app
170+
// bundle, execution clears that guard and hits the facet-owned sampler selection. The
171+
// Android sampler is the ONLY arm that threads `options.androidAdb`, so a scripted adb
172+
// executor is invoked exactly when the Android sampler was selected AND run through the
173+
// shipped code path. Breaking the facet lookup (Android returning a non-`android` tag, or
174+
// the resolver yielding no sampler) skips the Android sampler and fails this test — so the
175+
// suite now covers the dispatch line itself, not only registry parity.
176+
const SAMPLED_ADB_REASON = 'scripted adb unavailable';
177+
function makeThrowingAdb(): { adb: AndroidAdbExecutor; calls: () => number } {
178+
let calls = 0;
179+
const adb: AndroidAdbExecutor = async () => {
180+
calls += 1;
181+
throw new AppError('COMMAND_FAILED', SAMPLED_ADB_REASON);
182+
};
183+
return { adb, calls: () => calls };
184+
}
185+
186+
test('buildPerfResponseData dispatches the Android sampler selected by the facet', async () => {
187+
for (const device of SAMPLE_DEVICES.filter((d) => d.platform === 'android')) {
188+
const { adb, calls } = makeThrowingAdb();
189+
const session = makeSession(`perf-routed-${device.id}`, {
190+
device,
191+
appBundleId: 'com.example.app',
192+
});
193+
const data = await buildPerfResponseData(session, { androidAdb: adb });
194+
195+
assert.ok(calls() > 0, `Android sampler reached through the shipped path for ${device.id}`);
196+
for (const metric of ['memory', 'cpu', 'fps'] as const) {
197+
const entry = data.metrics[metric] as { available?: boolean; reason?: string };
198+
assert.equal(
199+
entry.available,
200+
false,
201+
`${metric} was sampled (not the base response) for ${device.id}`,
202+
);
203+
assert.equal(
204+
entry.reason,
205+
SAMPLED_ADB_REASON,
206+
`${metric} carries the sampler failure for ${device.id}`,
207+
);
208+
}
209+
}
210+
});
211+
212+
// The missing-app guard precedes sampler selection, so without an `appBundleId` the facet
213+
// sampler is never consulted and the scripted adb stays untouched.
214+
test('buildPerfResponseData consults the sampler only past the missing-app guard', async () => {
215+
const { adb, calls } = makeThrowingAdb();
216+
await buildPerfResponseData(makeSession('perf-no-bundle', { device: ANDROID_EMULATOR }), {
217+
androidAdb: adb,
218+
});
219+
assert.equal(calls(), 0, 'sampler not consulted without an app bundle');
220+
});

0 commit comments

Comments
 (0)