Skip to content

Commit 3a28bba

Browse files
Linux iOS sharding (Flank#313)
* Linux iOS sharding * Lazy install binaries * Document submodule git commands * Try loading resources from classLoader * Fix tests * Use folder prefix
1 parent b2e7ef6 commit 3a28bba

File tree

9 files changed

+64
-15
lines changed

9 files changed

+64
-15
lines changed

.gitmodules

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[submodule "test_runner/src/main/resources/binaries"]
2+
path = test_runner/src/main/resources/binaries
3+
url = https://github.com/Flank/binaries.git

README.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ Flank is a [massively parallel Android and iOS test runner](https://medium.com/w
55
### Contributing
66

77
- Use [JetBrains Toolbox](https://www.jetbrains.com/toolbox/app/) to install `IntelliJ IDEA Community`
8-
- Clone the repo `git clone https://github.com/TestArmada/flank.git`
8+
- Clone the repo `git clone --recursive https://github.com/TestArmada/flank.git`
9+
- `git submodule update --init --recursive` updates the submodules
910
- Open `test_runner/build.gradle.kts` with `IntelliJ IDEA Community`
1011

1112
### iOS example

test_runner/src/main/kotlin/ftl/config/FtlConstants.kt

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import com.google.api.client.json.jackson2.JacksonFactory
99

1010
object FtlConstants {
1111
var useMock = false
12+
val macOS = System.getProperty("os.name") == "Mac OS X"
1213
const val localhost = "http://localhost:8080"
1314

1415
const val defaultIosConfig = "./flank.ios.yml"

test_runner/src/main/kotlin/ftl/ios/Parse.kt

+29-7
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,21 @@
11
package ftl.ios
22

3+
import ftl.config.FtlConstants.macOS
34
import ftl.util.Bash
5+
import ftl.util.Utils.copyBinaryResource
46
import java.io.File
57

68
object Parse {
79

10+
private val installBinaries by lazy {
11+
if (!macOS) {
12+
copyBinaryResource("nm")
13+
copyBinaryResource("swift-demangle")
14+
copyBinaryResource("libatomic.so.1") // swift-demangle dependency
15+
copyBinaryResource("libatomic.so.1.2.0")
16+
}
17+
}
18+
819
private fun validateFile(path: String) {
920
val file = File(path)
1021
if (!file.exists()) {
@@ -16,16 +27,20 @@ object Parse {
1627

1728
private fun methodName(matcher: MatchResult): String {
1829
return matcher.groupValues.last()
19-
.replace('.', '/')
20-
.replace(' ', '/')
30+
.replace('.', '/')
31+
.replace(' ', '/')
2132
}
2233

2334
internal fun parseObjcTests(binary: String): List<String> {
35+
installBinaries
2436
validateFile(binary)
2537

2638
val results = mutableListOf<String>()
2739
// https://github.com/linkedin/bluepill/blob/37e7efa42472222b81adaa0e88f2bd82aa289b44/Source/Shared/BPXCTestFile.m#L18
28-
val output = Bash.execute("nm -U $binary")
40+
var cmd = "nm -U $binary"
41+
if (!macOS) cmd = "PATH=~/.flank $cmd"
42+
val output = Bash.execute(cmd)
43+
2944
output.lines().forEach { line ->
3045
// 000089b0 t -[EarlGreyExampleTests testLayout]
3146
// 00008330 t -[EarlGreyExampleTests testCustomAction]
@@ -39,15 +54,22 @@ object Parse {
3954
}
4055

4156
internal fun parseSwiftTests(binary: String): List<String> {
57+
installBinaries
4258
validateFile(binary)
43-
4459
val results = mutableListOf<String>()
45-
4660
// The OS limits the list of arguments to ARG_MAX. Setting the xargs limit avoids a fatal
4761
// 'argument too long' error. xargs will split the args and run the command for each chunk.
48-
val argMax = Bash.execute("getconf ARG_MAX")
62+
// getconf ARG_MAX
63+
val argMax = 262_144
64+
65+
val cmd = if (macOS) {
66+
"nm -gU $binary | xargs -s $argMax xcrun swift-demangle"
67+
} else {
68+
"export LD_LIBRARY_PATH=~/.flank; export PATH=~/.flank:\$PATH; nm -gU $binary | xargs -s $argMax swift-demangle"
69+
}
70+
4971
// https://github.com/linkedin/bluepill/blob/37e7efa42472222b81adaa0e88f2bd82aa289b44/Source/Shared/BPXCTestFile.m#L17-18
50-
val demangledOutput = Bash.execute("nm -gU $binary | xargs -s $argMax xcrun swift-demangle")
72+
val demangledOutput = Bash.execute(cmd)
5173
demangledOutput.lines().forEach { line ->
5274
// _T025EarlGreyExampleTestsSwift0abceD0C10testLayoutyyF ---> EarlGreyExampleTestsSwift.EarlGreyExampleSwiftTests.testLayout() -> ()
5375
// _T025EarlGreyExampleTestsSwift0abceD0C16testCustomActionyyF ---> EarlGreyExampleTestsSwift.EarlGreyExampleSwiftTests.testCustomAction() -> ()

test_runner/src/main/kotlin/ftl/util/Utils.kt

+23-3
Original file line numberDiff line numberDiff line change
@@ -95,9 +95,29 @@ object Utils {
9595
return bucketName.toString()
9696
}
9797

98+
private val classLoader = Thread.currentThread().contextClassLoader
99+
100+
private fun getResource(name: String): InputStream {
101+
return classLoader.getResourceAsStream(name)
102+
?: throw RuntimeException("Unable to find resource: $name")
103+
}
104+
98105
fun readTextResource(name: String): String {
99-
val resource: InputStream = this::class.java.getResourceAsStream("/$name")
100-
?: throw RuntimeException("Unable to find resource: /$name")
101-
return resource.bufferedReader().use { it.readText() }
106+
return getResource(name).bufferedReader().use { it.readText() }
107+
}
108+
109+
private val userHome = System.getProperty("user.home")
110+
111+
fun copyBinaryResource(name: String) {
112+
val destinationPath = Paths.get(userHome, ".flank", name)
113+
val destinationFile = destinationPath.toFile()
114+
115+
if (destinationFile.exists()) return
116+
destinationPath.parent.toFile().mkdirs()
117+
118+
// "binaries/" folder prefix is required for Linux to find the resource.
119+
val bytes = getResource("binaries/$name").use { it.readBytes() }
120+
Files.write(destinationPath, bytes)
121+
destinationFile.setExecutable(true)
102122
}
103123
}
Submodule binaries added at f019dc5

test_runner/src/test/kotlin/ftl/ios/ParseTest.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ class ParseTest {
8282
}
8383

8484
@Test(expected = RuntimeException::class)
85-
fun parseSwiftTests_validateFile() {
85+
fun parseSwiftTests_tmpFolder() {
8686
Parse.parseSwiftTests("/tmp")
8787
}
8888
}

test_runner/src/test/kotlin/ftl/test/util/FlankTestRunner.kt

-2
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@ import java.nio.file.Paths
1010
class FlankTestRunner(klass: Class<*>) : BlockJUnit4ClassRunner(klass) {
1111

1212
companion object {
13-
val macOS = System.getProperty("os.name") == "Mac OS X"
14-
1513
init {
1614
println("FlankTestRunner init\n")
1715
val server = MockServer.application

test_runner/src/test/kotlin/ftl/util/BashTest.kt

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
package ftl.util
22

33
import com.google.common.truth.Truth.assertThat
4-
import ftl.test.util.FlankTestRunner.Companion.macOS
4+
import ftl.config.FtlConstants.macOS
5+
import ftl.test.util.FlankTestRunner
56
import org.junit.Test
7+
import org.junit.runner.RunWith
68

9+
@RunWith(FlankTestRunner::class)
710
class BashTest {
811

912
@Test

0 commit comments

Comments
 (0)