diff --git a/buildSrc/src/main/kotlin/Versions.kt b/buildSrc/src/main/kotlin/Versions.kt index 1df06ca6f..75d46dfe8 100644 --- a/buildSrc/src/main/kotlin/Versions.kt +++ b/buildSrc/src/main/kotlin/Versions.kt @@ -4,7 +4,7 @@ object Versions { val coroutines = "1.7.3" val ktor = "2.0.3" - val ddmlib = "31.0.2" + val ddmlib = "31.4.2" val dexTestParser = "2.3.4" val kotlinLogging = "1.4.9" val slf4jAPI = "1.0.0" diff --git a/marathon-gradle-plugin/src/main/kotlin/com/malinskiy/marathon/ConfigurationFactory.kt b/marathon-gradle-plugin/src/main/kotlin/com/malinskiy/marathon/ConfigurationFactory.kt index 79b4990f6..24fc71351 100644 --- a/marathon-gradle-plugin/src/main/kotlin/com/malinskiy/marathon/ConfigurationFactory.kt +++ b/marathon-gradle-plugin/src/main/kotlin/com/malinskiy/marathon/ConfigurationFactory.kt @@ -96,6 +96,7 @@ private fun createAndroidConfiguration( } } ?: SerialStrategy.AUTOMATIC + val cleanupDeviceScript = extension.cleanupDeviceScript return AndroidConfiguration( sdkDirectory, @@ -109,6 +110,7 @@ private fun createAndroidConfiguration( adbInitTimeout, installOptions, preferableRecorderType, - serialStrategy + serialStrategy, + cleanupDeviceScript ) } diff --git a/marathon-gradle-plugin/src/main/kotlin/com/malinskiy/marathon/MarathonExtension.kt b/marathon-gradle-plugin/src/main/kotlin/com/malinskiy/marathon/MarathonExtension.kt index 5163dc0dd..59732f5cc 100644 --- a/marathon-gradle-plugin/src/main/kotlin/com/malinskiy/marathon/MarathonExtension.kt +++ b/marathon-gradle-plugin/src/main/kotlin/com/malinskiy/marathon/MarathonExtension.kt @@ -55,6 +55,7 @@ open class MarathonExtension { //Android specific for now var autoGrantPermission: Boolean? = null var instrumentationArgs: MutableMap = mutableMapOf() + var cleanupDeviceScript: String? = null //Kotlin way fun cache(block: CachePluginConfiguration.() -> Unit) { diff --git a/vendor/vendor-android/base/src/main/kotlin/com/malinskiy/marathon/android/AndroidConfiguration.kt b/vendor/vendor-android/base/src/main/kotlin/com/malinskiy/marathon/android/AndroidConfiguration.kt index 8d540dd99..395a07d0b 100644 --- a/vendor/vendor-android/base/src/main/kotlin/com/malinskiy/marathon/android/AndroidConfiguration.kt +++ b/vendor/vendor-android/base/src/main/kotlin/com/malinskiy/marathon/android/AndroidConfiguration.kt @@ -33,7 +33,8 @@ data class AndroidConfiguration( val adbInitTimeoutMillis: Int = defaultInitTimeoutMillis, val installOptions: String = DEFAULT_INSTALL_OPTIONS, val preferableRecorderType: DeviceFeature? = null, - val serialStrategy: SerialStrategy = SerialStrategy.AUTOMATIC + val serialStrategy: SerialStrategy = SerialStrategy.AUTOMATIC, + val cleanupDeviceScript: String? = null ) : VendorConfiguration, KoinComponent { private val koinModules = listOf(androidModule) + implementationModules diff --git a/vendor/vendor-android/base/src/main/kotlin/com/malinskiy/marathon/android/di/Modules.kt b/vendor/vendor-android/base/src/main/kotlin/com/malinskiy/marathon/android/di/Modules.kt index 9f09593cf..f947b7641 100644 --- a/vendor/vendor-android/base/src/main/kotlin/com/malinskiy/marathon/android/di/Modules.kt +++ b/vendor/vendor-android/base/src/main/kotlin/com/malinskiy/marathon/android/di/Modules.kt @@ -3,7 +3,6 @@ package com.malinskiy.marathon.android.di import com.malinskiy.marathon.android.AndroidComponentCacheKeyProvider import com.malinskiy.marathon.android.AndroidComponentInfoExtractor import com.malinskiy.marathon.android.AndroidTestParser -import com.malinskiy.marathon.android.ApkFileHasher import com.malinskiy.marathon.android.executor.logcat.LogcatCollector import com.malinskiy.marathon.android.executor.logcat.LogcatListener import com.malinskiy.marathon.android.executor.logcat.parse.LogcatEventsAdapter @@ -12,13 +11,14 @@ import com.malinskiy.marathon.cache.test.key.ComponentCacheKeyProvider import com.malinskiy.marathon.execution.ComponentInfoExtractor import com.malinskiy.marathon.execution.TestParser import com.malinskiy.marathon.io.CachedFileHasher +import com.malinskiy.marathon.io.Md5FileHasher import com.malinskiy.marathon.report.logs.LogsProvider import org.koin.dsl.module val androidModule = module { single { AndroidTestParser() } single { AndroidComponentInfoExtractor() } - single { AndroidComponentCacheKeyProvider(CachedFileHasher(ApkFileHasher())) } + single { AndroidComponentCacheKeyProvider(CachedFileHasher(Md5FileHasher())) } single { LogcatCollector() } single { get() } single { get() } diff --git a/vendor/vendor-android/base/src/main/kotlin/com/malinskiy/marathon/android/executor/ApkFileHasher.kt b/vendor/vendor-android/base/src/main/kotlin/com/malinskiy/marathon/android/executor/ApkFileHasher.kt deleted file mode 100644 index 8d00d750b..000000000 --- a/vendor/vendor-android/base/src/main/kotlin/com/malinskiy/marathon/android/executor/ApkFileHasher.kt +++ /dev/null @@ -1,28 +0,0 @@ -package com.malinskiy.marathon.android - -import com.android.apksig.ApkVerifier -import com.malinskiy.marathon.io.FileHasher -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext -import java.io.File -import java.security.MessageDigest -import java.util.HexFormat - -/** - * Extracts digest of APK contents from signature file - */ -class ApkFileHasher : FileHasher { - - val sha256digest = MessageDigest.getInstance("SHA-256") - - override suspend fun getHash(file: File): String = withContext(Dispatchers.IO) { - val result = ApkVerifier.Builder(file).build().verify() - if (result.signerCertificates.isNotEmpty()) { - val certificate = result.signerCertificates.first() - // https://cs.android.com/android/platform/superproject/main/+/main:tools/apksig/src/apksigner/java/com/android/apksigner/ApkSignerTool.java;l=1151;drc=d5137445c0d4067406cb3e38aade5507ff2fcd16 - HexFormat.of().formatHex(sha256digest.digest(certificate.encoded)) - } else { - throw IllegalArgumentException("Certificate not found") - } - } -} diff --git a/vendor/vendor-android/ddmlib/src/main/kotlin/com/malinskiy/marathon/android/AndroidAppInstaller.kt b/vendor/vendor-android/ddmlib/src/main/kotlin/com/malinskiy/marathon/android/AndroidAppInstaller.kt index a90f1606b..4b3425c90 100644 --- a/vendor/vendor-android/ddmlib/src/main/kotlin/com/malinskiy/marathon/android/AndroidAppInstaller.kt +++ b/vendor/vendor-android/ddmlib/src/main/kotlin/com/malinskiy/marathon/android/AndroidAppInstaller.kt @@ -64,6 +64,13 @@ class AndroidAppInstaller( } } catch (e: InstallException) { logger.error(e) { "Error while installing $appPackage, ${appApk.absolutePath} on ${device.serialNumber}" } + if (e.stackTrace.toString().contains("not enough space")) { + logger.error { "Not enough space" } + androidConfiguration.cleanupDeviceScript?.let { + logger.info { "Launch shell script `$it`" } + device.safeExecuteShellCommand(it).let { logger.info { it } } + } + } throw RuntimeException("Error while installing $appPackage on ${device.serialNumber}", e) } } diff --git a/vendor/vendor-android/ddmlib/src/main/kotlin/com/malinskiy/marathon/android/ddmlib/AndroidDeviceTestRunner.kt b/vendor/vendor-android/ddmlib/src/main/kotlin/com/malinskiy/marathon/android/ddmlib/AndroidDeviceTestRunner.kt index 72dc26c9d..b6840b06b 100644 --- a/vendor/vendor-android/ddmlib/src/main/kotlin/com/malinskiy/marathon/android/ddmlib/AndroidDeviceTestRunner.kt +++ b/vendor/vendor-android/ddmlib/src/main/kotlin/com/malinskiy/marathon/android/ddmlib/AndroidDeviceTestRunner.kt @@ -5,6 +5,7 @@ import com.android.ddmlib.ShellCommandUnresponsiveException import com.android.ddmlib.TimeoutException import com.android.ddmlib.testrunner.ITestRunListener import com.android.ddmlib.testrunner.RemoteAndroidTestRunner +import com.android.ddmlib.testrunner.RemoteAndroidTestRunner.StatusReporterMode import com.android.ddmlib.testrunner.TestIdentifier import com.malinskiy.marathon.android.AndroidComponentInfo import com.malinskiy.marathon.android.AndroidConfiguration @@ -104,7 +105,12 @@ class AndroidDeviceTestRunner(private val device: DdmlibAndroidDevice) { testBatch: TestBatch ): RemoteAndroidTestRunner { - val runner = RemoteAndroidTestRunner(info.instrumentationPackage, info.testRunnerClass, device.ddmsDevice) + val runner = RemoteAndroidTestRunner( + info.instrumentationPackage, + info.testRunnerClass, + device.ddmsDevice, + StatusReporterMode.PROTO_STD + ) val tests = testBatch.tests.map { val pkg = when {