zig-mobile-runner 0.1.0

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.
Files changed (225) hide show
  1. package/CHANGELOG.md +484 -0
  2. package/CONTRIBUTING.md +42 -0
  3. package/FEATURES.md +112 -0
  4. package/LICENSE +21 -0
  5. package/README.md +255 -0
  6. package/SECURITY.md +34 -0
  7. package/build.zig +38 -0
  8. package/build.zig.zon +7 -0
  9. package/clients/README.md +144 -0
  10. package/clients/go/README.md +24 -0
  11. package/clients/go/examples/fake-session/main.go +93 -0
  12. package/clients/go/go.mod +3 -0
  13. package/clients/go/zmr/client.go +432 -0
  14. package/clients/kotlin/README.md +35 -0
  15. package/clients/kotlin/build.gradle.kts +35 -0
  16. package/clients/kotlin/settings.gradle.kts +15 -0
  17. package/clients/kotlin/src/main/kotlin/dev/zmr/FakeSession.kt +86 -0
  18. package/clients/kotlin/src/main/kotlin/dev/zmr/ZmrClient.kt +67 -0
  19. package/clients/python/README.md +29 -0
  20. package/clients/python/examples/fake_session.py +48 -0
  21. package/clients/python/pyproject.toml +13 -0
  22. package/clients/python/zmr_client.py +202 -0
  23. package/clients/rust/Cargo.lock +107 -0
  24. package/clients/rust/Cargo.toml +10 -0
  25. package/clients/rust/README.md +19 -0
  26. package/clients/rust/examples/fake_session.rs +70 -0
  27. package/clients/rust/src/lib.rs +461 -0
  28. package/clients/swift/Package.swift +16 -0
  29. package/clients/swift/README.md +36 -0
  30. package/clients/swift/Sources/ZMRClient/ZMRClient.swift +114 -0
  31. package/clients/swift/Sources/ZMRFakeSession/main.swift +86 -0
  32. package/clients/typescript/README.md +34 -0
  33. package/clients/typescript/examples/fake-session.mjs +36 -0
  34. package/clients/typescript/index.d.ts +144 -0
  35. package/clients/typescript/index.mjs +192 -0
  36. package/clients/typescript/package.json +8 -0
  37. package/docs/adr/0001-agent-native-runner-boundary.md +31 -0
  38. package/docs/adr/0002-app-local-zmr-contract.md +39 -0
  39. package/docs/adr/0003-ios-simulator-xctest-shim.md +41 -0
  40. package/docs/adr/0004-benchmark-claims-and-baseline-collection.md +37 -0
  41. package/docs/adr/README.md +12 -0
  42. package/docs/ai-agents.md +156 -0
  43. package/docs/app-integration.md +316 -0
  44. package/docs/benchmarking.md +275 -0
  45. package/docs/client-installation.md +141 -0
  46. package/docs/clients.md +98 -0
  47. package/docs/config.md +175 -0
  48. package/docs/demo.md +259 -0
  49. package/docs/dsl.md +57 -0
  50. package/docs/install.md +233 -0
  51. package/docs/market-positioning.md +70 -0
  52. package/docs/npm.md +359 -0
  53. package/docs/protocol-fixtures/README.md +8 -0
  54. package/docs/protocol-fixtures/core-session.requests.jsonl +8 -0
  55. package/docs/protocol-fixtures/core-session.responses.jsonl +8 -0
  56. package/docs/protocol-versioning.md +65 -0
  57. package/docs/protocol.md +560 -0
  58. package/docs/publication.md +77 -0
  59. package/docs/release-audit.md +99 -0
  60. package/docs/release-candidate.md +111 -0
  61. package/docs/release-evidence.md +188 -0
  62. package/docs/release-notes-template.md +58 -0
  63. package/docs/roadmap.md +334 -0
  64. package/docs/scenario-authoring.md +88 -0
  65. package/docs/shipping.md +170 -0
  66. package/docs/trace-privacy.md +88 -0
  67. package/docs/troubleshooting.md +256 -0
  68. package/examples/android-app-auth-probe.json +89 -0
  69. package/examples/android-app-error-state.json +13 -0
  70. package/examples/android-app-login-smoke.json +192 -0
  71. package/examples/android-app-onboarding.json +12 -0
  72. package/examples/android-app-referral-deep-link.json +12 -0
  73. package/examples/android-shim-smoke.json +19 -0
  74. package/examples/demo-failure.json +12 -0
  75. package/examples/demo-fake.json +14 -0
  76. package/examples/ios-dev-client-open-link.json +26 -0
  77. package/examples/ios-dev-client-route-snapshot.json +24 -0
  78. package/examples/ios-shim-smoke.json +23 -0
  79. package/examples/ios-smoke.json +9 -0
  80. package/go.work +3 -0
  81. package/npm/agents.mjs +183 -0
  82. package/npm/app-config.mjs +95 -0
  83. package/npm/build-zmr.mjs +21 -0
  84. package/npm/commands.mjs +104 -0
  85. package/npm/generated-files.mjs +50 -0
  86. package/npm/index.mjs +75 -0
  87. package/npm/init-app.mjs +80 -0
  88. package/npm/package-scripts.mjs +72 -0
  89. package/npm/postinstall.mjs +21 -0
  90. package/npm/scaffold.mjs +179 -0
  91. package/npm/scenarios.mjs +93 -0
  92. package/npm/setup.mjs +69 -0
  93. package/npm/wizard.mjs +117 -0
  94. package/npm/zmr.mjs +23 -0
  95. package/package.json +114 -0
  96. package/prebuilds/darwin-arm64/zmr +0 -0
  97. package/prebuilds/darwin-x64/zmr +0 -0
  98. package/prebuilds/linux-arm64/zmr +0 -0
  99. package/prebuilds/linux-x64/zmr +0 -0
  100. package/schemas/README.md +26 -0
  101. package/schemas/action-result.schema.json +27 -0
  102. package/schemas/capabilities-output.schema.json +98 -0
  103. package/schemas/devices-output.schema.json +25 -0
  104. package/schemas/doctor-output.schema.json +51 -0
  105. package/schemas/explain-output.schema.json +51 -0
  106. package/schemas/import-output.schema.json +23 -0
  107. package/schemas/init-output.schema.json +71 -0
  108. package/schemas/json-rpc.schema.json +55 -0
  109. package/schemas/release-manifest.schema.json +43 -0
  110. package/schemas/release-readiness-output.schema.json +127 -0
  111. package/schemas/run-output.schema.json +43 -0
  112. package/schemas/scenario.schema.json +128 -0
  113. package/schemas/schemas-output.schema.json +26 -0
  114. package/schemas/semantic-snapshot.schema.json +116 -0
  115. package/schemas/snapshot.schema.json +60 -0
  116. package/schemas/trace-event.schema.json +14 -0
  117. package/schemas/trace-manifest.schema.json +59 -0
  118. package/schemas/validate-output.schema.json +42 -0
  119. package/schemas/version-output.schema.json +23 -0
  120. package/schemas/zmr-config.schema.json +75 -0
  121. package/scripts/android-emulator.sh +126 -0
  122. package/scripts/assert-ios-physical-ready.sh +213 -0
  123. package/scripts/benchmark-command.sh +307 -0
  124. package/scripts/benchmark.sh +359 -0
  125. package/scripts/benchmark_gate.py +117 -0
  126. package/scripts/benchmark_result_row.py +88 -0
  127. package/scripts/compare-benchmarks.py +288 -0
  128. package/scripts/create-android-demo-app.sh +342 -0
  129. package/scripts/create-ios-demo-app.sh +261 -0
  130. package/scripts/demo-android-real.sh +232 -0
  131. package/scripts/demo-ios-real.sh +270 -0
  132. package/scripts/demo.sh +464 -0
  133. package/scripts/device-matrix.sh +338 -0
  134. package/scripts/ensure-ios-shim-target.rb +237 -0
  135. package/scripts/install-android-shim.sh +281 -0
  136. package/scripts/install-ios-shim.sh +589 -0
  137. package/scripts/pilot-gate.sh +560 -0
  138. package/scripts/release-readiness.py +838 -0
  139. package/scripts/release-readiness.sh +91 -0
  140. package/scripts/run-android-pilot.sh +561 -0
  141. package/scripts/run-ios-pilot.sh +509 -0
  142. package/shims/android/README.md +21 -0
  143. package/shims/android/ZMRShimInstrumentedTest.java +152 -0
  144. package/shims/android/protocol.md +18 -0
  145. package/shims/ios/README.md +50 -0
  146. package/shims/ios/ZMRShim.swift +110 -0
  147. package/shims/ios/ZMRShimUITestCase.swift +475 -0
  148. package/shims/ios/protocol.md +74 -0
  149. package/skills/zmr-mobile-testing/SKILL.md +127 -0
  150. package/src/android.zig +344 -0
  151. package/src/android_device_info.zig +99 -0
  152. package/src/android_emulator.zig +154 -0
  153. package/src/android_screen_recording.zig +112 -0
  154. package/src/android_shell.zig +112 -0
  155. package/src/bundle.zig +124 -0
  156. package/src/bundle_redaction.zig +272 -0
  157. package/src/bundle_tar.zig +123 -0
  158. package/src/cli_devices.zig +97 -0
  159. package/src/cli_doctor.zig +114 -0
  160. package/src/cli_import.zig +70 -0
  161. package/src/cli_info.zig +39 -0
  162. package/src/cli_init.zig +72 -0
  163. package/src/cli_output.zig +467 -0
  164. package/src/cli_run.zig +259 -0
  165. package/src/cli_serve.zig +287 -0
  166. package/src/cli_trace.zig +111 -0
  167. package/src/cli_validate.zig +41 -0
  168. package/src/command.zig +211 -0
  169. package/src/config.zig +305 -0
  170. package/src/config_diagnostics.zig +212 -0
  171. package/src/config_paths.zig +49 -0
  172. package/src/device_registry.zig +37 -0
  173. package/src/doctor.zig +412 -0
  174. package/src/doctor_hints.zig +52 -0
  175. package/src/errors.zig +55 -0
  176. package/src/fake_device.zig +163 -0
  177. package/src/health.zig +28 -0
  178. package/src/importer.zig +343 -0
  179. package/src/importer_json.zig +100 -0
  180. package/src/importer_model.zig +103 -0
  181. package/src/ios.zig +399 -0
  182. package/src/ios_devices.zig +219 -0
  183. package/src/ios_lifecycle.zig +72 -0
  184. package/src/ios_shim.zig +242 -0
  185. package/src/ios_snapshot.zig +20 -0
  186. package/src/json_fields.zig +80 -0
  187. package/src/json_rpc.zig +150 -0
  188. package/src/json_rpc_methods.zig +318 -0
  189. package/src/json_rpc_observation.zig +31 -0
  190. package/src/json_rpc_params.zig +52 -0
  191. package/src/json_rpc_protocol.zig +110 -0
  192. package/src/json_rpc_trace.zig +73 -0
  193. package/src/main.zig +135 -0
  194. package/src/mcp.zig +234 -0
  195. package/src/mcp_protocol.zig +64 -0
  196. package/src/mcp_trace.zig +83 -0
  197. package/src/report.zig +346 -0
  198. package/src/report_html.zig +63 -0
  199. package/src/report_values.zig +27 -0
  200. package/src/run_options.zig +152 -0
  201. package/src/runner.zig +280 -0
  202. package/src/runner_actions.zig +109 -0
  203. package/src/runner_config.zig +6 -0
  204. package/src/runner_diagnostics.zig +268 -0
  205. package/src/runner_events.zig +170 -0
  206. package/src/runner_native.zig +88 -0
  207. package/src/runner_waits.zig +300 -0
  208. package/src/scaffold.zig +472 -0
  209. package/src/scenario.zig +346 -0
  210. package/src/scenario_fields.zig +50 -0
  211. package/src/schema_registry.zig +53 -0
  212. package/src/selector.zig +84 -0
  213. package/src/semantic.zig +171 -0
  214. package/src/trace.zig +315 -0
  215. package/src/trace_json.zig +340 -0
  216. package/src/trace_summary.zig +218 -0
  217. package/src/trace_summary_diagnostic.zig +202 -0
  218. package/src/types.zig +120 -0
  219. package/src/uiautomator.zig +164 -0
  220. package/src/validation.zig +187 -0
  221. package/src/version.zig +22 -0
  222. package/viewer/app.js +373 -0
  223. package/viewer/index.html +126 -0
  224. package/viewer/parser.js +233 -0
  225. package/viewer/styles.css +585 -0
