Skip to content

Commit

Permalink
feat(android): support boot timeout
Browse files Browse the repository at this point in the history
+ fix android device borrowing when devices are not ready
+ deviceInitializationTimeoutMillis should work all retries for remote parsing, not individual
  • Loading branch information
Malinskiy committed Sep 5, 2023
1 parent 1ebbea1 commit b42cbb2
Show file tree
Hide file tree
Showing 4 changed files with 19 additions and 32 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ data class TimeoutConfiguration(
var screencapturer: Duration = Duration.ofMillis(300),
var socketIdleTimeout: Duration = Duration.ofSeconds(30),
var portForward: Duration = shell,
var boot: Duration = Duration.ofSeconds(30),
)
8 changes: 4 additions & 4 deletions core/src/main/kotlin/com/malinskiy/marathon/Marathon.kt
Original file line number Diff line number Diff line change
Expand Up @@ -112,12 +112,12 @@ class Marathon(
parsedAllTests = when (testParser) {
is LocalTestParser -> testParser.extract()
is RemoteTestParser<*> -> {
withRetry(3, 0) {
withTimeoutOrNull(configuration.deviceInitializationTimeoutMillis) {
withTimeoutOrNull(configuration.deviceInitializationTimeoutMillis) {
withRetry(3, 0) {
val borrowedDevice = deviceProvider.borrow()
testParser.extract(borrowedDevice)
} ?: throw NoDevicesException("Timed out waiting for a temporary device for remote test parsing")
}
}
} ?: throw NoDevicesException("Timed out waiting for a temporary device for remote test parsing")
}

else -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ import com.malinskiy.marathon.time.Timer
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import java.util.UUID
import kotlin.system.measureTimeMillis

Expand Down Expand Up @@ -79,11 +78,12 @@ abstract class BaseAndroidDevice(
get() = initialRotation

override suspend fun setup() {
booted = waitForBoot()
if(!booted) {
throw DeviceSetupException("Unable to configure device $serialNumber: not booted")
}

booted = false
withTimeoutOrNull(androidConfiguration.timeoutConfiguration.boot) {
waitForBoot()
booted = true
} ?: throw DeviceSetupException("Unable to configure device $serialNumber: not booted")

abi = getProperty("ro.product.cpu.abi") ?: abi

val sdk = getProperty("ro.build.version.sdk")
Expand Down Expand Up @@ -215,28 +215,14 @@ abstract class BaseAndroidDevice(
return safeExecuteShellCommand("ls $path")?.exitCode == 0
}

private suspend fun waitForBoot(): Boolean {
var booted = false

for (i in 1..30) {
if (getProperty("sys.boot_completed", false) != null) {
logger.debug { "Device $serialNumber booted!" }
booted = true
break
} else {
delay(1000)
logger.debug { "Device $serialNumber is still booting..." }
}

if (Thread.interrupted() || !isActive) {
booted = true
break
}
private suspend fun waitForBoot() {
while (getProperty("sys.boot_completed", false) == null) {
logger.debug { "Device $serialNumber is still booting..." }
delay(1000)
}

return booted
logger.debug { "Device $serialNumber booted!" }
}

fun isLocalEmulator() = adbSerial.startsWith("emulator-")

protected suspend fun AndroidDevice.isEmulator(): Boolean = when {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,10 +179,10 @@ class AdamDeviceProvider(
}

override suspend fun borrow(): AdamAndroidDevice {
var availableDevices = devices.filter { it.value.setupJob.isCompleted }
var availableDevices = devices.filter { it.value.setupJob.isCompleted && !it.value.setupJob.isCancelled }
while(availableDevices.isEmpty()) {
delay(200)
availableDevices = devices.filter { it.value.setupJob.isCompleted }
availableDevices = devices.filter { it.value.setupJob.isCompleted && !it.value.setupJob.isCancelled }
}
return availableDevices.values.random().device
}
Expand Down

0 comments on commit b42cbb2

Please sign in to comment.