zeno-mobile-runner 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +497 -0
- package/CONTRIBUTING.md +42 -0
- package/FEATURES.md +111 -0
- package/LICENSE +21 -0
- package/README.md +176 -0
- package/SECURITY.md +34 -0
- package/build.zig +38 -0
- package/build.zig.zon +7 -0
- package/clients/README.md +149 -0
- package/clients/go/README.md +24 -0
- package/clients/go/examples/fake-session/main.go +93 -0
- package/clients/go/go.mod +3 -0
- package/clients/go/zmr/client.go +432 -0
- package/clients/kotlin/README.md +35 -0
- package/clients/kotlin/build.gradle.kts +35 -0
- package/clients/kotlin/settings.gradle.kts +15 -0
- package/clients/kotlin/src/main/kotlin/dev/zmr/FakeSession.kt +86 -0
- package/clients/kotlin/src/main/kotlin/dev/zmr/ZmrClient.kt +67 -0
- package/clients/python/README.md +29 -0
- package/clients/python/examples/fake_session.py +48 -0
- package/clients/python/pyproject.toml +13 -0
- package/clients/python/zmr_client.py +202 -0
- package/clients/rust/Cargo.lock +107 -0
- package/clients/rust/Cargo.toml +10 -0
- package/clients/rust/README.md +19 -0
- package/clients/rust/examples/fake_session.rs +70 -0
- package/clients/rust/src/lib.rs +461 -0
- package/clients/swift/Package.swift +16 -0
- package/clients/swift/README.md +36 -0
- package/clients/swift/Sources/ZMRClient/ZMRClient.swift +114 -0
- package/clients/swift/Sources/ZMRFakeSession/main.swift +86 -0
- package/clients/typescript/README.md +34 -0
- package/clients/typescript/examples/fake-session.mjs +36 -0
- package/clients/typescript/index.d.ts +144 -0
- package/clients/typescript/index.mjs +192 -0
- package/clients/typescript/package.json +8 -0
- package/docs/adr/0001-agent-native-runner-boundary.md +31 -0
- package/docs/adr/0002-app-local-zmr-contract.md +39 -0
- package/docs/adr/0003-ios-simulator-xctest-shim.md +41 -0
- package/docs/adr/0004-benchmark-claims-and-baseline-collection.md +37 -0
- package/docs/adr/README.md +12 -0
- package/docs/ai-agents.md +154 -0
- package/docs/app-integration.md +330 -0
- package/docs/benchmarking.md +273 -0
- package/docs/client-installation.md +133 -0
- package/docs/clients.md +98 -0
- package/docs/config.md +175 -0
- package/docs/demo.md +259 -0
- package/docs/frameworks.md +72 -0
- package/docs/install.md +95 -0
- package/docs/npm.md +356 -0
- package/docs/protocol-fixtures/README.md +8 -0
- package/docs/protocol-fixtures/core-session.requests.jsonl +8 -0
- package/docs/protocol-fixtures/core-session.responses.jsonl +8 -0
- package/docs/protocol-versioning.md +65 -0
- package/docs/protocol.md +560 -0
- package/docs/scenario-authoring.md +88 -0
- package/docs/trace-privacy.md +88 -0
- package/docs/troubleshooting.md +256 -0
- package/examples/android-app-auth-probe.json +89 -0
- package/examples/android-app-error-state.json +13 -0
- package/examples/android-app-login-smoke.json +192 -0
- package/examples/android-app-onboarding.json +12 -0
- package/examples/android-app-referral-deep-link.json +12 -0
- package/examples/android-shim-smoke.json +19 -0
- package/examples/demo-failure.json +12 -0
- package/examples/demo-fake.json +14 -0
- package/examples/ios-dev-client-open-link.json +26 -0
- package/examples/ios-dev-client-route-snapshot.json +24 -0
- package/examples/ios-shim-smoke.json +23 -0
- package/examples/ios-smoke.json +9 -0
- package/go.work +3 -0
- package/npm/agents.mjs +183 -0
- package/npm/app-config.mjs +95 -0
- package/npm/build-zmr.mjs +21 -0
- package/npm/commands.mjs +104 -0
- package/npm/generated-files.mjs +50 -0
- package/npm/index.mjs +75 -0
- package/npm/init-app.mjs +80 -0
- package/npm/package-scripts.mjs +72 -0
- package/npm/postinstall.mjs +21 -0
- package/npm/scaffold.mjs +179 -0
- package/npm/scenarios.mjs +93 -0
- package/npm/setup.mjs +69 -0
- package/npm/wizard.mjs +117 -0
- package/npm/zmr.mjs +23 -0
- package/package.json +118 -0
- package/schemas/README.md +26 -0
- package/schemas/action-result.schema.json +27 -0
- package/schemas/capabilities-output.schema.json +98 -0
- package/schemas/devices-output.schema.json +25 -0
- package/schemas/doctor-output.schema.json +51 -0
- package/schemas/explain-output.schema.json +51 -0
- package/schemas/import-output.schema.json +23 -0
- package/schemas/init-output.schema.json +71 -0
- package/schemas/json-rpc.schema.json +55 -0
- package/schemas/release-manifest.schema.json +43 -0
- package/schemas/release-readiness-output.schema.json +127 -0
- package/schemas/run-output.schema.json +43 -0
- package/schemas/scenario.schema.json +128 -0
- package/schemas/schemas-output.schema.json +26 -0
- package/schemas/semantic-snapshot.schema.json +116 -0
- package/schemas/snapshot.schema.json +60 -0
- package/schemas/trace-event.schema.json +14 -0
- package/schemas/trace-manifest.schema.json +59 -0
- package/schemas/validate-output.schema.json +42 -0
- package/schemas/version-output.schema.json +23 -0
- package/schemas/zmr-config.schema.json +75 -0
- package/scripts/android-emulator.sh +126 -0
- package/scripts/assert-ios-physical-ready.sh +213 -0
- package/scripts/benchmark-command.sh +307 -0
- package/scripts/benchmark.sh +359 -0
- package/scripts/benchmark_gate.py +117 -0
- package/scripts/benchmark_result_row.py +88 -0
- package/scripts/compare-benchmarks.py +288 -0
- package/scripts/create-android-demo-app.sh +342 -0
- package/scripts/create-ios-demo-app.sh +261 -0
- package/scripts/demo-android-real.sh +232 -0
- package/scripts/demo-ios-real.sh +270 -0
- package/scripts/demo.sh +464 -0
- package/scripts/device-matrix.sh +338 -0
- package/scripts/ensure-ios-shim-target.rb +237 -0
- package/scripts/install-android-shim.sh +281 -0
- package/scripts/install-ios-shim.sh +589 -0
- package/scripts/pilot-gate.sh +560 -0
- package/scripts/release-readiness.py +838 -0
- package/scripts/release-readiness.sh +91 -0
- package/scripts/run-android-pilot.sh +561 -0
- package/scripts/run-ios-pilot.sh +509 -0
- package/shims/android/README.md +21 -0
- package/shims/android/ZMRShimInstrumentedTest.java +152 -0
- package/shims/android/protocol.md +18 -0
- package/shims/ios/README.md +50 -0
- package/shims/ios/ZMRShim.swift +110 -0
- package/shims/ios/ZMRShimUITestCase.swift +518 -0
- package/shims/ios/protocol.md +74 -0
- package/skills/zmr-mobile-testing/SKILL.md +127 -0
- package/src/android.zig +344 -0
- package/src/android_device_info.zig +99 -0
- package/src/android_emulator.zig +154 -0
- package/src/android_screen_recording.zig +112 -0
- package/src/android_shell.zig +112 -0
- package/src/bundle.zig +124 -0
- package/src/bundle_redaction.zig +272 -0
- package/src/bundle_tar.zig +123 -0
- package/src/cli_devices.zig +97 -0
- package/src/cli_doctor.zig +114 -0
- package/src/cli_import.zig +70 -0
- package/src/cli_info.zig +39 -0
- package/src/cli_init.zig +72 -0
- package/src/cli_output.zig +467 -0
- package/src/cli_run.zig +259 -0
- package/src/cli_serve.zig +287 -0
- package/src/cli_trace.zig +111 -0
- package/src/cli_validate.zig +41 -0
- package/src/command.zig +211 -0
- package/src/config.zig +305 -0
- package/src/config_diagnostics.zig +212 -0
- package/src/config_paths.zig +49 -0
- package/src/device_registry.zig +37 -0
- package/src/doctor.zig +412 -0
- package/src/doctor_hints.zig +52 -0
- package/src/errors.zig +55 -0
- package/src/fake_device.zig +163 -0
- package/src/health.zig +28 -0
- package/src/importer.zig +343 -0
- package/src/importer_json.zig +100 -0
- package/src/importer_model.zig +103 -0
- package/src/ios.zig +399 -0
- package/src/ios_devices.zig +219 -0
- package/src/ios_lifecycle.zig +72 -0
- package/src/ios_shim.zig +242 -0
- package/src/ios_snapshot.zig +20 -0
- package/src/json_fields.zig +80 -0
- package/src/json_rpc.zig +150 -0
- package/src/json_rpc_methods.zig +318 -0
- package/src/json_rpc_observation.zig +31 -0
- package/src/json_rpc_params.zig +52 -0
- package/src/json_rpc_protocol.zig +110 -0
- package/src/json_rpc_trace.zig +73 -0
- package/src/main.zig +131 -0
- package/src/mcp.zig +234 -0
- package/src/mcp_protocol.zig +64 -0
- package/src/mcp_trace.zig +83 -0
- package/src/report.zig +346 -0
- package/src/report_html.zig +63 -0
- package/src/report_values.zig +27 -0
- package/src/run_options.zig +152 -0
- package/src/runner.zig +280 -0
- package/src/runner_actions.zig +109 -0
- package/src/runner_config.zig +6 -0
- package/src/runner_diagnostics.zig +268 -0
- package/src/runner_events.zig +170 -0
- package/src/runner_native.zig +88 -0
- package/src/runner_waits.zig +300 -0
- package/src/scaffold.zig +472 -0
- package/src/scenario.zig +346 -0
- package/src/scenario_fields.zig +50 -0
- package/src/schema_registry.zig +53 -0
- package/src/selector.zig +84 -0
- package/src/semantic.zig +171 -0
- package/src/trace.zig +315 -0
- package/src/trace_json.zig +340 -0
- package/src/trace_summary.zig +218 -0
- package/src/trace_summary_diagnostic.zig +202 -0
- package/src/types.zig +120 -0
- package/src/uiautomator.zig +164 -0
- package/src/validation.zig +187 -0
- package/src/version.zig +22 -0
- package/viewer/app.js +373 -0
- package/viewer/index.html +126 -0
- package/viewer/parser.js +233 -0
- package/viewer/styles.css +585 -0
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
SOURCE="${BASH_SOURCE[0]}"
|
|
5
|
+
while [[ -h "$SOURCE" ]]; do
|
|
6
|
+
SOURCE_DIR="$(cd -P "$(dirname "$SOURCE")" && pwd)"
|
|
7
|
+
SOURCE="$(readlink "$SOURCE")"
|
|
8
|
+
if [[ "$SOURCE" != /* ]]; then
|
|
9
|
+
SOURCE="$SOURCE_DIR/$SOURCE"
|
|
10
|
+
fi
|
|
11
|
+
done
|
|
12
|
+
|
|
13
|
+
ROOT="$(cd -P "$(dirname "$SOURCE")/.." && pwd)"
|
|
14
|
+
OUT="/tmp/zmr-android-demo-$(date +%Y%m%d-%H%M%S)"
|
|
15
|
+
APP_ID="com.example.mobiletest"
|
|
16
|
+
DEVICE="emulator-5554"
|
|
17
|
+
AVD=""
|
|
18
|
+
RUNS="1"
|
|
19
|
+
TRACE_ROOT=""
|
|
20
|
+
API="35"
|
|
21
|
+
BUILD_TOOLS="35.0.1"
|
|
22
|
+
ANDROID_SDK="${ANDROID_HOME:-$HOME/Library/Android/sdk}"
|
|
23
|
+
ADB="${ADB:-adb}"
|
|
24
|
+
EMULATOR="${EMULATOR:-emulator}"
|
|
25
|
+
AUTO_BOOT_EMULATOR=1
|
|
26
|
+
DRY_RUN=0
|
|
27
|
+
|
|
28
|
+
usage() {
|
|
29
|
+
cat <<'USAGE'
|
|
30
|
+
Usage:
|
|
31
|
+
scripts/demo-android-real.sh [options]
|
|
32
|
+
|
|
33
|
+
Creates a generic public Android demo app, installs it on an Android
|
|
34
|
+
emulator/device, and runs the ZMR Android smoke scenario with trace output.
|
|
35
|
+
|
|
36
|
+
Options:
|
|
37
|
+
--out <dir> Demo app output directory. Default: /tmp/zmr-android-demo-<timestamp>.
|
|
38
|
+
--app-id <id> Android application id. Default: com.example.mobiletest.
|
|
39
|
+
--device <serial> Android device/emulator serial. Default: emulator-5554.
|
|
40
|
+
--avd <name> AVD to boot when the requested device is not ready.
|
|
41
|
+
--runs <n> Scenario run count. Default: 1.
|
|
42
|
+
--trace-root <dir> Trace output directory. Default: <out>/traces/pilot.
|
|
43
|
+
--api <level> Android platform API level. Default: 35.
|
|
44
|
+
--build-tools <ver> Android build-tools version. Default: 35.0.1.
|
|
45
|
+
--android-sdk <path> Android SDK root. Default: ANDROID_HOME or ~/Library/Android/sdk.
|
|
46
|
+
--adb <path> adb path. Default: adb.
|
|
47
|
+
--emulator <path> emulator path. Default: emulator.
|
|
48
|
+
--no-auto-boot-emulator Require an already ready device/emulator.
|
|
49
|
+
--dry-run Print commands without executing them.
|
|
50
|
+
-h, --help Show this help.
|
|
51
|
+
USAGE
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
die() {
|
|
55
|
+
echo "error: $*" >&2
|
|
56
|
+
exit 2
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
require_value() {
|
|
60
|
+
local flag="$1"
|
|
61
|
+
local value="${2-}"
|
|
62
|
+
if [[ -z "$value" || "$value" == --* ]]; then
|
|
63
|
+
die "$flag requires a value"
|
|
64
|
+
fi
|
|
65
|
+
printf '%s\n' "$value"
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
quote_cmd() {
|
|
69
|
+
local quoted=()
|
|
70
|
+
local arg
|
|
71
|
+
for arg in "$@"; do
|
|
72
|
+
quoted+=("$(printf '%q' "$arg")")
|
|
73
|
+
done
|
|
74
|
+
printf '%s\n' "${quoted[*]}"
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
run() {
|
|
78
|
+
echo "+ $(quote_cmd "$@")"
|
|
79
|
+
if [[ "$DRY_RUN" -eq 0 ]]; then
|
|
80
|
+
"$@"
|
|
81
|
+
fi
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
run_allow_fail() {
|
|
85
|
+
echo "+ $(quote_cmd "$@")"
|
|
86
|
+
if [[ "$DRY_RUN" -eq 0 ]]; then
|
|
87
|
+
"$@" >/dev/null 2>&1 || true
|
|
88
|
+
fi
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
run_background() {
|
|
92
|
+
echo "+ $(quote_cmd "$@") &"
|
|
93
|
+
if [[ "$DRY_RUN" -eq 0 ]]; then
|
|
94
|
+
"$@" &
|
|
95
|
+
fi
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
device_ready() {
|
|
99
|
+
echo "+ $(quote_cmd "$ADB" -s "$DEVICE" get-state)"
|
|
100
|
+
if [[ "$DRY_RUN" -eq 1 ]]; then
|
|
101
|
+
return 1
|
|
102
|
+
fi
|
|
103
|
+
local state
|
|
104
|
+
state="$("$ADB" -s "$DEVICE" get-state 2>/dev/null | tr -d '\r' || true)"
|
|
105
|
+
[[ "$state" == "device" ]]
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
ensure_android_device_ready() {
|
|
109
|
+
if device_ready; then
|
|
110
|
+
return 0
|
|
111
|
+
fi
|
|
112
|
+
|
|
113
|
+
if [[ "$AUTO_BOOT_EMULATOR" -eq 0 ]]; then
|
|
114
|
+
die "device $DEVICE is not ready and auto boot is disabled"
|
|
115
|
+
fi
|
|
116
|
+
[[ -n "$AVD" ]] || die "device $DEVICE is not ready; pass --avd <name> to boot an emulator or start a device manually"
|
|
117
|
+
|
|
118
|
+
echo "+ auto boot Android emulator $AVD when $DEVICE is not ready"
|
|
119
|
+
run_background "$ROOT/scripts/android-emulator.sh" boot --avd "$AVD" --device "$DEVICE"
|
|
120
|
+
run "$ROOT/scripts/android-emulator.sh" wait-ready --device "$DEVICE"
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
while [[ $# -gt 0 ]]; do
|
|
124
|
+
case "$1" in
|
|
125
|
+
--out)
|
|
126
|
+
OUT="$(require_value "$1" "${2-}")"
|
|
127
|
+
shift 2
|
|
128
|
+
;;
|
|
129
|
+
--app-id)
|
|
130
|
+
APP_ID="$(require_value "$1" "${2-}")"
|
|
131
|
+
shift 2
|
|
132
|
+
;;
|
|
133
|
+
--device)
|
|
134
|
+
DEVICE="$(require_value "$1" "${2-}")"
|
|
135
|
+
shift 2
|
|
136
|
+
;;
|
|
137
|
+
--avd)
|
|
138
|
+
AVD="$(require_value "$1" "${2-}")"
|
|
139
|
+
shift 2
|
|
140
|
+
;;
|
|
141
|
+
--runs)
|
|
142
|
+
RUNS="$(require_value "$1" "${2-}")"
|
|
143
|
+
shift 2
|
|
144
|
+
;;
|
|
145
|
+
--trace-root)
|
|
146
|
+
TRACE_ROOT="$(require_value "$1" "${2-}")"
|
|
147
|
+
shift 2
|
|
148
|
+
;;
|
|
149
|
+
--api)
|
|
150
|
+
API="$(require_value "$1" "${2-}")"
|
|
151
|
+
shift 2
|
|
152
|
+
;;
|
|
153
|
+
--build-tools)
|
|
154
|
+
BUILD_TOOLS="$(require_value "$1" "${2-}")"
|
|
155
|
+
shift 2
|
|
156
|
+
;;
|
|
157
|
+
--android-sdk)
|
|
158
|
+
ANDROID_SDK="$(require_value "$1" "${2-}")"
|
|
159
|
+
shift 2
|
|
160
|
+
;;
|
|
161
|
+
--adb)
|
|
162
|
+
ADB="$(require_value "$1" "${2-}")"
|
|
163
|
+
shift 2
|
|
164
|
+
;;
|
|
165
|
+
--emulator)
|
|
166
|
+
EMULATOR="$(require_value "$1" "${2-}")"
|
|
167
|
+
shift 2
|
|
168
|
+
;;
|
|
169
|
+
--no-auto-boot-emulator)
|
|
170
|
+
AUTO_BOOT_EMULATOR=0
|
|
171
|
+
shift
|
|
172
|
+
;;
|
|
173
|
+
--dry-run)
|
|
174
|
+
DRY_RUN=1
|
|
175
|
+
shift
|
|
176
|
+
;;
|
|
177
|
+
-h|--help)
|
|
178
|
+
usage
|
|
179
|
+
exit 0
|
|
180
|
+
;;
|
|
181
|
+
*)
|
|
182
|
+
die "unknown argument: $1"
|
|
183
|
+
;;
|
|
184
|
+
esac
|
|
185
|
+
done
|
|
186
|
+
|
|
187
|
+
[[ -n "$OUT" ]] || die "--out must not be empty"
|
|
188
|
+
[[ "$APP_ID" =~ ^[A-Za-z][A-Za-z0-9_]*(\.[A-Za-z][A-Za-z0-9_]*)+$ ]] || die "--app-id must be a Java-style package id"
|
|
189
|
+
[[ "$RUNS" =~ ^[0-9]+$ && "$RUNS" -ge 1 ]] || die "--runs must be a positive integer"
|
|
190
|
+
[[ "$API" =~ ^[0-9]+$ ]] || die "--api must be an integer"
|
|
191
|
+
[[ -n "$BUILD_TOOLS" ]] || die "--build-tools must be non-empty"
|
|
192
|
+
|
|
193
|
+
if [[ -z "$TRACE_ROOT" ]]; then
|
|
194
|
+
TRACE_ROOT="$OUT/traces/pilot"
|
|
195
|
+
fi
|
|
196
|
+
|
|
197
|
+
APK="$OUT/build/app-debug.apk"
|
|
198
|
+
SCENARIO="$OUT/.zmr/android-smoke.json"
|
|
199
|
+
|
|
200
|
+
echo "Android real demo app: $OUT"
|
|
201
|
+
echo "Android real demo traces: $TRACE_ROOT"
|
|
202
|
+
if [[ "$DRY_RUN" -eq 1 ]]; then
|
|
203
|
+
echo "DRY RUN: commands will be printed but not executed"
|
|
204
|
+
fi
|
|
205
|
+
|
|
206
|
+
run "$ROOT/scripts/create-android-demo-app.sh" \
|
|
207
|
+
--out "$OUT" \
|
|
208
|
+
--app-id "$APP_ID" \
|
|
209
|
+
--api "$API" \
|
|
210
|
+
--build-tools "$BUILD_TOOLS" \
|
|
211
|
+
--android-sdk "$ANDROID_SDK"
|
|
212
|
+
|
|
213
|
+
ensure_android_device_ready
|
|
214
|
+
|
|
215
|
+
run_allow_fail "$ADB" -s "$DEVICE" uninstall "$APP_ID"
|
|
216
|
+
run "$ADB" -s "$DEVICE" install -r "$APK"
|
|
217
|
+
|
|
218
|
+
run "$ROOT/scripts/benchmark.sh" \
|
|
219
|
+
--zmr "$SCENARIO" \
|
|
220
|
+
--device "$DEVICE" \
|
|
221
|
+
--app-id "$APP_ID" \
|
|
222
|
+
--runs "$RUNS" \
|
|
223
|
+
--trace-root "$TRACE_ROOT" \
|
|
224
|
+
--min-pass-rate 100 \
|
|
225
|
+
--max-failures 0
|
|
226
|
+
|
|
227
|
+
cat <<EOF
|
|
228
|
+
|
|
229
|
+
Android real demo complete.
|
|
230
|
+
App directory: $OUT
|
|
231
|
+
Trace directory: $TRACE_ROOT
|
|
232
|
+
EOF
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
SOURCE="${BASH_SOURCE[0]}"
|
|
5
|
+
while [[ -h "$SOURCE" ]]; do
|
|
6
|
+
SOURCE_DIR="$(cd -P "$(dirname "$SOURCE")" && pwd)"
|
|
7
|
+
SOURCE="$(readlink "$SOURCE")"
|
|
8
|
+
if [[ "$SOURCE" != /* ]]; then
|
|
9
|
+
SOURCE="$SOURCE_DIR/$SOURCE"
|
|
10
|
+
fi
|
|
11
|
+
done
|
|
12
|
+
|
|
13
|
+
ROOT="$(cd -P "$(dirname "$SOURCE")/.." && pwd)"
|
|
14
|
+
OUT="/tmp/zmr-ios-demo-$(date +%Y%m%d-%H%M%S)"
|
|
15
|
+
APP_NAME="ZMRDemo"
|
|
16
|
+
APP_ID="com.example.mobiletest"
|
|
17
|
+
DEVICE="booted"
|
|
18
|
+
DEPLOYMENT_TARGET="16.0"
|
|
19
|
+
RUNS="1"
|
|
20
|
+
TRACE_ROOT=""
|
|
21
|
+
XCRUN="${XCRUN:-xcrun}"
|
|
22
|
+
AUTO_BOOT_SIMULATOR=1
|
|
23
|
+
CLEANUP_BUILD_PRODUCTS=0
|
|
24
|
+
DRY_RUN=0
|
|
25
|
+
|
|
26
|
+
usage() {
|
|
27
|
+
cat <<'USAGE'
|
|
28
|
+
Usage:
|
|
29
|
+
scripts/demo-ios-real.sh [options]
|
|
30
|
+
|
|
31
|
+
Creates a generic public iOS simulator demo app, builds it, and runs the real
|
|
32
|
+
ZMR iOS pilot with the generated XCTest shim.
|
|
33
|
+
|
|
34
|
+
Options:
|
|
35
|
+
--out <dir> Demo app output directory. Default: /tmp/zmr-ios-demo-<timestamp>.
|
|
36
|
+
--name <name> App target name. Default: ZMRDemo.
|
|
37
|
+
--app-id <id> App bundle id. Default: com.example.mobiletest.
|
|
38
|
+
--device <udid|booted> Simulator target. Default: booted.
|
|
39
|
+
--deployment-target <ver> iOS deployment target. Default: 16.0.
|
|
40
|
+
--runs <n> Pilot run count. Default: 1.
|
|
41
|
+
--trace-root <dir> Trace output directory. Default: <out>/traces/pilot.
|
|
42
|
+
--xcrun <path> xcrun path. Default: xcrun.
|
|
43
|
+
--no-auto-boot-simulator Require an already booted simulator.
|
|
44
|
+
--cleanup-build-products Remove generated DerivedData after pilot traces are written.
|
|
45
|
+
--dry-run Print commands without executing them.
|
|
46
|
+
-h, --help Show this help.
|
|
47
|
+
USAGE
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
die() {
|
|
51
|
+
echo "error: $*" >&2
|
|
52
|
+
exit 2
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
require_value() {
|
|
56
|
+
local flag="$1"
|
|
57
|
+
local value="${2-}"
|
|
58
|
+
if [[ -z "$value" || "$value" == --* ]]; then
|
|
59
|
+
die "$flag requires a value"
|
|
60
|
+
fi
|
|
61
|
+
printf '%s\n' "$value"
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
quote_cmd() {
|
|
65
|
+
local quoted=()
|
|
66
|
+
local arg
|
|
67
|
+
for arg in "$@"; do
|
|
68
|
+
quoted+=("$(printf '%q' "$arg")")
|
|
69
|
+
done
|
|
70
|
+
printf '%s\n' "${quoted[*]}"
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
run() {
|
|
74
|
+
echo "+ $(quote_cmd "$@")"
|
|
75
|
+
if [[ "$DRY_RUN" -eq 0 ]]; then
|
|
76
|
+
"$@"
|
|
77
|
+
fi
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
available_ios_simulators() {
|
|
81
|
+
"$XCRUN" simctl list devices available --json | python3 -c '
|
|
82
|
+
import json
|
|
83
|
+
import sys
|
|
84
|
+
|
|
85
|
+
data = json.load(sys.stdin)
|
|
86
|
+
for runtime, devices in data.get("devices", {}).items():
|
|
87
|
+
if "iOS" not in runtime:
|
|
88
|
+
continue
|
|
89
|
+
for device in devices:
|
|
90
|
+
if device.get("isAvailable", True) and device.get("state") in ("Shutdown", "Booted"):
|
|
91
|
+
udid = device.get("udid")
|
|
92
|
+
if udid:
|
|
93
|
+
print(udid)
|
|
94
|
+
'
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
simulator_is_booted() {
|
|
98
|
+
local wanted="${1:-}"
|
|
99
|
+
local booted_text
|
|
100
|
+
booted_text="$("$XCRUN" simctl list devices booted 2>/dev/null || true)"
|
|
101
|
+
if [[ -z "$wanted" || "$wanted" == "booted" ]]; then
|
|
102
|
+
[[ "$booted_text" == *"(Booted)"* ]]
|
|
103
|
+
return
|
|
104
|
+
fi
|
|
105
|
+
[[ "$booted_text" == *"$wanted"* && "$booted_text" == *"(Booted)"* ]]
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
ensure_ios_simulator_ready() {
|
|
109
|
+
if [[ "$AUTO_BOOT_SIMULATOR" -eq 0 ]]; then
|
|
110
|
+
return 0
|
|
111
|
+
fi
|
|
112
|
+
|
|
113
|
+
run "$XCRUN" simctl list devices booted
|
|
114
|
+
if [[ "$DRY_RUN" -eq 1 ]]; then
|
|
115
|
+
if [[ "$DEVICE" == "booted" ]]; then
|
|
116
|
+
echo "+ auto boot first available iOS simulator when no simulator is booted"
|
|
117
|
+
echo "+ try available iOS simulators until one boots"
|
|
118
|
+
else
|
|
119
|
+
echo "+ auto boot iOS simulator $DEVICE when it is not booted"
|
|
120
|
+
fi
|
|
121
|
+
run "$XCRUN" simctl bootstatus "$DEVICE" -b
|
|
122
|
+
return 0
|
|
123
|
+
fi
|
|
124
|
+
|
|
125
|
+
if simulator_is_booted "$DEVICE"; then
|
|
126
|
+
run "$XCRUN" simctl bootstatus "$DEVICE" -b
|
|
127
|
+
return 0
|
|
128
|
+
fi
|
|
129
|
+
|
|
130
|
+
local boot_target="$DEVICE"
|
|
131
|
+
if [[ "$DEVICE" == "booted" ]]; then
|
|
132
|
+
local candidates=()
|
|
133
|
+
local listed_candidate
|
|
134
|
+
while IFS= read -r listed_candidate; do
|
|
135
|
+
[[ -n "$listed_candidate" ]] && candidates+=("$listed_candidate")
|
|
136
|
+
done < <(available_ios_simulators)
|
|
137
|
+
if [[ "${#candidates[@]}" -eq 0 ]]; then
|
|
138
|
+
die "no available iOS simulator found to boot"
|
|
139
|
+
fi
|
|
140
|
+
local candidate status
|
|
141
|
+
for candidate in "${candidates[@]}"; do
|
|
142
|
+
echo "+ $(quote_cmd "$XCRUN" simctl boot "$candidate")"
|
|
143
|
+
set +e
|
|
144
|
+
"$XCRUN" simctl boot "$candidate"
|
|
145
|
+
status=$?
|
|
146
|
+
set -e
|
|
147
|
+
if [[ "$status" -eq 0 ]]; then
|
|
148
|
+
run "$XCRUN" simctl bootstatus "$candidate" -b
|
|
149
|
+
return 0
|
|
150
|
+
fi
|
|
151
|
+
echo "warning: failed to boot iOS simulator $candidate; trying next available simulator" >&2
|
|
152
|
+
done
|
|
153
|
+
die "no available iOS simulator could be booted"
|
|
154
|
+
fi
|
|
155
|
+
|
|
156
|
+
run "$XCRUN" simctl boot "$boot_target"
|
|
157
|
+
run "$XCRUN" simctl bootstatus "$boot_target" -b
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
while [[ $# -gt 0 ]]; do
|
|
161
|
+
case "$1" in
|
|
162
|
+
--out)
|
|
163
|
+
OUT="$(require_value "$1" "${2-}")"
|
|
164
|
+
shift 2
|
|
165
|
+
;;
|
|
166
|
+
--name)
|
|
167
|
+
APP_NAME="$(require_value "$1" "${2-}")"
|
|
168
|
+
shift 2
|
|
169
|
+
;;
|
|
170
|
+
--app-id)
|
|
171
|
+
APP_ID="$(require_value "$1" "${2-}")"
|
|
172
|
+
shift 2
|
|
173
|
+
;;
|
|
174
|
+
--device)
|
|
175
|
+
DEVICE="$(require_value "$1" "${2-}")"
|
|
176
|
+
shift 2
|
|
177
|
+
;;
|
|
178
|
+
--deployment-target)
|
|
179
|
+
DEPLOYMENT_TARGET="$(require_value "$1" "${2-}")"
|
|
180
|
+
shift 2
|
|
181
|
+
;;
|
|
182
|
+
--runs)
|
|
183
|
+
RUNS="$(require_value "$1" "${2-}")"
|
|
184
|
+
shift 2
|
|
185
|
+
;;
|
|
186
|
+
--trace-root)
|
|
187
|
+
TRACE_ROOT="$(require_value "$1" "${2-}")"
|
|
188
|
+
shift 2
|
|
189
|
+
;;
|
|
190
|
+
--xcrun)
|
|
191
|
+
XCRUN="$(require_value "$1" "${2-}")"
|
|
192
|
+
shift 2
|
|
193
|
+
;;
|
|
194
|
+
--no-auto-boot-simulator)
|
|
195
|
+
AUTO_BOOT_SIMULATOR=0
|
|
196
|
+
shift
|
|
197
|
+
;;
|
|
198
|
+
--cleanup-build-products)
|
|
199
|
+
CLEANUP_BUILD_PRODUCTS=1
|
|
200
|
+
shift
|
|
201
|
+
;;
|
|
202
|
+
--dry-run)
|
|
203
|
+
DRY_RUN=1
|
|
204
|
+
shift
|
|
205
|
+
;;
|
|
206
|
+
-h|--help)
|
|
207
|
+
usage
|
|
208
|
+
exit 0
|
|
209
|
+
;;
|
|
210
|
+
*)
|
|
211
|
+
die "unknown argument: $1"
|
|
212
|
+
;;
|
|
213
|
+
esac
|
|
214
|
+
done
|
|
215
|
+
|
|
216
|
+
[[ -n "$OUT" ]] || die "--out must not be empty"
|
|
217
|
+
[[ "$APP_NAME" =~ ^[A-Za-z_][A-Za-z0-9_]*$ ]] || die "--name must be a valid Swift identifier"
|
|
218
|
+
[[ "$RUNS" =~ ^[0-9]+$ && "$RUNS" -ge 1 ]] || die "--runs must be a positive integer"
|
|
219
|
+
|
|
220
|
+
if [[ -z "$TRACE_ROOT" ]]; then
|
|
221
|
+
TRACE_ROOT="$OUT/traces/pilot"
|
|
222
|
+
fi
|
|
223
|
+
|
|
224
|
+
PROJECT_PATH="$OUT/ios/$APP_NAME.xcodeproj"
|
|
225
|
+
DERIVED_DATA="$OUT/DerivedData"
|
|
226
|
+
APP_PATH="$DERIVED_DATA/Build/Products/Debug-iphonesimulator/$APP_NAME.app"
|
|
227
|
+
IOS_SHIM="$OUT/.zmr/ios-shim"
|
|
228
|
+
|
|
229
|
+
echo "iOS real demo app: $OUT"
|
|
230
|
+
echo "iOS real demo traces: $TRACE_ROOT"
|
|
231
|
+
if [[ "$DRY_RUN" -eq 1 ]]; then
|
|
232
|
+
echo "DRY RUN: commands will be printed but not executed"
|
|
233
|
+
fi
|
|
234
|
+
|
|
235
|
+
run "$ROOT/scripts/create-ios-demo-app.sh" \
|
|
236
|
+
--out "$OUT" \
|
|
237
|
+
--name "$APP_NAME" \
|
|
238
|
+
--bundle-id "$APP_ID" \
|
|
239
|
+
--deployment-target "$DEPLOYMENT_TARGET"
|
|
240
|
+
|
|
241
|
+
run xcodebuild \
|
|
242
|
+
-project "$PROJECT_PATH" \
|
|
243
|
+
-scheme "$APP_NAME" \
|
|
244
|
+
-destination "generic/platform=iOS Simulator" \
|
|
245
|
+
-configuration Debug \
|
|
246
|
+
-derivedDataPath "$DERIVED_DATA" \
|
|
247
|
+
build
|
|
248
|
+
|
|
249
|
+
ensure_ios_simulator_ready
|
|
250
|
+
|
|
251
|
+
run "$ROOT/scripts/run-ios-pilot.sh" \
|
|
252
|
+
--app-root "$OUT" \
|
|
253
|
+
--app-path "$APP_PATH" \
|
|
254
|
+
--device "$DEVICE" \
|
|
255
|
+
--app-id "$APP_ID" \
|
|
256
|
+
--xcrun "$XCRUN" \
|
|
257
|
+
--ios-shim "$IOS_SHIM" \
|
|
258
|
+
--runs "$RUNS" \
|
|
259
|
+
--trace-root "$TRACE_ROOT"
|
|
260
|
+
|
|
261
|
+
if [[ "$CLEANUP_BUILD_PRODUCTS" -eq 1 ]]; then
|
|
262
|
+
run rm -rf "$DERIVED_DATA"
|
|
263
|
+
fi
|
|
264
|
+
|
|
265
|
+
cat <<EOF
|
|
266
|
+
|
|
267
|
+
iOS real demo complete.
|
|
268
|
+
App directory: $OUT
|
|
269
|
+
Trace directory: $TRACE_ROOT
|
|
270
|
+
EOF
|