Skip to content

Commit

Permalink
Merge pull request #27 from Workday/update_aapt2
Browse files Browse the repository at this point in the history
Update torque to use aapt2
MarcusBermelWD authored Jun 23, 2022
2 parents c94b812 + 9042595 commit 3e59f25
Showing 6 changed files with 106 additions and 36 deletions.
12 changes: 12 additions & 0 deletions torque-core/build.gradle
Original file line number Diff line number Diff line change
@@ -41,3 +41,15 @@ junitPlatform {
}
}
}

jar {
manifest {
attributes 'Implementation-Title': POM_NAME,
'Built-Date': new Date(),
'Built-JDK': System.getProperty('java.version'),
'Built-Gradle': gradle.gradleVersion
}
from {
configurations.runtimeClasspath.findAll { it.name.endsWith('jar') }.collect { zipTree(it) }
}
}
95 changes: 68 additions & 27 deletions torque-core/src/main/kotlin/com/workday/torque/ApkTestParser.kt
Original file line number Diff line number Diff line change
@@ -1,32 +1,56 @@
package com.workday.torque

import com.gojuno.commander.android.aapt
import com.gojuno.commander.android.androidHome
import com.gojuno.commander.os.Notification
import com.gojuno.commander.os.process
import com.linkedin.dex.parser.DexParser
import com.linkedin.dex.parser.TestMethod
import java.io.File
import java.util.*