@@ -0,0 +1,261 @@
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=""
15
+ APP_NAME="ZMRDemo"
16
+ BUNDLE_ID="com.example.mobiletest"
17
+ DEPLOYMENT_TARGET="16.0"
18
+
19
+ usage() {
20
+ cat <<'USAGE'
21
+ Usage:
22
+ scripts/create-ios-demo-app.sh --out <dir> [options]
23
+
24
+ Creates a small public SwiftUI iOS simulator demo app and installs the ZMR
25
+ XCTest shim into it. The generated app is intentionally generic and contains no
26
+ private app references.
27
+
28
+ Options:
29
+ --out <dir> Output app repository directory. Required.
30
+ --name <name> App target name. Default: ZMRDemo.
31
+ --bundle-id <id> App bundle id. Default: com.example.mobiletest.
32
+ --deployment-target <ver> iOS deployment target. Default: 16.0.
33
+ -h, --help Show this help.
34
+
35
+ After generation:
36
+ cd <dir>
37
+ xcodebuild -project ios/ZMRDemo.xcodeproj -scheme ZMRDemo -destination 'generic/platform=iOS Simulator' -derivedDataPath DerivedData build
38
+ xcrun simctl install booted DerivedData/Build/Products/Debug-iphonesimulator/ZMRDemo.app
39
+ zmr run .zmr/ios-shim-smoke.json --platform ios --device booted --app-id com.example.mobiletest --ios-shim ./.zmr/ios-shim --trace-dir traces/zmr-ios-demo
40
+ USAGE
41
+ }
42
+
43
+ die() {
44
+ echo "error: $*" >&2
45
+ exit 2
46
+ }
47
+
48
+ require_value() {
49
+ local flag="$1"
50
+ local value="${2-}"
51
+ if [[ -z "$value" || "$value" == --* ]]; then
52
+ die "$flag requires a value"
53
+ fi
54
+ printf '%s\n' "$value"
55
+ }
56
+
57
+ while [[ $# -gt 0 ]]; do
58
+ case "$1" in
59
+ --out)
60
+ OUT="$(require_value "$1" "${2-}")"
61
+ shift 2
62
+ ;;
63
+ --name)
64
+ APP_NAME="$(require_value "$1" "${2-}")"
65
+ shift 2
66
+ ;;
67
+ --bundle-id)
68
+ BUNDLE_ID="$(require_value "$1" "${2-}")"
69
+ shift 2
70
+ ;;
71
+ --deployment-target)
72
+ DEPLOYMENT_TARGET="$(require_value "$1" "${2-}")"
73
+ shift 2
74
+ ;;
75
+ -h|--help)
76
+ usage
77
+ exit 0
78
+ ;;
79
+ *)
80
+ die "unknown argument: $1"
81
+ ;;
82
+ esac
83
+ done
84
+
85
+ [[ -n "$OUT" ]] || die "--out is required"
86
+ [[ "$APP_NAME" =~ ^[A-Za-z_][A-Za-z0-9_]*$ ]] || die "--name must be a valid Swift identifier"
87
+ if ! ruby -e 'require "xcodeproj"' >/dev/null 2>&1; then
88
+ die "Ruby gem xcodeproj is required. Install it with: gem install xcodeproj"
89
+ fi
90
+
91
+ mkdir -p "$OUT/ios/$APP_NAME"
92
+ OUT="$(cd "$OUT" && pwd)"
93
+ PROJECT_PATH="$OUT/ios/$APP_NAME.xcodeproj"
94
+ SOURCE_DIR="$OUT/ios/$APP_NAME"
95
+ TEST_SCHEME="${APP_NAME}ZMRUITests"
96
+
97
+ cat > "$SOURCE_DIR/${APP_NAME}App.swift" <<EOF
98
+ import SwiftUI
99
+
100
+ @main
101
+ struct ${APP_NAME}App: App {
102
+ var body: some Scene {
103
+ WindowGroup {
104
+ ContentView()
105
+ }
106
+ }
107
+ }
108
+ EOF
109
+
110
+ cat > "$SOURCE_DIR/ContentView.swift" <<'EOF'
111
+ import SwiftUI
112
+
113
+ struct ContentView: View {
114
+ @State private var input = ""
115
+ @State private var status = "Ready"
116
+ @FocusState private var inputFocused: Bool
117
+
118
+ var body: some View {
119
+ VStack(spacing: 20) {
120
+ Text("ZMR iOS Demo")
121
+ .font(.title)
122
+ .accessibilityIdentifier("demo_title")
123
+
124
+ Button("Continue") {
125
+ status = "Continue tapped"
126
+ inputFocused = true
127
+ }
128
+ .buttonStyle(.borderedProminent)
129
+ .accessibilityIdentifier("continue_button")
130
+
131
+ TextField("Type here", text: $input)
132
+ .textFieldStyle(.roundedBorder)
133
+ .focused($inputFocused)
134
+ .accessibilityIdentifier("demo_input")
135
+ .padding(.horizontal, 32)
136
+
137
+ Text(status)
138
+ .accessibilityIdentifier("demo_status")
139
+ }
140
+ .padding()
141
+ .onOpenURL { _ in
142
+ status = "Deep link opened"
143
+ }
144
+ }
145
+ }
146
+ EOF
147
+
148
+ cat > "$SOURCE_DIR/Info.plist" <<EOF
149
+ <?xml version="1.0" encoding="UTF-8"?>
150
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
151
+ <plist version="1.0">
152
+ <dict>
153
+ <key>CFBundleDevelopmentRegion</key>
154
+ <string>\$(DEVELOPMENT_LANGUAGE)</string>
155
+ <key>CFBundleExecutable</key>
156
+ <string>\$(EXECUTABLE_NAME)</string>
157
+ <key>CFBundleIdentifier</key>
158
+ <string>\$(PRODUCT_BUNDLE_IDENTIFIER)</string>
159
+ <key>CFBundleInfoDictionaryVersion</key>
160
+ <string>6.0</string>
161
+ <key>CFBundleName</key>
162
+ <string>\$(PRODUCT_NAME)</string>
163
+ <key>CFBundlePackageType</key>
164
+ <string>APPL</string>
165
+ <key>CFBundleShortVersionString</key>
166
+ <string>1.0</string>
167
+ <key>CFBundleURLTypes</key>
168
+ <array>
169
+ <dict>
170
+ <key>CFBundleURLName</key>
171
+ <string>${BUNDLE_ID}</string>
172
+ <key>CFBundleURLSchemes</key>
173
+ <array>
174
+ <string>exampleapp</string>
175
+ </array>
176
+ </dict>
177
+ </array>
178
+ <key>CFBundleVersion</key>
179
+ <string>1</string>
180
+ <key>UILaunchScreen</key>
181
+ <dict/>
182
+ </dict>
183
+ </plist>
184
+ EOF
185
+
186
+ ruby - "$PROJECT_PATH" "$APP_NAME" "$BUNDLE_ID" "$DEPLOYMENT_TARGET" <<'RUBY'
187
+ require "fileutils"
188
+ require "xcodeproj"
189
+
190
+ project_path, app_name, bundle_id, deployment_target = ARGV
191
+ project = Xcodeproj::Project.new(project_path)
192
+ target = project.new_target(:application, app_name, :ios, deployment_target)
193
+ group = project.main_group.new_group(app_name, app_name)
194
+
195
+ ["#{app_name}App.swift", "ContentView.swift"].each do |source|
196
+ file_ref = group.new_file(source)
197
+ target.add_file_references([file_ref])
198
+ end
199
+ group.new_file("Info.plist")
200
+
201
+ target.build_configurations.each do |configuration|
202
+ settings = configuration.build_settings
203
+ settings["PRODUCT_BUNDLE_IDENTIFIER"] = bundle_id
204
+ settings["PRODUCT_NAME"] = "$(TARGET_NAME)"
205
+ settings["SWIFT_VERSION"] = "5.0"
206
+ settings["GENERATE_INFOPLIST_FILE"] = "NO"
207
+ settings["INFOPLIST_FILE"] = "#{app_name}/Info.plist"
208
+ settings["TARGETED_DEVICE_FAMILY"] = "1,2"
209
+ settings["CODE_SIGNING_ALLOWED"] = "NO"
210
+ end
211
+
212
+ project.save
213
+ scheme_dir = File.join(project.path, "xcshareddata/xcschemes")
214
+ FileUtils.mkdir_p(scheme_dir)
215
+ scheme_path = File.join(scheme_dir, "#{app_name}.xcscheme")
216
+ File.write(scheme_path, <<~XML)
217
+ <?xml version="1.0" encoding="UTF-8"?>
218
+ <Scheme LastUpgradeVersion = "1600" version = "1.7">
219
+ <BuildAction parallelizeBuildables = "YES" buildImplicitDependencies = "YES">
220
+ <BuildActionEntries>
221
+ <BuildActionEntry buildForTesting = "YES" buildForRunning = "YES" buildForProfiling = "YES" buildForArchiving = "YES" buildForAnalyzing = "YES">
222
+ <BuildableReference BuildableIdentifier = "primary" BlueprintIdentifier = "#{target.uuid}" BuildableName = "#{app_name}.app" BlueprintName = "#{app_name}" ReferencedContainer = "container:#{File.basename(project.path)}">
223
+ </BuildableReference>
224
+ </BuildActionEntry>
225
+ </BuildActionEntries>
226
+ </BuildAction>
227
+ <LaunchAction buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" debugDocumentVersioning = "YES" debugServiceExtension = "internal" allowLocationSimulation = "YES">
228
+ <BuildableProductRunnable runnableDebuggingMode = "0">
229
+ <BuildableReference BuildableIdentifier = "primary" BlueprintIdentifier = "#{target.uuid}" BuildableName = "#{app_name}.app" BlueprintName = "#{app_name}" ReferencedContainer = "container:#{File.basename(project.path)}">
230
+ </BuildableReference>
231
+ </BuildableProductRunnable>
232
+ </LaunchAction>
233
+ <ProfileAction buildConfiguration = "Release" shouldUseLaunchSchemeArgsEnv = "YES" savedToolIdentifier = "" useCustomWorkingDirectory = "NO" debugDocumentVersioning = "YES">
234
+ <BuildableProductRunnable runnableDebuggingMode = "0">
235
+ <BuildableReference BuildableIdentifier = "primary" BlueprintIdentifier = "#{target.uuid}" BuildableName = "#{app_name}.app" BlueprintName = "#{app_name}" ReferencedContainer = "container:#{File.basename(project.path)}">
236
+ </BuildableReference>
237
+ </BuildableProductRunnable>
238
+ </ProfileAction>
239
+ </Scheme>
240
+ XML
241
+ RUBY
242
+
243
+ "$ROOT/scripts/install-ios-shim.sh" \
244
+ --app-root "$OUT" \
245
+ --scheme "$TEST_SCHEME" \
246
+ --test-target "$TEST_SCHEME" \
247
+ --project "ios/$APP_NAME.xcodeproj" \
248
+ --app-target "$APP_NAME" \
249
+ --bundle-id "$BUNDLE_ID" \
250
+ --test-bundle-id "$BUNDLE_ID.zmr-uitests" \
251
+ --deployment-target "$DEPLOYMENT_TARGET" \
252
+ --patch-xcodeproj
253
+
254
+ cp "$ROOT/examples/ios-smoke.json" "$OUT/.zmr/ios-smoke.json"
255
+ cp "$ROOT/examples/ios-shim-smoke.json" "$OUT/.zmr/ios-shim-smoke.json"
256
+
257
+ echo "created iOS demo app at $OUT"
258
+ echo "project: $PROJECT_PATH"
259
+ echo "app scheme: $APP_NAME"
260
+ echo "shim scheme: $TEST_SCHEME"
261
+ echo "bundle id: $BUNDLE_ID"
@@ -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