@@ -11,6 +11,7 @@ import com.malinskiy.marathon.apple.bin.xcrun.simctl.service.ApplicationService
11
11
import com.malinskiy.marathon.apple.cmd.CommandExecutor
12
12
import com.malinskiy.marathon.apple.cmd.CommandResult
13
13
import com.malinskiy.marathon.apple.cmd.FileBridge
14
+ import com.malinskiy.marathon.apple.configuration.Transport
14
15
import com.malinskiy.marathon.apple.extensions.bundleConfiguration
15
16
import com.malinskiy.marathon.apple.ios.listener.DataContainerClearListener
16
17
import com.malinskiy.marathon.apple.listener.AppleTestRunListener
@@ -24,6 +25,7 @@ import com.malinskiy.marathon.apple.ios.listener.video.ScreenRecordingListener
24
25
import com.malinskiy.marathon.apple.model.Sdk
25
26
import com.malinskiy.marathon.apple.ios.model.Simulator
26
27
import com.malinskiy.marathon.apple.logparser.parser.DeviceFailureException
28
+ import com.malinskiy.marathon.apple.logparser.parser.DeviceFailureReason
27
29
import com.malinskiy.marathon.apple.logparser.parser.DiagnosticLogsPathFinder
28
30
import com.malinskiy.marathon.apple.logparser.parser.SessionResultsPathFinder
29
31
import com.malinskiy.marathon.apple.model.AppleTestBundle
@@ -45,6 +47,7 @@ import com.malinskiy.marathon.device.screenshot.Rotation
45
47
import com.malinskiy.marathon.device.toDeviceInfo
46
48
import com.malinskiy.marathon.exceptions.DeviceLostException
47
49
import com.malinskiy.marathon.exceptions.DeviceSetupException
50
+ import com.malinskiy.marathon.exceptions.IncompatibleDeviceException
48
51
import com.malinskiy.marathon.execution.TestBatchResults
49
52
import com.malinskiy.marathon.execution.listener.LineListener
50
53
import com.malinskiy.marathon.execution.listener.LogListener
@@ -76,11 +79,13 @@ import java.awt.image.BufferedImage
76
79
import java.io.File
77
80
import java.time.Duration
78
81
import java.util.concurrent.CopyOnWriteArrayList
82
+ import java.util.concurrent.RejectedExecutionException
79
83
import javax.imageio.ImageIO
80
84
import kotlin.coroutines.CoroutineContext
81
85
82
86
class AppleSimulatorDevice (
83
87
override val udid : String ,
88
+ override val transport : Transport ,
84
89
override var sdk : Sdk ,
85
90
override val binaryEnvironment : AppleBinaryEnvironment ,
86
91
private val testBundleIdentifier : AppleTestBundleIdentifier ,
@@ -134,53 +139,55 @@ class AppleSimulatorDevice(
134
139
* Called only once per device's lifetime
135
140
*/
136
141
override suspend fun setup () {
137
- val simctlDevices = binaryEnvironment.xcrun.simctl.device.listDevices()
138
- val simctlDevice = simctlDevices.find { it.udid == udid } ? : throw DeviceSetupException (" simulator $udid not found" )
139
- env = fetchEnvvars()
142
+ withContext(coroutineContext) {
143
+ val simctlDevices = binaryEnvironment.xcrun.simctl.device.listDevices()
144
+ val simctlDevice = simctlDevices.find { it.udid == udid } ? : throw DeviceSetupException (" simulator $udid not found" )
145
+ env = fetchEnvvars()
146
+
147
+ xcodeVersion = binaryEnvironment.xcrun.xcodebuild.getVersion()
148
+
149
+ home = env[" HOME" ]
150
+ ? : binaryEnvironment.xcrun.simctl.simulator.getenv(udid, " SIMULATOR_HOST_HOME" )
151
+ ? : " "
152
+ if (home.isBlank()) {
153
+ throw DeviceSetupException (" simulator $udid : invalid value $home for environment variable HOME" )
154
+ }
155
+ val logDirectory = simctlDevice.logPath ? : " $home /Library/Developer/CoreSimulator/Devices/$udid "
156
+ logFile = " $logDirectory /system.log"
157
+ rootPath = binaryEnvironment.xcrun.simctl.simulator.getenv(udid, " HOME" )?.let {
158
+ if (it.endsWith(" /data" )) {
159
+ it.substringBefore(" /data" )
160
+ } else {
161
+ it
162
+ }
163
+ } ? : " $home /Library/Developer/CoreSimulator/Devices/$udid "
140
164
141
- xcodeVersion = binaryEnvironment.xcrun.xcodebuild.getVersion()
165
+ devicePlistPath = " $rootPath /device.plist"
166
+ fetchDeviceDescriptor()
142
167
143
- home = env[" HOME" ]
144
- ? : binaryEnvironment.xcrun.simctl.simulator.getenv(udid, " SIMULATOR_HOST_HOME" )
145
- ? : " "
146
- if (home.isBlank()) {
147
- throw DeviceSetupException (" simulator $udid : invalid value $home for environment variable HOME" )
148
- }
149
- val logDirectory = simctlDevice.logPath ? : " $home /Library/Developer/CoreSimulator/Devices/$udid "
150
- logFile = " $logDirectory /system.log"
151
- rootPath = binaryEnvironment.xcrun.simctl.simulator.getenv(udid, " HOME" )?.let {
152
- if (it.endsWith(" /data" )) {
153
- it.substringBefore(" /data" )
154
- } else {
155
- it
156
- }
157
- } ? : " $home /Library/Developer/CoreSimulator/Devices/$udid "
158
-
159
- devicePlistPath = " $rootPath /device.plist"
160
- fetchDeviceDescriptor()
161
-
162
- deviceType = simctlDevice.deviceTypeIdentifier
163
- ? : getDeviceProperty<String >(" deviceType" )?.trim()
164
- ? : throw DeviceSetupException (" simulator $udid : unable to detect deviceType" )
165
-
166
- model = getSimpleEnvProperty(" SIMULATOR_MODEL_IDENTIFIER" , deviceType)
167
- manufacturer = " Apple"
168
- runtimeBuildVersion = getSimpleEnvProperty(" SIMULATOR_RUNTIME_BUILD_VERSION" )
169
- runtimeVersion = getSimpleEnvProperty(" SIMULATOR_RUNTIME_VERSION" )
170
- version = getSimpleEnvProperty(" SIMULATOR_VERSION_INFO" )
171
- abi = executeWorkerCommand(listOf (" uname" , " -m" ))?.let {
172
- if (it.successful) {
173
- it.combinedStdout.trim()
174
- } else {
175
- null
176
- }
177
- } ? : " Unknown"
168
+ deviceType = simctlDevice.deviceTypeIdentifier
169
+ ? : getDeviceProperty<String >(" deviceType" )?.trim()
170
+ ? : throw DeviceSetupException (" simulator $udid : unable to detect deviceType" )
171
+
172
+ model = getSimpleEnvProperty(" SIMULATOR_MODEL_IDENTIFIER" , deviceType)
173
+ manufacturer = " Apple"
174
+ runtimeBuildVersion = getSimpleEnvProperty(" SIMULATOR_RUNTIME_BUILD_VERSION" )
175
+ runtimeVersion = getSimpleEnvProperty(" SIMULATOR_RUNTIME_VERSION" )
176
+ version = getSimpleEnvProperty(" SIMULATOR_VERSION_INFO" )
177
+ abi = executeWorkerCommand(listOf (" uname" , " -m" ))?.let {
178
+ if (it.successful) {
179
+ it.combinedStdout.trim()
180
+ } else {
181
+ null
182
+ }
183
+ } ? : " Unknown"
178
184
179
- deviceFeatures = detectFeatures()
185
+ deviceFeatures = detectFeatures()
186
+ }
180
187
}
181
188
182
189
override suspend fun prepare (configuration : Configuration ) {
183
- async(CoroutineName (" prepare $serialNumber " )) {
190
+ async(coroutineContext + CoroutineName (" prepare $serialNumber " )) {
184
191
supervisorScope {
185
192
track.trackDevicePreparing(this @AppleSimulatorDevice) {
186
193
remoteFileManager.removeRemoteDirectory()
@@ -240,7 +247,7 @@ class AppleSimulatorDevice(
240
247
deferred : CompletableDeferred <TestBatchResults >
241
248
) {
242
249
try {
243
- async(CoroutineName (" execute $serialNumber " )) {
250
+ async(coroutineContext + CoroutineName (" execute $serialNumber " )) {
244
251
supervisorScope {
245
252
var executionLineListeners = setOf<LineListener >()
246
253
try {
@@ -266,7 +273,13 @@ class AppleSimulatorDevice(
266
273
} catch (e: IllegalStateException ) {
267
274
throw DeviceLostException (e)
268
275
} catch (e: DeviceFailureException ) {
269
- throw DeviceLostException (e)
276
+ when (e.reason) {
277
+ DeviceFailureReason .InvalidSimulatorIdentifier , DeviceFailureReason .IncompatibleDevice -> throw IncompatibleDeviceException (
278
+ e
279
+ )
280
+
281
+ else -> throw DeviceLostException (e)
282
+ }
270
283
}
271
284
}
272
285
@@ -348,40 +361,41 @@ class AppleSimulatorDevice(
348
361
349
362
override suspend fun executeTestRequest (request : TestRequest ): ReceiveChannel <List <TestEvent >> {
350
363
return produce {
351
- binaryEnvironment.xcrun.xcodebuild.testWithoutBuilding(udid, sdk, request, vendorConfiguration.xcodebuildTestArgs).use { session ->
352
- withContext(Dispatchers .IO ) {
353
- val deferredStdout = supervisorScope {
354
- async {
355
- val testEventProducer =
356
- com.malinskiy.marathon.apple.logparser.XctestEventProducer (request.testTargetName ? : " " , timer)
357
- for (line in session.stdout) {
358
- testEventProducer.process(line)?.let {
359
- send(it)
364
+ binaryEnvironment.xcrun.xcodebuild.testWithoutBuilding(udid, sdk, request, vendorConfiguration.xcodebuildTestArgs)
365
+ .use { session ->
366
+ withContext(Dispatchers .IO ) {
367
+ val deferredStdout = supervisorScope {
368
+ async {
369
+ val testEventProducer =
370
+ com.malinskiy.marathon.apple.logparser.XctestEventProducer (request.testTargetName ? : " " , timer)
371
+ for (line in session.stdout) {
372
+ testEventProducer.process(line)?.let {
373
+ send(it)
374
+ }
375
+ lineListeners.forEach { it.onLine(line) }
360
376
}
361
- lineListeners.forEach { it.onLine(line) }
362
377
}
363
378
}
364
- }
365
379
366
- val deferredStderr = supervisorScope {
367
- async {
368
- for (line in session.stderr) {
369
- if (line.trim().isNotBlank()) {
370
- logger.error { " simulator $udid : stderr=$line " }
380
+ val deferredStderr = supervisorScope {
381
+ async {
382
+ for (line in session.stderr) {
383
+ if (line.trim().isNotBlank()) {
384
+ logger.error { " simulator $udid : stderr=$line " }
385
+ }
371
386
}
372
387
}
373
388
}
374
- }
375
389
376
- deferredStderr.await()
377
- deferredStdout.await()
378
- val exitCode = session.exitCode.await()
379
- // 70 = no devices
380
- // 65 = ** TEST EXECUTE FAILED **: crash
381
- logger.debug { " Finished test batch execution with exit status $exitCode " }
382
- close()
390
+ deferredStderr.await()
391
+ deferredStdout.await()
392
+ val exitCode = session.exitCode.await()
393
+ // 70 = no devices
394
+ // 65 = ** TEST EXECUTE FAILED **: crash
395
+ logger.debug { " Finished test batch execution with exit status $exitCode " }
396
+ close()
397
+ }
383
398
}
384
- }
385
399
}
386
400
}
387
401
0 commit comments