Skip to content

Commit

Permalink
Add base domain integration
Browse files Browse the repository at this point in the history
  • Loading branch information
jan-goral committed Apr 30, 2021
1 parent f2cb52b commit 72c2dcf
Show file tree
Hide file tree
Showing 7 changed files with 200 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,7 @@ class CorelliumApi(
val authorize: Authorization.Request,
val invokeAndroidDevices: AndroidInstance.Invoke,
val installAndroidApps: AndroidApps.Install,
val executeTest: AndroidTestPlan.Execute
val executeTest: AndroidTestPlan.Execute,
val parseTestCases: TestApk.ParseTestCases,
val parsePackageName: TestApk.ParsePackageName,
)
23 changes: 22 additions & 1 deletion corellium/api/src/main/kotlin/flank/corellium/api/TestApk.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,38 @@ package flank.corellium.api
/**
* Structured representation of the parsed test apk file.
* @property packageName Parsed apk package name.
* @property testCases Full list of test methods from parsed apk.
*/
data class TestApk(
val packageName: String,
val testCases: List<String>
) {


interface Parse : (LocalPath) -> TestApk

/**
* @return The full list of test methods from parsed apk.
*/
interface ParseTestCases: (LocalPath) -> TestCases

/**
* @return The package name for given apk.
*/
interface ParsePackageName: (LocalPath) -> PackageName
}

/**
* Local path to the test apk file.
*/
private typealias LocalPath = String

/**
* The full package name for example: "example.full.package.name"
*/
private typealias PackageName = String

/**
* List of test method names, where test method name is matching format: "package.name.ClassName#testCaseName"
*/
private typealias TestCases = List<String>
31 changes: 31 additions & 0 deletions corellium/domain/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
kotlin(Plugins.Kotlin.PLUGIN_JVM)
kotlin(Plugins.Kotlin.PLUGIN_SERIALIZATION) version Versions.KOTLIN
}

repositories {
jcenter()
mavenCentral()
maven(url = "https://kotlin.bintray.com/kotlinx")
}

tasks.withType<KotlinCompile> { kotlinOptions.jvmTarget = "1.8" }

dependencies {
implementation(project(":corellium:api"))
implementation(project(":corellium:adapter"))
implementation(project(":corellium:shard"))
implementation(project(":corellium:log"))

implementation(Dependencies.KOTLIN_COROUTINES_CORE)

testImplementation(Dependencies.JUNIT)
}

tasks.test {
maxHeapSize = "3072m"
minHeapSize = "512m"
dependsOn(":resolveArtifacts")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
package flank.corellium.domain

import flank.corellium.api.AndroidApps
import flank.corellium.api.AndroidInstance
import flank.corellium.api.AndroidTestPlan
import flank.corellium.api.Authorization
import flank.corellium.api.CorelliumApi
import flank.corellium.api.TestApk
import flank.corellium.api.invoke
import flank.corellium.shard.Shard
import flank.corellium.shard.calculateShards
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.runBlocking

interface RunTestAndroidCorellium {
val api: CorelliumApi
val config: Config

data class Config(
val credentials: Authorization.Credentials,
val apks: List<Apk.App>,
val maxShardsCount: Int,
)

sealed class Apk {
abstract val path: String

data class App(
override val path: String,
val tests: List<Test>,
) : Apk()

data class Test(
override val path: String
) : Apk()
}
}

fun RunTestAndroidCorellium.invoke(): Unit = runBlocking {

println("* Authorizing")
api.authorize(config.credentials)

println("* Calculating shards")
val shards: List<List<Shard.App>> = config.apks
.prepareDataForSharding(api.parseTestCases)
.calculateShards(config.maxShardsCount)

println("* Invoking devices")
val associatedShards: AssociatedShards = api
.invokeAndroidDevices(AndroidInstance.Config(shards.size))
.associateShardsToInstances(shards)

println("* Installing apks")
val apps: List<AndroidApps> = associatedShards.prepareApkToInstall()
api.installAndroidApps(apps)

// If tests will be executed too fast just after the
// app installed, the instrumentation will fail
delay(10_000)

println("* Executing tests")
val testPlan = associatedShards.prepareTestPlan(api.parsePackageName)

api.executeTest(testPlan).collect { line ->
print(line)
}
println()
println("* Finish")
}

private fun List<RunTestAndroidCorellium.Apk.App>.prepareDataForSharding(
parseTestCases: TestApk.ParseTestCases
): List<Shard.App> =
map { app ->
Shard.App(
name = app.path,
tests = app.tests.map { test ->
Shard.Test(
name = test.path,
cases = parseTestCases(test.path).map(Shard.Test::Case)
)
}
)
}

private fun List<String>.associateShardsToInstances(
shards: List<List<Shard.App>>,
): AssociatedShards {
require(shards.size <= size) { "Not enough instances, required ${shards.size} but was $size" }
return mapIndexed { index, id -> id to shards[index] }.toMap()
}

private fun AssociatedShards.prepareApkToInstall(): List<AndroidApps> =
map { (instanceId, list: List<Shard.App>) ->
AndroidApps(
instanceId = instanceId,
paths = list.flatMap { app -> app.tests.map { test -> test.name } + app.name }
)
}

private fun AssociatedShards.prepareTestPlan(
parsePackageName: TestApk.ParsePackageName
) =
AndroidTestPlan.Config(
instances = mapValues { (_, shards) ->
shards.map { shard ->
shard.tests.map { test ->

AndroidTestPlan.Shard(
packageName = shard.name,
testRunner = "",
testCases = shard.tests.map { test ->
test.name
}
)
}
}
}
)

private typealias AssociatedShards = Map<String, List<Shard.App>>
4 changes: 4 additions & 0 deletions corellium/domain/src/test/resources/corellium.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
## Credentials
api=rh.corellium.io
username=matthew.edwards@robinhood.com
password=hakequkihojoxux
17 changes: 16 additions & 1 deletion corellium/shard/src/main/kotlin/flank/corellium/shard/Shard.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,34 @@ fun List<Shard.App>.calculateShards(
.mapToShards()

/**
* Namespace for sharding input and output structures
* Namespace for sharding input and output structures.
*/
object Shard {

/**
* Abstract representation for test app apk.
* @property name An abstract name for identifying app.
* @property tests The list of tests modules related to app.
*/
class App(
val name: String,
val tests: List<Test>
)

/**
* Abstract representation for test apk.
* @property name An abstract name for identifying test group.
* @property cases The list of test cases related to group.
*/
class Test(
val name: String,
val cases: List<Case>
) {
/**
* Abstract representation for test case (test method).
* @property name An abstract name for identifying test case.
* @property duration The duration of the test case run. Use default if no previous duration was recorded.
*/
class Case(
val name: String,
val duration: Long = DEFAULT_DURATION
Expand Down
1 change: 1 addition & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ include(
":corellium:api",
":corellium:shard",
":corellium:adapter",
":corellium:domain",
)

plugins {
Expand Down

0 comments on commit 72c2dcf

Please # to comment.