class ApkTestParser {
fun getValidatedTestPackage(testApkPath: String): ApkPackage.Valid {
return parseTestPackage(testApkPath).validateApkPackage()
}

private val buildTools: String? by lazy {
File(androidHome, "build-tools")
.listFiles()
.sortedArray()
.lastOrNull()
?.absolutePath
}
val aapt: String by lazy { buildTools?.let { "$buildTools/aapt2" } ?: "" }

private fun parseTestPackage(testApkPath: String): ApkPackage {
val commandAndArgs = listOf(
aapt, "dump", "badging", testApkPath
)
return process(
commandAndArgs = listOf(
aapt, "dump", "badging", testApkPath
),
unbufferedOutput = true
commandAndArgs = commandAndArgs,
unbufferedOutput = true,
)
.ofType(Notification.Exit::class.java)
.map { (output) ->
output
.readText()
.split(System.lineSeparator())
// output format `package: name='$testPackage' versionCode='' versionName='' platformBuildVersionName='xxx'`
.firstOrNull { it.contains("package") }
?.split(" ")
?.firstOrNull { it.startsWith("name=") }
val unTouched = output
.readText()
val packageText = unTouched
.split(System.lineSeparator())
.firstOrNull { it.contains("package") }

if (packageText.isNullOrEmpty()) {
return@map ApkPackage.ParseError("'package' token was null")
}
val splitPackageText = packageText
?.split(" ")
val name = splitPackageText
?.firstOrNull { it.startsWith("name=") }

if (name.isNullOrEmpty()) {
return@map ApkPackage.ParseError("'name' token was null")
}

name
?.split("'")
?.getOrNull(1)
?.let(ApkPackage::Valid)
@@ -37,30 +61,48 @@ class ApkTestParser {
.value()
}

private fun makeOutputFile(): File {
return Random()
.nextInt()
.let { System.nanoTime() + it }
.let { name ->
File("$name.output").apply {
createNewFile()
deleteOnExit()
}
}
}

fun getValidatedTargetPackage(testApkPath: String): ApkPackage.Valid {
return parseTargetPackage(testApkPath).validateApkPackage()
}

private fun parseTargetPackage(testApkPath: String): ApkPackage {
return process(
commandAndArgs = listOf(
aapt, "dump", "xmltree", testApkPath, "AndroidManifest.xml"
aapt, "dump", "xmltree", testApkPath, "--file", "AndroidManifest.xml"
),
unbufferedOutput = true
unbufferedOutput = true,
keepOutputOnExit = true,
)
.ofType(Notification.Exit::class.java)
.map { (output) ->
output
.readText()
.split(System.lineSeparator())
// output format `A: android:targetPackage(0x01010021)="$targetPackage" (Raw: "$targetPackag")`
.firstOrNull { it.contains("android:targetPackage") }
?.split(" ")
?.firstOrNull { it.startsWith("android:targetPackage") }
?.substringAfter("=")
?.trim('"')
val initialOutput = output
.readText()
.split(System.lineSeparator())
.firstOrNull { it.contains("android:targetPackage") }

val secondaryOutput = initialOutput
?.split(" ")
val finalOutput = secondaryOutput
?.firstOrNull {
it.contains("android:targetPackage")
}
?.substringAfter("=")
?.trim('"')
finalOutput
?.let(ApkPackage::Valid)
?: ApkPackage.ParseError("Cannot parse target package from `aapt dump xmltree \$TEST_APK AndroidManifest.xml` output.")
?: ApkPackage.ParseError("Cannot parse target package from `aapt dump xmltree ${testApkPath} AndroidManifest.xml` output.")
}
.toSingle()
.toBlocking()
@@ -85,7 +127,7 @@ class ApkTestParser {
private fun parseTestRunner(testApkPath: String): TestRunner =
process(
commandAndArgs = listOf(
aapt, "dump", "xmltree", testApkPath, "AndroidManifest.xml"
aapt, "dump", "xmltree", testApkPath, "--file", "AndroidManifest.xml"
),
unbufferedOutput = true
)
@@ -96,11 +138,10 @@ class ApkTestParser {
.split(System.lineSeparator())
.dropWhile { !it.contains("instrumentation") }
.firstOrNull { it.contains("android:name") }
// output format : `A: android:name(0x01010003)="$testRunner" (Raw: "$testRunner")`
?.split("\"")
?.getOrNull(1)
?.let(TestRunner::Valid)
?: TestRunner.ParseError("Cannot parse test runner from `aapt dump xmltree \$TEST_APK AndroidManifest.xml` output.")
?: TestRunner.ParseError("Cannot parse test runner from `aapt dump xmltree ${testApkPath} AndroidManifest.xml` output.")
}
.toSingle()
.toBlocking()
18 changes: 10 additions & 8 deletions torque-core/src/main/kotlin/com/workday/torque/Installer.kt
Original file line number Diff line number Diff line change
@@ -97,10 +97,11 @@ class Installer(private val adbDevice: AdbDevice, private val processRunner: Pro
.fromCallable { System.currentTimeMillis() }
.flatMap { startTimeMillis -> adbInstallApk(pathToApk, installTimeout).map { it to startTimeMillis } }
.map { (exitNotification, startTimeMillis) ->
val success = exitNotification
.preprocessOutput()
.filter { it.isNotEmpty() }
.firstOrNull { it.equals("Success", ignoreCase = true) } != null
val preProcessed = exitNotification
.preprocessOutput()
.filter { it.isNotEmpty() }
.firstOrNull { it.equals("Success", ignoreCase = true) }
val success = preProcessed != null

val duration = System.currentTimeMillis() - startTimeMillis

@@ -124,15 +125,16 @@ class Installer(private val adbDevice: AdbDevice, private val processRunner: Pro
return processRunner.runAdb(
commandAndArgs = listOf("-s", adbDevice.id, "install", "-r", "-g", pathToApk),
timeout = installTimeout,
unbufferedOutput = true)
unbufferedOutput = true,
keepOutputOnExit = true)
.ofType(Notification.Exit::class.java)
}

private fun Notification.Exit.preprocessOutput(): List<String> {
return output
.readText()
.split(System.lineSeparator())
.map { it.trim() }
.readText()
.split(System.lineSeparator())
.map { it.trim() }
}
}

Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package com.workday.torque

import com.gojuno.commander.os.log
import com.linkedin.dex.parser.TestAnnotation
import com.linkedin.dex.parser.TestMethod
import com.workday.torque.pooling.ModuleInfo
import com.workday.torque.pooling.TestModule
import com.workday.torque.pooling.TestModuleInfo
import java.io.File
import java.util.concurrent.TimeUnit

class ModuleTestParser(private val args: Args, private val apkTestParser: ApkTestParser = ApkTestParser()) {
fun parseTestsFromModuleApks(): List<TestModule> {
@@ -14,8 +17,18 @@ class ModuleTestParser(private val args: Args, private val apkTestParser: ApkTes
.filterAnnotations(includedAnnotations = args.includedAnnotations, excludedAnnotations = args.excludedAnnotations)
.filterClassRegexes(args.testClassRegexes)
println("Filtered tests count: ${testMethods.size}")
val testApkFile = File(testApkPath)

val time = System.currentTimeMillis()
val expired = time + TimeUnit.SECONDS.toMillis(5)
while((!testApkFile.exists() || testApkFile.length() < 1024) && System.currentTimeMillis() < expired) {
Thread.sleep(1000)
}
val moduleInfo = createModuleInfo(testApkPath)
add(TestModule(moduleInfo, testMethods))
val isMyModule = moduleInfo.moduleInfo.pathToApk.contains(other = "-DEBUG.apk", ignoreCase = false)
if (!isMyModule) {
add(TestModule(moduleInfo, testMethods))
}
}
}
}
1 change: 1 addition & 0 deletions torque-gradle-plugin/build.gradle
Original file line number Diff line number Diff line change
@@ -12,6 +12,7 @@ dependencies {
}

jar {
entryCompression = ZipEntryCompression.STORED
manifest {
attributes 'Implementation-Title': POM_NAME,
'Built-Date': new Date(),
1 change: 1 addition & 0 deletions torque-runner/build.gradle
Original file line number Diff line number Diff line change
@@ -10,6 +10,7 @@ dependencies {


jar {
entryCompression = ZipEntryCompression.STORED
// Build jar with dependencies.
from(configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }) {
exclude 'META-INF/*.SF'

0 comments on commit 3e59f25

Please sign in to comment.