agent-device 0.21.2 → 0.21.4
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/android/ime-helper/dist/{agent-device-android-ime-helper-0.21.2.apk → agent-device-android-ime-helper-0.21.4.apk} +0 -0
- package/android/ime-helper/dist/agent-device-android-ime-helper-0.21.4.apk.sha256 +1 -0
- package/android/ime-helper/dist/{agent-device-android-ime-helper-0.21.2.manifest.json → agent-device-android-ime-helper-0.21.4.manifest.json} +4 -4
- package/android/snapshot-helper/dist/{agent-device-android-snapshot-helper-0.21.2.apk → agent-device-android-snapshot-helper-0.21.4.apk} +0 -0
- package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.21.4.apk.sha256 +1 -0
- package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.21.4.manifest.json +16 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunner/AgentDeviceRunnerApp.m +39 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerSystemSurfaceHostPolicy.swift +9 -1
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+AXSnapshotFallback.swift +2 -1
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Alert.swift +10 -1
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandExecution.swift +26 -124
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandJournal.swift +46 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Lifecycle.swift +36 -4
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+MainThreadWork.swift +229 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Models.swift +15 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Snapshot.swift +4 -40
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotCapturePlan.swift +6 -40
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Transport.swift +30 -9
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests.swift +22 -6
- package/dist/src/adapter.js +1 -1
- package/dist/src/adb-executor.js +2 -2
- package/dist/src/adb-failure.js +1 -1
- package/dist/src/agent-browser-process-record.js +1 -1
- package/dist/src/agent-device-client.js +2 -2
- package/dist/src/api.js +3 -11
- package/dist/src/app-launch.js +1 -1
- package/dist/src/app-lifecycle.js +1 -1
- package/dist/src/app-log-reconnect.js +1 -1
- package/dist/src/archive.js +2 -2
- package/dist/src/auth.js +1 -1
- package/dist/src/back-mode.js +1 -1
- package/dist/src/cli-help.js +2 -2
- package/dist/src/cli.js +4 -4
- package/dist/src/client-metro-companion.js +1 -1
- package/dist/src/client-metro.js +1 -1
- package/dist/src/client-types.d.ts +70 -5
- package/dist/src/code-signature-cache.js +1 -1
- package/dist/src/command-schema.js +1 -1
- package/dist/src/command-tools.js +2 -2
- package/dist/src/command.js +1 -1
- package/dist/src/config.js +1 -1
- package/dist/src/connection-runtime.js +1 -1
- package/dist/src/connection.js +1 -1
- package/dist/src/contracts.js +1 -1
- package/dist/src/daemon-client-lifecycle.js +1 -1
- package/dist/src/daemon-registration.js +1 -1
- package/dist/src/daemon-resolution.js +1 -0
- package/dist/src/daemon-shutdown-report.js +1 -1
- package/dist/src/daemon.js +1 -1
- package/dist/src/device-claim-rule.js +1 -1
- package/dist/src/device-input-state.d.ts +10 -8
- package/dist/src/device-inventory-context.js +1 -1
- package/dist/src/device-session.js +1 -1
- package/dist/src/diagnostics.js +1 -1
- package/dist/src/error.js +2 -2
- package/dist/src/exec.js +1 -1
- package/dist/src/file.js +1 -1
- package/dist/src/find.js +1 -1
- package/dist/src/gesture-runtime.js +1 -1
- package/dist/src/harmonyos.js +1 -1
- package/dist/src/helper.js +1 -1
- package/dist/src/human-control-contract.js +1 -1
- package/dist/src/human-control.js +1 -1
- package/dist/src/index.js +1 -1
- package/dist/src/install-source-network-transport.js +1 -1
- package/dist/src/interaction.js +1 -1
- package/dist/src/interaction2.js +1 -1
- package/dist/src/interactor.js +4 -4
- package/dist/src/interactors.js +1 -1
- package/dist/src/internal/bin.js +1 -1
- package/dist/src/internal/daemon.js +2 -2
- package/dist/src/internal/png-worker.js +1 -1
- package/dist/src/ios-client.js +121 -7
- package/dist/src/ios-snapshot-adapter.js +1 -1
- package/dist/src/ios-system-surface.js +1 -1
- package/dist/src/lease-scope.js +1 -1
- package/dist/src/limrun-delta-sync-omitted.js +1 -0
- package/dist/src/limrun.d.ts +0 -1598
- package/dist/src/location-coordinates.js +1 -1
- package/dist/src/mechanics.js +16 -16
- package/dist/src/output-common.js +2 -0
- package/dist/src/owner-identity.js +1 -1
- package/dist/src/perf-runtime-operation-builder.js +1 -1
- package/dist/src/perf-runtime-plan.js +1 -1
- package/dist/src/physical-device-control.js +1 -1
- package/dist/src/platform-request-scope.js +1 -1
- package/dist/src/platform-runtime-android-adb-host.js +1 -1
- package/dist/src/platform-runtime-app-log-android-transport.js +1 -1
- package/dist/src/platform-runtime-app-log-process.js +1 -1
- package/dist/src/platform-runtime-host.js +1 -1
- package/dist/src/platform-runtime-operation-host.js +2 -2
- package/dist/src/platform-runtime-screen-recording-android-host.js +1 -1
- package/dist/src/platform-runtime-screen-recording-finalizer-host.js +1 -1
- package/dist/src/platform-runtime-screen-recording-harmony-host.js +1 -1
- package/dist/src/platform-runtime-screen-recording-output-host.js +1 -1
- package/dist/src/platform-runtime-screen-recording-process-host.js +1 -1
- package/dist/src/platform-runtime.js +1 -1
- package/dist/src/process.js +1 -1
- package/dist/src/provider-webdriver.js +1 -1
- package/dist/src/proxy.js +1 -1
- package/dist/src/quality-warnings.js +1 -1
- package/dist/src/react-native.js +1 -1
- package/dist/src/record-runtime.js +1 -1
- package/dist/src/recording-stop-observation.js +1 -0
- package/dist/src/register-builtins.js +1 -1
- package/dist/src/registry.js +35 -36
- package/dist/src/replay-divergence.js +1 -1
- package/dist/src/reporting.js +11 -9
- package/dist/src/request-providers.js +1 -1
- package/dist/src/result-serialization.js +1 -1
- package/dist/src/runner-cache-metadata.js +2 -2
- package/dist/src/runner-client.js +1 -1
- package/dist/src/runner-disposal.js +1 -1
- package/dist/src/runner-operations-facade.js +1 -1
- package/dist/src/runner.js +1 -1
- package/dist/src/runtime.js +3 -3
- package/dist/src/runtime10.js +1 -1
- package/dist/src/runtime2.js +4 -4
- package/dist/src/runtime3.js +1 -1
- package/dist/src/runtime4.js +5 -5
- package/dist/src/runtime5.js +1 -1
- package/dist/src/runtime6.js +1 -1
- package/dist/src/runtime9.js +1 -1
- package/dist/src/screen-recording-completion.js +1 -1
- package/dist/src/screen-recording-resource-recovery.js +1 -1
- package/dist/src/screen-recording-runtime.js +1 -1
- package/dist/src/screenshot-result.js +1 -1
- package/dist/src/screenshot-runtime.js +1 -1
- package/dist/src/sdk-batch.js +2 -2
- package/dist/src/sdk-contracts.js +2 -2
- package/dist/src/sdk-remote-config.d.ts +1 -0
- package/dist/src/sdk-remote-config.js +1 -1
- package/dist/src/sdk-selectors.d.ts +36 -24
- package/dist/src/selector-runtime.js +1 -1
- package/dist/src/session-observation.js +1 -1
- package/dist/src/session-routing.js +1 -1
- package/dist/src/session-snapshot.js +1 -1
- package/dist/src/session-store.js +2 -2
- package/dist/src/session2.js +5 -5
- package/dist/src/simulator.js +1 -1
- package/dist/src/snapshot-runtime-binding.js +1 -1
- package/dist/src/snapshot-runtime.js +1 -1
- package/dist/src/snapshot.js +1 -1
- package/dist/src/snapshot4.js +1 -1
- package/dist/src/src3.js +1 -1
- package/dist/src/src4.js +1 -1
- package/dist/src/stop-sequence.js +1 -0
- package/dist/src/success-text.js +1 -1
- package/dist/src/text-entry-focus.js +1 -0
- package/dist/src/tool-provider.js +1 -1
- package/dist/src/tool-provider2.js +1 -1
- package/dist/src/tool-provider3.js +1 -1
- package/dist/src/type-text-runtime.js +1 -1
- package/dist/src/video.js +2 -2
- package/dist/src/yauzl.js +1 -0
- package/package.json +2 -2
- package/server.json +2 -2
- package/android/ime-helper/dist/agent-device-android-ime-helper-0.21.2.apk.sha256 +0 -1
- package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.21.2.apk.sha256 +0 -1
- package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.21.2.manifest.json +0 -17
- package/dist/src/audio-probe-support.js +0 -1
- package/dist/src/config2.js +0 -1
- package/dist/src/provider-device-runtime.js +0 -1
- package/dist/src/screen-recording-live-handle.js +0 -1
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import XCTest
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
extension RunnerTests {
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
private final class MainThreadWorkState {
|
|
16
|
+
var finished = false
|
|
17
|
+
var abandoned = false
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
enum MainThreadBusyState {
|
|
21
|
+
case idle
|
|
22
|
+
case busy(abandonedForSeconds: TimeInterval)
|
|
23
|
+
case wedged(abandonedForSeconds: TimeInterval)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
var reportsMainThreadBusy: Bool {
|
|
29
|
+
if case .idle = self { return false }
|
|
30
|
+
return true
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
func currentMainThreadBusyState() -> MainThreadBusyState {
|
|
35
|
+
mainThreadWorkLock.lock()
|
|
36
|
+
defer { mainThreadWorkLock.unlock() }
|
|
37
|
+
guard abandonedMainThreadWorkCount > 0 else { return .idle }
|
|
38
|
+
let abandonedFor = abandonedMainThreadWorkSince.map { Date().timeIntervalSince($0) } ?? 0
|
|
39
|
+
if abandonedFor > mainThreadWedgeThreshold {
|
|
40
|
+
return .wedged(abandonedForSeconds: abandonedFor)
|
|
41
|
+
}
|
|
42
|
+
return .busy(abandonedForSeconds: abandonedFor)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
func hasAbandonedMainThreadWork() -> Bool {
|
|
46
|
+
mainThreadWorkLock.lock()
|
|
47
|
+
defer { mainThreadWorkLock.unlock() }
|
|
48
|
+
return abandonedMainThreadWorkCount > 0
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
func runMainThreadWork<T>(
|
|
56
|
+
_ operation: String,
|
|
57
|
+
timeout: TimeInterval,
|
|
58
|
+
timeoutError: @escaping () -> Error,
|
|
59
|
+
onAbandoned: (() -> Void)? = nil,
|
|
60
|
+
_ work: @escaping () throws -> T
|
|
61
|
+
) throws -> T {
|
|
62
|
+
if Thread.isMainThread {
|
|
63
|
+
return try work()
|
|
64
|
+
}
|
|
65
|
+
var result: Result<T, Error>?
|
|
66
|
+
let semaphore = DispatchSemaphore(value: 0)
|
|
67
|
+
let workState = MainThreadWorkState()
|
|
68
|
+
DispatchQueue.main.async {
|
|
69
|
+
do {
|
|
70
|
+
result = .success(try work())
|
|
71
|
+
} catch {
|
|
72
|
+
result = .failure(error)
|
|
73
|
+
}
|
|
74
|
+
self.mainThreadWorkLock.lock()
|
|
75
|
+
let abandoned = workState.abandoned
|
|
76
|
+
if abandoned {
|
|
77
|
+
self.abandonedMainThreadWorkCount -= 1
|
|
78
|
+
if self.abandonedMainThreadWorkCount == 0 {
|
|
79
|
+
self.abandonedMainThreadWorkSince = nil
|
|
80
|
+
}
|
|
81
|
+
} else {
|
|
82
|
+
workState.finished = true
|
|
83
|
+
}
|
|
84
|
+
let allDrained = abandoned && self.abandonedMainThreadWorkCount == 0
|
|
85
|
+
self.mainThreadWorkLock.unlock()
|
|
86
|
+
if abandoned {
|
|
87
|
+
NSLog("AGENT_DEVICE_RUNNER_MAIN_THREAD_WORK_DRAINED operation=%@", operation)
|
|
88
|
+
if allDrained {
|
|
89
|
+
NSLog("AGENT_DEVICE_RUNNER_ABANDONED_WORK_DRAINED")
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
semaphore.signal()
|
|
93
|
+
}
|
|
94
|
+
let waitResult = semaphore.wait(timeout: .now() + timeout)
|
|
95
|
+
if waitResult == .timedOut {
|
|
96
|
+
mainThreadWorkLock.lock()
|
|
97
|
+
let abandoned = !workState.finished
|
|
98
|
+
if abandoned {
|
|
99
|
+
workState.abandoned = true
|
|
100
|
+
abandonedMainThreadWorkCount += 1
|
|
101
|
+
if abandonedMainThreadWorkSince == nil {
|
|
102
|
+
abandonedMainThreadWorkSince = Date()
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
mainThreadWorkLock.unlock()
|
|
106
|
+
if abandoned {
|
|
107
|
+
NSLog(
|
|
108
|
+
"AGENT_DEVICE_RUNNER_MAIN_THREAD_WORK_ABANDONED operation=%@ slice=%.1f",
|
|
109
|
+
operation,
|
|
110
|
+
timeout
|
|
111
|
+
)
|
|
112
|
+
onAbandoned?()
|
|
113
|
+
}
|
|
114
|
+
throw timeoutError()
|
|
115
|
+
}
|
|
116
|
+
switch result {
|
|
117
|
+
case .success(let value):
|
|
118
|
+
return value
|
|
119
|
+
case .failure(let error):
|
|
120
|
+
throw error
|
|
121
|
+
case .none:
|
|
122
|
+
throw NSError(
|
|
123
|
+
domain: RunnerErrorDomain.general,
|
|
124
|
+
code: RunnerErrorCode.noResponseFromMainThread,
|
|
125
|
+
userInfo: [NSLocalizedDescriptionKey: "no response from main thread"]
|
|
126
|
+
)
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
func mainThreadExecutionTimeoutError() -> Error {
|
|
131
|
+
NSError(
|
|
132
|
+
domain: RunnerErrorDomain.general,
|
|
133
|
+
code: RunnerErrorCode.mainThreadExecutionTimedOut,
|
|
134
|
+
userInfo: [NSLocalizedDescriptionKey: "main thread execution timed out"]
|
|
135
|
+
)
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
|
package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Models.swift
CHANGED
|
@@ -229,6 +229,16 @@ extension Response {
|
|
|
229
229
|
payload.currentUptimeMs = value
|
|
230
230
|
return Response(ok: ok, data: payload, error: error)
|
|
231
231
|
}
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
func stampingCurrentMainThreadBusy(_ value: Bool) -> Response {
|
|
237
|
+
guard ok else { return self }
|
|
238
|
+
var payload = data ?? DataPayload()
|
|
239
|
+
payload.runnerMainThreadBusy = value
|
|
240
|
+
return Response(ok: ok, data: payload, error: error)
|
|
241
|
+
}
|
|
232
242
|
}
|
|
233
243
|
|
|
234
244
|
struct DataPayload: Codable {
|
|
@@ -276,6 +286,11 @@ struct DataPayload: Codable {
|
|
|
276
286
|
var textEntryRoute: String?
|
|
277
287
|
var runnerFatal: Bool?
|
|
278
288
|
var runnerFatalReason: String?
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
var runnerMainThreadBusy: Bool?
|
|
279
294
|
var completedSteps: Int?
|
|
280
295
|
var failedStepIndex: Int?
|
|
281
296
|
var sequenceResults: [SequenceStepResult]?
|
package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Snapshot.swift
CHANGED
|
@@ -321,6 +321,7 @@ extension RunnerTests {
|
|
|
321
321
|
let startedAt = Date()
|
|
322
322
|
do {
|
|
323
323
|
return try runMainThreadWork(
|
|
324
|
+
"system_modal_probe",
|
|
324
325
|
timeout: slice,
|
|
325
326
|
timeoutError: {
|
|
326
327
|
SnapshotCaptureFailure(
|
|
@@ -330,16 +331,10 @@ extension RunnerTests {
|
|
|
330
331
|
)
|
|
331
332
|
},
|
|
332
333
|
onAbandoned: {
|
|
333
|
-
self.retainAbandonedXCTestChannelWork()
|
|
334
|
-
NSLog("AGENT_DEVICE_RUNNER_SYSTEM_MODAL_PROBE_TIMEOUT slice=%.1f", slice)
|
|
335
334
|
self.penalizeSnapshotXCTestChannel(
|
|
336
335
|
bundleId: self.currentBundleId,
|
|
337
336
|
reason: "system_modal_probe_timeout"
|
|
338
337
|
)
|
|
339
|
-
},
|
|
340
|
-
onDrained: {
|
|
341
|
-
self.releaseAbandonedXCTestChannelWork()
|
|
342
|
-
NSLog("AGENT_DEVICE_RUNNER_SYSTEM_MODAL_PROBE_DRAINED")
|
|
343
338
|
}
|
|
344
339
|
) {
|
|
345
340
|
probe(probeDeadline)
|
|
@@ -788,8 +783,6 @@ extension RunnerTests {
|
|
|
788
783
|
|
|
789
784
|
|
|
790
785
|
|
|
791
|
-
|
|
792
|
-
|
|
793
786
|
|
|
794
787
|
|
|
795
788
|
|
|
@@ -839,6 +832,7 @@ extension RunnerTests {
|
|
|
839
832
|
treeCaptureSliceBudgetOverride: TimeInterval? = nil
|
|
840
833
|
) throws -> SnapshotTraversalContext? {
|
|
841
834
|
let viewport = try runMainThreadWork(
|
|
835
|
+
"snapshot_viewport",
|
|
842
836
|
timeout: min(1.0, max(0.1, captureDeadline.timeIntervalSinceNow)),
|
|
843
837
|
timeoutError: snapshotMainThreadTimeoutError("preparing tree snapshot")
|
|
844
838
|
) {
|
|
@@ -860,25 +854,6 @@ extension RunnerTests {
|
|
|
860
854
|
|
|
861
855
|
static let xCTestSnapshotTimeoutCode = "IOS_TREE_CAPTURE_TIMEOUT"
|
|
862
856
|
|
|
863
|
-
func hasAbandonedTreeCapture() -> Bool {
|
|
864
|
-
treeCaptureLock.lock()
|
|
865
|
-
defer { treeCaptureLock.unlock() }
|
|
866
|
-
return abandonedTreeCaptureCount > 0
|
|
867
|
-
}
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
func retainAbandonedXCTestChannelWork() {
|
|
872
|
-
treeCaptureLock.lock()
|
|
873
|
-
abandonedTreeCaptureCount += 1
|
|
874
|
-
treeCaptureLock.unlock()
|
|
875
|
-
}
|
|
876
|
-
|
|
877
|
-
func releaseAbandonedXCTestChannelWork() {
|
|
878
|
-
treeCaptureLock.lock()
|
|
879
|
-
abandonedTreeCaptureCount -= 1
|
|
880
|
-
treeCaptureLock.unlock()
|
|
881
|
-
}
|
|
882
857
|
|
|
883
858
|
|
|
884
859
|
|
|
@@ -893,20 +868,9 @@ extension RunnerTests {
|
|
|
893
868
|
return try captureSnapshotRoot(element)
|
|
894
869
|
}
|
|
895
870
|
return try runMainThreadWork(
|
|
871
|
+
"tree_capture",
|
|
896
872
|
timeout: sliceSeconds,
|
|
897
|
-
timeoutError: treeCaptureTimeoutError(sliceSeconds: sliceSeconds)
|
|
898
|
-
onAbandoned: {
|
|
899
|
-
self.retainAbandonedXCTestChannelWork()
|
|
900
|
-
NSLog("AGENT_DEVICE_RUNNER_TREE_CAPTURE_SLICE_TIMEOUT slice=%.1f", sliceSeconds)
|
|
901
|
-
self.penalizeSnapshotXCTestChannel(
|
|
902
|
-
bundleId: self.currentBundleId,
|
|
903
|
-
reason: "tree_capture_slice_timeout"
|
|
904
|
-
)
|
|
905
|
-
},
|
|
906
|
-
onDrained: {
|
|
907
|
-
self.releaseAbandonedXCTestChannelWork()
|
|
908
|
-
NSLog("AGENT_DEVICE_RUNNER_TREE_CAPTURE_DRAINED")
|
|
909
|
-
}
|
|
873
|
+
timeoutError: treeCaptureTimeoutError(sliceSeconds: sliceSeconds)
|
|
910
874
|
) {
|
|
911
875
|
try self.captureSnapshotRoot(element)
|
|
912
876
|
}
|
|
@@ -248,8 +248,8 @@ extension RunnerTests {
|
|
|
248
248
|
)
|
|
249
249
|
}
|
|
250
250
|
|
|
251
|
-
func
|
|
252
|
-
kind.usesXCTestAccessibilityChannel &&
|
|
251
|
+
func shouldSkipSnapshotBackendForAbandonedMainThreadWork(_ kind: SnapshotBackendKind) -> Bool {
|
|
252
|
+
kind.usesXCTestAccessibilityChannel && hasAbandonedMainThreadWork()
|
|
253
253
|
}
|
|
254
254
|
|
|
255
255
|
|
|
@@ -316,11 +316,11 @@ extension RunnerTests {
|
|
|
316
316
|
}
|
|
317
317
|
|
|
318
318
|
|
|
319
|
-
if
|
|
319
|
+
if shouldSkipSnapshotBackendForAbandonedMainThreadWork(kind) {
|
|
320
320
|
NSLog("AGENT_DEVICE_RUNNER_SNAPSHOT_TIER_SKIPPED_XCTEST_OCCUPIED tier=%@", kind.rawValue)
|
|
321
321
|
if firstFailure == nil {
|
|
322
322
|
firstFailure = (
|
|
323
|
-
"the XCTest capture channel is occupied by
|
|
323
|
+
"the XCTest capture channel is occupied by abandoned main-thread work",
|
|
324
324
|
"budget"
|
|
325
325
|
)
|
|
326
326
|
}
|
|
@@ -431,6 +431,7 @@ extension RunnerTests {
|
|
|
431
431
|
return nil
|
|
432
432
|
}
|
|
433
433
|
return try self.runMainThreadWork(
|
|
434
|
+
"tree_processing",
|
|
434
435
|
timeout: min(self.treeCaptureSliceBudget, max(0.5, deadline.timeIntervalSinceNow)),
|
|
435
436
|
timeoutError: self.snapshotMainThreadTimeoutError("processing tree snapshot")
|
|
436
437
|
) {
|
|
@@ -440,6 +441,7 @@ extension RunnerTests {
|
|
|
440
441
|
}
|
|
441
442
|
case .querySweep:
|
|
442
443
|
return try self.runMainThreadWork(
|
|
444
|
+
"query_sweep",
|
|
443
445
|
timeout: min(Self.flatInteractiveFallbackBudget, max(0.1, deadline.timeIntervalSinceNow)),
|
|
444
446
|
timeoutError: self.snapshotMainThreadTimeoutError("running query-sweep snapshot")
|
|
445
447
|
) {
|
|
@@ -1169,42 +1171,6 @@ extension RunnerTests {
|
|
|
1169
1171
|
|
|
1170
1172
|
|
|
1171
1173
|
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
1174
|
|
|
1209
1175
|
|
|
1210
1176
|
|
package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Transport.swift
CHANGED
|
@@ -152,14 +152,7 @@ extension RunnerTests {
|
|
|
152
152
|
self.deliverCommandResult(
|
|
153
153
|
command: command,
|
|
154
154
|
result: (
|
|
155
|
-
self.jsonResponse(
|
|
156
|
-
status: 500,
|
|
157
|
-
response: self.errorResponse(
|
|
158
|
-
code: "COMMAND_FAILED",
|
|
159
|
-
message: error.localizedDescription,
|
|
160
|
-
hint: "Check the runner log for XCTest details, then retry after the app is foregrounded if this was a timeout or activation failure."
|
|
161
|
-
)
|
|
162
|
-
),
|
|
155
|
+
self.jsonResponse(status: 500, response: self.commandFailedResponse(from: error)),
|
|
163
156
|
false
|
|
164
157
|
),
|
|
165
158
|
completion: completion
|
|
@@ -274,7 +267,9 @@ extension RunnerTests {
|
|
|
274
267
|
|
|
275
268
|
let stamped =
|
|
276
269
|
response.ok
|
|
277
|
-
? response
|
|
270
|
+
? response
|
|
271
|
+
.stampingCurrentUptimeMs(ProcessInfo.processInfo.systemUptime * 1000)
|
|
272
|
+
.stampingCurrentMainThreadBusy(currentMainThreadBusyState().reportsMainThreadBusy)
|
|
278
273
|
: response
|
|
279
274
|
let encoder = JSONEncoder()
|
|
280
275
|
let body = (try? encoder.encode(stamped)).flatMap { String(data: $0, encoding: .utf8) } ?? "{}"
|
|
@@ -285,6 +280,32 @@ extension RunnerTests {
|
|
|
285
280
|
Response(ok: false, error: ErrorPayload(code: code, message: message, hint: hint))
|
|
286
281
|
}
|
|
287
282
|
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
func commandFailedResponse(from error: Error) -> Response {
|
|
288
|
+
let nsError = error as NSError
|
|
289
|
+
if nsError.domain == RunnerErrorDomain.general,
|
|
290
|
+
nsError.code == RunnerErrorCode.mainThreadExecutionTimedOut
|
|
291
|
+
{
|
|
292
|
+
return Response(
|
|
293
|
+
ok: false,
|
|
294
|
+
error: ErrorPayload(
|
|
295
|
+
code: RunnerWireErrorCode.mainThreadTimeout,
|
|
296
|
+
message: nsError.localizedDescription,
|
|
297
|
+
hint:
|
|
298
|
+
"The runner abandoned this command's main-thread work past its execution watchdog and it is still draining. Wait and retry, or use a screenshot and interact by coordinates."
|
|
299
|
+
)
|
|
300
|
+
)
|
|
301
|
+
}
|
|
302
|
+
return errorResponse(
|
|
303
|
+
code: "COMMAND_FAILED",
|
|
304
|
+
message: error.localizedDescription,
|
|
305
|
+
hint: "Check the runner log for XCTest details, then retry after the app is foregrounded if this was a timeout or activation failure."
|
|
306
|
+
)
|
|
307
|
+
}
|
|
308
|
+
|
|
288
309
|
private func httpResponse(status: Int, body: String) -> Data {
|
|
289
310
|
let headers = [
|
|
290
311
|
"HTTP/1.1 \(status) OK",
|
|
@@ -28,6 +28,13 @@ final class RunnerTests: XCTestCase {
|
|
|
28
28
|
static let objcException = 1
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
enum RunnerWireErrorCode {
|
|
35
|
+
static let mainThreadTimeout = "MAIN_THREAD_TIMEOUT"
|
|
36
|
+
}
|
|
37
|
+
|
|
31
38
|
static let springboardBundleId = "com.apple.springboard"
|
|
32
39
|
|
|
33
40
|
|
|
@@ -59,7 +66,7 @@ final class RunnerTests: XCTestCase {
|
|
|
59
66
|
let retryCooldown: TimeInterval = 0.2
|
|
60
67
|
let postSnapshotInteractionDelay: TimeInterval = 0.2
|
|
61
68
|
let firstInteractionAfterActivateDelay: TimeInterval = 0.25
|
|
62
|
-
let
|
|
69
|
+
let interactionIdleTimeoutDefault: TimeInterval = 1.0
|
|
63
70
|
let tvRemoteDoublePressDelayDefault: TimeInterval = 0.0
|
|
64
71
|
|
|
65
72
|
let xctestIdleKeepaliveInterval: TimeInterval = 60.0
|
|
@@ -81,6 +88,8 @@ final class RunnerTests: XCTestCase {
|
|
|
81
88
|
var inFlightCommandWaiters: [String: [((data: Data, shouldFinish: Bool)) -> Void]] = [:]
|
|
82
89
|
|
|
83
90
|
|
|
91
|
+
|
|
92
|
+
|
|
84
93
|
let mainThreadWorkLock = NSLock()
|
|
85
94
|
var abandonedMainThreadWorkCount = 0
|
|
86
95
|
var abandonedMainThreadWorkSince: Date?
|
|
@@ -115,10 +124,6 @@ final class RunnerTests: XCTestCase {
|
|
|
115
124
|
|
|
116
125
|
|
|
117
126
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
let treeCaptureLock = NSLock()
|
|
121
|
-
var abandonedTreeCaptureCount = 0
|
|
122
127
|
let treeCaptureSliceBudget: TimeInterval = 8
|
|
123
128
|
|
|
124
129
|
|
|
@@ -210,10 +215,20 @@ final class RunnerTests: XCTestCase {
|
|
|
210
215
|
|
|
211
216
|
|
|
212
217
|
|
|
218
|
+
static let axServerRejectionFetchWordings = [
|
|
219
|
+
"Failed to get matching snapshot",
|
|
220
|
+
"Failed to resolve query"
|
|
221
|
+
]
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
|
|
213
227
|
|
|
214
228
|
|
|
215
229
|
static func isSuppressedAxSnapshotIssueDescription(_ description: String) -> Bool {
|
|
216
|
-
description.contains("
|
|
230
|
+
guard description.contains("kAXError") else { return false }
|
|
231
|
+
return axServerRejectionFetchWordings.contains { description.contains($0) }
|
|
217
232
|
}
|
|
218
233
|
|
|
219
234
|
|
|
@@ -224,6 +239,7 @@ final class RunnerTests: XCTestCase {
|
|
|
224
239
|
|
|
225
240
|
|
|
226
241
|
|
|
242
|
+
|
|
227
243
|
override func record(_ issue: XCTIssue) {
|
|
228
244
|
if containTextInputProbeIssue(issue) { return }
|
|
229
245
|
let description = issue.compactDescription
|