-
Notifications
You must be signed in to change notification settings - Fork 119
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Dump shards #794
Dump shards #794
Changes from all commits
cfa8c9d
d6dc2ef
d2e8881
b7abfe3
5a93d6c
9aa7f52
6a6d464
e673d41
07ed2c3
5606561
e878905
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
package ftl.run | ||
|
||
import ftl.args.AndroidArgs | ||
import ftl.args.IosArgs | ||
import ftl.run.common.prettyPrint | ||
import ftl.run.model.AndroidMatrixTestShards | ||
import ftl.run.platform.android.getAndroidMatrixShards | ||
import ftl.util.FlankFatalError | ||
import java.nio.file.Files | ||
import java.nio.file.Paths | ||
|
||
fun dumpShards(args: AndroidArgs) { | ||
if (!args.isInstrumentationTest) throw FlankFatalError( | ||
"Cannot dump shards for non instrumentation test, ensure test apk has been set." | ||
) | ||
val shards: AndroidMatrixTestShards = getAndroidMatrixShards(args) | ||
saveShardChunks( | ||
shardFilePath = ANDROID_SHARD_FILE, | ||
shards = shards, | ||
size = shards.size | ||
) | ||
} | ||
|
||
fun dumpShards(args: IosArgs) { | ||
saveShardChunks( | ||
shardFilePath = IOS_SHARD_FILE, | ||
shards = args.testShardChunks, | ||
size = args.testShardChunks.size | ||
) | ||
} | ||
|
||
private fun saveShardChunks( | ||
shardFilePath: String, | ||
shards: Any, | ||
size: Int | ||
) { | ||
Files.write( | ||
Paths.get(shardFilePath), | ||
prettyPrint.toJson(shards).toByteArray() | ||
) | ||
println("Saved $size shards to $shardFilePath") | ||
} | ||
|
||
const val ANDROID_SHARD_FILE = "android_shards.json" | ||
const val IOS_SHARD_FILE = "ios_shards.json" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
package ftl.run.model | ||
|
||
typealias AndroidMatrixTestShards = Map<String, AndroidTestShards> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package ftl.run.model | ||
|
||
data class AndroidTestShards( | ||
val app: String, | ||
val test: String, | ||
val shards: Map<String, List<String>> = emptyMap() | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package ftl.run.model | ||
|
||
import ftl.util.FileReference | ||
|
||
data class InstrumentationTestApk( | ||
val app: FileReference = FileReference(), | ||
val test: FileReference = FileReference() | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
package ftl.run.platform.android | ||
|
||
import ftl.args.AndroidArgs | ||
import ftl.args.ShardChunks | ||
import ftl.run.model.AndroidMatrixTestShards | ||
import ftl.run.model.AndroidTestShards | ||
import ftl.run.model.InstrumentationTestApk | ||
import ftl.util.asFileReference | ||
|
||
fun getAndroidMatrixShards( | ||
args: AndroidArgs | ||
): AndroidMatrixTestShards = | ||
getInstrumentationShardChunks( | ||
args = args, | ||
testApks = args.createInstrumentationTestApks() | ||
).asMatrixTestShards() | ||
|
||
private fun AndroidArgs.createInstrumentationTestApks(): List<InstrumentationTestApk> = | ||
listOfNotNull( | ||
testApk?.let { testApk -> | ||
InstrumentationTestApk( | ||
app = appApk.asFileReference(), | ||
test = testApk.asFileReference() | ||
) | ||
} | ||
) + additionalAppTestApks.map { | ||
InstrumentationTestApk( | ||
app = (it.app ?: appApk).asFileReference(), | ||
test = it.test.asFileReference() | ||
) | ||
} | ||
|
||
private fun Map<InstrumentationTestApk, ShardChunks>.asMatrixTestShards(): AndroidMatrixTestShards = | ||
map { (testApks, shards: List<List<String>>) -> | ||
AndroidTestShards( | ||
app = testApks.app.local, | ||
test = testApks.test.local, | ||
shards = shards.mapIndexed { index, testCases -> | ||
"shard-$index" to testCases | ||
}.toMap() | ||
) | ||
}.mapIndexed { index, androidTestShards -> | ||
"matrix-$index" to androidTestShards | ||
}.toMap() |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package ftl.run.platform.android | ||
|
||
import ftl.args.AndroidArgs | ||
import ftl.args.ShardChunks | ||
import ftl.run.model.InstrumentationTestApk | ||
import ftl.util.asFileReference | ||
|
||
fun getAndroidShardChunks( | ||
args: AndroidArgs, | ||
testApk: String | ||
): ShardChunks = | ||
getInstrumentationShardChunks( | ||
args = args, | ||
testApks = listOf(InstrumentationTestApk(test = testApk.asFileReference())) | ||
).flatMap { (_, shardChunks) -> shardChunks } |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
package ftl.run.platform.android | ||
|
||
import com.linkedin.dex.parser.DexParser | ||
import ftl.args.AndroidArgs | ||
import ftl.args.ArgsHelper | ||
import ftl.args.ShardChunks | ||
import ftl.config.FtlConstants | ||
import ftl.filter.TestFilter | ||
import ftl.filter.TestFilters | ||
import ftl.run.model.InstrumentationTestApk | ||
import ftl.util.FlankTestMethod | ||
import ftl.util.downloadIfNeeded | ||
import java.io.File | ||
|
||
fun getInstrumentationShardChunks( | ||
args: AndroidArgs, | ||
testApks: List<InstrumentationTestApk> | ||
): Map<InstrumentationTestApk, ShardChunks> = | ||
getFlankTestMethods( | ||
testApks = testApks.download(), | ||
testFilter = TestFilters.fromTestTargets(args.testTargets) | ||
).mapValues { (_, testMethods: List<FlankTestMethod>) -> | ||
if (testMethods.isNotEmpty()) { | ||
ArgsHelper.calculateShards(testMethods, args, args.numUniformShards) | ||
} else { | ||
printNoTests(testApks) | ||
emptyList() | ||
} | ||
} | ||
|
||
private fun getFlankTestMethods( | ||
testApks: List<InstrumentationTestApk>, | ||
testFilter: TestFilter | ||
): Map<InstrumentationTestApk, List<FlankTestMethod>> = | ||
testApks.associateWith { testApk -> | ||
DexParser.findTestMethods(testApk.test.local).asSequence().distinct().filter(testFilter.shouldRun).map { testMethod -> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How about more functional styling here, WDYT? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There are only function calls, no value assignments, no ordinary loops, even no conditions so I have no idea how to do it more functional :). Pls explain me by example. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well my comment was just cosmetic one. Here we have invocation chain in one line, I was thinking about splitting it to new line each. So as I said 100% cosmetic |
||
FlankTestMethod( | ||
testName = "class ${testMethod.testName}", | ||
ignored = testMethod.annotations.any { it.name == "org.junit.Ignore" } | ||
) | ||
}.toList() | ||
} | ||
|
||
private fun List<InstrumentationTestApk>.download(): List<InstrumentationTestApk> = | ||
map { reference -> | ||
reference.copy( | ||
app = reference.app.downloadIfNeeded(), | ||
test = reference.test.downloadIfNeeded() | ||
) | ||
} | ||
|
||
private fun printNoTests(testApks: List<InstrumentationTestApk>) { | ||
val testApkNames = testApks.joinToString(", ") { pathname -> File(pathname.test.local).name } | ||
println("${FtlConstants.indent}No tests for $testApkNames") | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be great to have concurrent download but I guess it's for another PR :)
cc @bootstraponline
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking about concurrent download, but decided to leave as is due to additional changes in tests. But I can add it easily. @bootstraponline ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think concurrent downloads would be nice