diff --git a/README.md b/README.md index 97f6702214..3e9165fc34 100644 --- a/README.md +++ b/README.md @@ -77,6 +77,9 @@ flank: # test targets - a list of tests to run. omit to run all tests. test-targets: - b/testBasicSelection + # regex is matched against bucket paths, for example: 2019-01-09_00:18:07.314000_hCMY/shard_0/EarlGreyExampleSwiftTests_iphoneos12.1-arm64e.xctestrun + files-to-download: + - .*\.png$ ``` ### Android example @@ -127,6 +130,9 @@ flank: # useful if you need to grant permissions or login before other tests run test-targets-always-run: - class com.example.app.ExampleUiTest#testPasses + # regex is matched against bucket paths, for example: 2019-01-09_00:13:06.106000_YCKl/shard_0/NexusLowRes-28-en-portrait/bugreport.txt + files-to-download: + - .*\.mp4$ ``` ### CI integration diff --git a/contributing.md b/contributing.md index a4b8b162ee..7a2ac58eee 100644 --- a/contributing.md +++ b/contributing.md @@ -1,4 +1,5 @@ ## Setup + - Install [Oracle JDK 8](http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html) - JDK 9 or later will not work - [IntelliJ Toolbox](https://www.jetbrains.com/toolbox/app/) @@ -21,6 +22,11 @@ See the main readme for instructions on how to run the iOS and Android samples. - Update `IArgs` with new property - Update `AndroidArgs` to reference the propery and update `toString` - Update `IosArgs` to reference the propery and `toString` +- Add test to `IosArgsTest` +- Add test to `IosRunCommandTest` and update `empty_params_parse_null` test +- Add test to `AndroidArgsTest` +- Add test to `AndroidRunCommandTest` and update `empty_params_parse_null` test +- Update Android/iOS example config in README.md, `flank.yml` and `flank.ios.yml` ## CLA diff --git a/release_notes.md b/release_notes.md index c315838d2b..1ee5333665 100644 --- a/release_notes.md +++ b/release_notes.md @@ -1,6 +1,7 @@ ## v4.2.0 (unreleased) - Fix create Gcs bucket [#444](https://github.com/TestArmada/flank/pull/444) +- Add `directories-to-download` to Android and iOS. Specify a list of regular expressions to download files from the Google Cloud Storage bucket. [#441](https://github.com/TestArmada/flank/pull/441) ## v4.1.1 diff --git a/test_runner/build.gradle.kts b/test_runner/build.gradle.kts index a9bf710177..bb096d8a0a 100644 --- a/test_runner/build.gradle.kts +++ b/test_runner/build.gradle.kts @@ -135,7 +135,7 @@ dependencies { // https://stackoverflow.com/a/45286710 configurations.all { resolutionStrategy { - force("com.google.guava:guava:23.6-jre") + force("com.google.guava:guava:25.1-jre") force(Libs.KOTLIN_REFLECT) exclude(group = "com.google.guava", module = "guava-jdk5") } diff --git a/test_runner/flank.ios.yml b/test_runner/flank.ios.yml index cc798fca54..08824611fe 100644 --- a/test_runner/flank.ios.yml +++ b/test_runner/flank.ios.yml @@ -41,3 +41,7 @@ flank: # # test-targets: # - b/testBasicSelection + + # # regex is matched against bucket paths, for example: 2019-01-09_00:18:07.314000_hCMY/shard_0/EarlGreyExampleSwiftTests_iphoneos12.1-arm64e.xctestrun + # files-to-download: + # - .*\.png$ diff --git a/test_runner/flank.yml b/test_runner/flank.yml index 1b15e8a0a0..051b139230 100644 --- a/test_runner/flank.yml +++ b/test_runner/flank.yml @@ -46,3 +46,7 @@ flank: # # test-targets-always-run: # - class com.example.app.ExampleUiTest#testPasses + + # # regex is matched against bucket paths, for example: 2019-01-09_00:13:06.106000_YCKl/shard_0/NexusLowRes-28-en-portrait/bugreport.txt + # files-to-download: + # - .*\.mp4$ diff --git a/test_runner/src/main/kotlin/ftl/args/AndroidArgs.kt b/test_runner/src/main/kotlin/ftl/args/AndroidArgs.kt index e8b335335b..976b87c588 100644 --- a/test_runner/src/main/kotlin/ftl/args/AndroidArgs.kt +++ b/test_runner/src/main/kotlin/ftl/args/AndroidArgs.kt @@ -67,6 +67,7 @@ class AndroidArgs( override val repeatTests = cli?.repeatTests ?: flank.repeatTests override val smartFlankGcsPath = flank.smartFlankGcsPath override val testTargetsAlwaysRun = cli?.testTargetsAlwaysRun ?: flank.testTargetsAlwaysRun + override val filesToDownload = cli?.filesToDownload ?: flank.filesToDownload // computed properties not specified in yaml override val testShardChunks: List> by lazy { @@ -159,6 +160,8 @@ ${devicesToString(devices)} testShards: $testShards repeatTests: $repeatTests smartFlankGcsPath: $smartFlankGcsPath + files-to-download: +${listToString(filesToDownload)} test-targets-always-run: ${listToString(testTargetsAlwaysRun)} """.trimIndent() diff --git a/test_runner/src/main/kotlin/ftl/args/IArgs.kt b/test_runner/src/main/kotlin/ftl/args/IArgs.kt index 783c289264..4681eeddb9 100644 --- a/test_runner/src/main/kotlin/ftl/args/IArgs.kt +++ b/test_runner/src/main/kotlin/ftl/args/IArgs.kt @@ -18,6 +18,7 @@ interface IArgs { val repeatTests: Int val smartFlankGcsPath: String val testTargetsAlwaysRun: List + val filesToDownload: List // computed property val testShardChunks: List> diff --git a/test_runner/src/main/kotlin/ftl/args/IosArgs.kt b/test_runner/src/main/kotlin/ftl/args/IosArgs.kt index 67c44d979e..8917810dc9 100644 --- a/test_runner/src/main/kotlin/ftl/args/IosArgs.kt +++ b/test_runner/src/main/kotlin/ftl/args/IosArgs.kt @@ -52,6 +52,7 @@ class IosArgs( override val repeatTests = cli?.repeatTests ?: flank.repeatTests override val smartFlankGcsPath = flank.smartFlankGcsPath override val testTargetsAlwaysRun = cli?.testTargetsAlwaysRun ?: flank.testTargetsAlwaysRun + override val filesToDownload = cli?.filesToDownload ?: flank.filesToDownload private val iosFlank = iosFlankYml.flank val testTargets = cli?.testTargets ?: iosFlank.testTargets @@ -123,6 +124,8 @@ ${devicesToString(devices)} smartFlankGcsPath: $smartFlankGcsPath test-targets-always-run: ${listToString(testTargetsAlwaysRun)} + files-to-download: +${listToString(filesToDownload)} # iOS flank test-targets: ${listToString(testTargets)} diff --git a/test_runner/src/main/kotlin/ftl/args/yml/FlankYml.kt b/test_runner/src/main/kotlin/ftl/args/yml/FlankYml.kt index a5bb50af25..8f97e54be6 100644 --- a/test_runner/src/main/kotlin/ftl/args/yml/FlankYml.kt +++ b/test_runner/src/main/kotlin/ftl/args/yml/FlankYml.kt @@ -13,10 +13,13 @@ class FlankYmlParams( val smartFlankGcsPath: String = "", @field:JsonProperty("test-targets-always-run") - val testTargetsAlwaysRun: List = emptyList() + val testTargetsAlwaysRun: List = emptyList(), + + @field:JsonProperty("files-to-download") + val filesToDownload: List = emptyList() ) { companion object : IYmlKeys { - override val keys = listOf("testShards", "repeatTests", "smartFlankGcsPath", "test-targets-always-run") + override val keys = listOf("testShards", "repeatTests", "smartFlankGcsPath", "test-targets-always-run", "files-to-download") } init { diff --git a/test_runner/src/main/kotlin/ftl/cli/firebase/test/android/AndroidRunCommand.kt b/test_runner/src/main/kotlin/ftl/cli/firebase/test/android/AndroidRunCommand.kt index d39ece28ff..a0a85a9c2f 100644 --- a/test_runner/src/main/kotlin/ftl/cli/firebase/test/android/AndroidRunCommand.kt +++ b/test_runner/src/main/kotlin/ftl/cli/firebase/test/android/AndroidRunCommand.kt @@ -235,6 +235,16 @@ class AndroidRunCommand : Runnable { ) var testTargetsAlwaysRun: List? = null + @Option( + names = ["--files-to-download"], + split = ",", + description = ["A list of paths that will be downloaded from the resulting bucket " + + "to the local results folder after the test is complete. These must be absolute paths " + + "(for example, --files-to-download /images/tempDir1,/data/local/tmp/tempDir2). " + + "Path names are restricted to the characters a-zA-Z0-9_-./+."] + ) + var filesToDownload: List? = null + @Option( names = ["--results-dir"], description = [ diff --git a/test_runner/src/main/kotlin/ftl/cli/firebase/test/ios/IosRunCommand.kt b/test_runner/src/main/kotlin/ftl/cli/firebase/test/ios/IosRunCommand.kt index f3882f1755..817bbe8e52 100644 --- a/test_runner/src/main/kotlin/ftl/cli/firebase/test/ios/IosRunCommand.kt +++ b/test_runner/src/main/kotlin/ftl/cli/firebase/test/ios/IosRunCommand.kt @@ -126,6 +126,16 @@ class IosRunCommand : Runnable { ) var testTargets: List? = null + @Option( + names = ["--files-to-download"], + split = ",", + description = ["A list of paths that will be downloaded from the resulting bucket " + + "to the local results folder after the test is complete. These must be absolute paths " + + "(for example, --files-to-download /images/tempDir1,/data/local/tmp/tempDir2). " + + "Path names are restricted to the characters a-zA-Z0-9_-./+."] + ) + var filesToDownload: List? = null + @Option( names = ["--test"], description = ["The path to the test package (a zip file containing the iOS app " + diff --git a/test_runner/src/main/kotlin/ftl/reports/util/ReportManager.kt b/test_runner/src/main/kotlin/ftl/reports/util/ReportManager.kt index ffc83df5bf..79142cb343 100644 --- a/test_runner/src/main/kotlin/ftl/reports/util/ReportManager.kt +++ b/test_runner/src/main/kotlin/ftl/reports/util/ReportManager.kt @@ -11,7 +11,7 @@ import ftl.reports.MatrixResultsReport import ftl.reports.xml.model.JUnitTestResult import ftl.reports.xml.parseOneSuiteXml import ftl.reports.xml.parseAllSuitesXml -import ftl.util.ArtifactRegex +import ftl.util.Artifacts import ftl.util.resolveLocalRunPath import java.io.File import java.nio.file.Paths @@ -23,7 +23,7 @@ object ReportManager { val rootFolder = File(resolveLocalRunPath(matrices)) rootFolder.walk().forEach { - if (it.name.matches(ArtifactRegex.testResultRgx)) { + if (it.name.matches(Artifacts.testResultRgx)) { xmlFiles.add(it) } } diff --git a/test_runner/src/main/kotlin/ftl/run/TestRunner.kt b/test_runner/src/main/kotlin/ftl/run/TestRunner.kt index 3b20080bce..073aeabc5d 100644 --- a/test_runner/src/main/kotlin/ftl/run/TestRunner.kt +++ b/test_runner/src/main/kotlin/ftl/run/TestRunner.kt @@ -22,7 +22,7 @@ import ftl.gc.GcToolResults import ftl.json.MatrixMap import ftl.json.SavedMatrix import ftl.reports.util.ReportManager -import ftl.util.ArtifactRegex +import ftl.util.Artifacts import ftl.util.MatrixState import ftl.util.StopWatch import ftl.util.Utils @@ -188,8 +188,7 @@ object TestRunner { return MatrixMap(map, path) } - /** fetch test_result_0.xml & *.png **/ - private fun fetchArtifacts(matrixMap: MatrixMap) { + private fun fetchArtifacts(matrixMap: MatrixMap, args: IArgs) { println("FetchArtifacts") val fields = Storage.BlobListOption.fields(Storage.BlobField.NAME) @@ -206,10 +205,11 @@ object TestRunner { launch { val prefix = Storage.BlobListOption.prefix(matrix.gcsPathWithoutRootBucket) val result = GcStorage.storage.list(matrix.gcsRootBucket, prefix, fields) + val artifactsList = Artifacts.regexList(args) result.iterateAll().forEach { blob -> val blobPath = blob.blobId.name - if (blobPath.matches(ArtifactRegex.testResultRgx)) { + if (artifactsList.any { blobPath.matches(it) }) { val downloadFile = Paths.get(FtlConstants.localResultsDir, blobPath) print(".") if (!downloadFile.toFile().exists()) { @@ -325,7 +325,7 @@ object TestRunner { refreshMatrices(matrixMap, args) pollMatrices(matrixMap, args) - fetchArtifacts(matrixMap) + fetchArtifacts(matrixMap, args) // Must generate reports *after* fetching xml artifacts since reports require xml val exitCode = ReportManager.generate(matrixMap, args) @@ -346,7 +346,7 @@ object TestRunner { if (!args.async) { pollMatrices(matrixMap, args) - fetchArtifacts(matrixMap) + fetchArtifacts(matrixMap, args) val exitCode = ReportManager.generate(matrixMap, args) System.exit(exitCode) diff --git a/test_runner/src/main/kotlin/ftl/util/ArtifactRegex.kt b/test_runner/src/main/kotlin/ftl/util/ArtifactRegex.kt deleted file mode 100644 index c3069c1181..0000000000 --- a/test_runner/src/main/kotlin/ftl/util/ArtifactRegex.kt +++ /dev/null @@ -1,7 +0,0 @@ -package ftl.util - -object ArtifactRegex { - - val testResultRgx = Regex(".*test_result_\\d+\\.xml$") - val screenshotRgx = Regex(".*\\.png$") -} diff --git a/test_runner/src/main/kotlin/ftl/util/Artifacts.kt b/test_runner/src/main/kotlin/ftl/util/Artifacts.kt new file mode 100644 index 0000000000..0c03f3a48a --- /dev/null +++ b/test_runner/src/main/kotlin/ftl/util/Artifacts.kt @@ -0,0 +1,12 @@ +package ftl.util + +import ftl.args.IArgs + +object Artifacts { + + val testResultRgx = Regex(".*test_result_\\d+\\.xml$") + + fun regexList(args: IArgs): List { + return listOf(testResultRgx) + args.filesToDownload.map { Regex(it) } + } +} diff --git a/test_runner/src/main/resources/version.txt b/test_runner/src/main/resources/version.txt index c6a958af38..79d041d58e 100644 --- a/test_runner/src/main/resources/version.txt +++ b/test_runner/src/main/resources/version.txt @@ -1 +1 @@ -v4.1-SNAPSHOT +v4.2-SNAPSHOT diff --git a/test_runner/src/test/kotlin/ftl/args/AndroidArgsTest.kt b/test_runner/src/test/kotlin/ftl/args/AndroidArgsTest.kt index 0d0f9ee0bc..0111ecbfbb 100644 --- a/test_runner/src/test/kotlin/ftl/args/AndroidArgsTest.kt +++ b/test_runner/src/test/kotlin/ftl/args/AndroidArgsTest.kt @@ -59,6 +59,9 @@ class AndroidArgsTest { flank: testShards: 7 repeatTests: 8 + files-to-download: + - /sdcard/screenshots + - /sdcard/screenshots2 test-targets-always-run: - class example.Test#grantPermission - class example.Test#grantPermission2 @@ -154,6 +157,7 @@ class AndroidArgsTest { // FlankYml assert(testShards, 7) assert(repeatTests, 8) + assert(filesToDownload, listOf("/sdcard/screenshots", "/sdcard/screenshots2")) assert( testTargetsAlwaysRun, listOf( "class example.Test#grantPermission", @@ -206,6 +210,9 @@ AndroidArgs testShards: 7 repeatTests: 8 smartFlankGcsPath:${' '} + files-to-download: + - /sdcard/screenshots + - /sdcard/screenshots2 test-targets-always-run: - class example.Test#grantPermission - class example.Test#grantPermission2 @@ -245,6 +252,7 @@ AndroidArgs // FlankYml assert(testShards, 1) assert(repeatTests, 1) + assert(filesToDownload, empty) assert(testTargetsAlwaysRun, empty) } } @@ -476,6 +484,22 @@ AndroidArgs assertThat(androidArgs.directoriesToPull).isEqualTo(listOf("a", "b")) } + @Test + fun cli_filesToDownload() { + val cli = AndroidRunCommand() + CommandLine(cli).parse("--files-to-download=a,b") + + val yaml = """ + gcloud: + app: $appApk + test: $testApk + """ + assertThat(AndroidArgs.load(yaml).filesToDownload).isEmpty() + + val androidArgs = AndroidArgs.load(yaml, cli) + assertThat(androidArgs.filesToDownload).isEqualTo(listOf("a", "b")) + } + @Test fun cli_device() { val cli = AndroidRunCommand() diff --git a/test_runner/src/test/kotlin/ftl/args/IosArgsTest.kt b/test_runner/src/test/kotlin/ftl/args/IosArgsTest.kt index d84fe154e4..b4992aae33 100644 --- a/test_runner/src/test/kotlin/ftl/args/IosArgsTest.kt +++ b/test_runner/src/test/kotlin/ftl/args/IosArgsTest.kt @@ -53,6 +53,8 @@ class IosArgsTest { flank: testShards: 7 repeatTests: 8 + files-to-download: + - /sdcard/screenshots test-targets-always-run: - a/testGrantPermissions - a/testGrantPermissions2 @@ -159,6 +161,8 @@ IosArgs test-targets-always-run: - a/testGrantPermissions - a/testGrantPermissions2 + files-to-download: + - /sdcard/screenshots # iOS flank test-targets: - b/testBasicSelection @@ -194,6 +198,7 @@ IosArgs assert(testShards, 1) assert(repeatTests, 1) assert(testTargetsAlwaysRun, emptyList()) + assert(filesToDownload, emptyList()) // IosFlankYml assert(testTargets, empty) @@ -507,4 +512,20 @@ IosArgs assertThat(IosArgs.load(yaml).resultsDir).isEqualTo("a") assertThat(IosArgs.load(yaml, cli).resultsDir).isEqualTo("b") } + + @Test + fun cli_filesToDownload() { + val cli = IosRunCommand() + CommandLine(cli).parse("--files-to-download=a,b") + + val yaml = """ + gcloud: + test: $testPath + xctestrun-file: $testPath + """ + assertThat(IosArgs.load(yaml).filesToDownload).isEmpty() + + val androidArgs = IosArgs.load(yaml, cli) + assertThat(androidArgs.filesToDownload).isEqualTo(listOf("a", "b")) + } } diff --git a/test_runner/src/test/kotlin/ftl/cli/firebase/test/android/AndroidRunCommandTest.kt b/test_runner/src/test/kotlin/ftl/cli/firebase/test/android/AndroidRunCommandTest.kt index 525179c1a6..20786c90c1 100644 --- a/test_runner/src/test/kotlin/ftl/cli/firebase/test/android/AndroidRunCommandTest.kt +++ b/test_runner/src/test/kotlin/ftl/cli/firebase/test/android/AndroidRunCommandTest.kt @@ -80,6 +80,7 @@ class AndroidRunCommandTest { assertThat(cmd.testShards).isNull() assertThat(cmd.repeatTests).isNull() assertThat(cmd.testTargetsAlwaysRun).isNull() + assertThat(cmd.filesToDownload).isNull() assertThat(cmd.resultsDir).isNull() } @@ -273,4 +274,12 @@ class AndroidRunCommandTest { assertThat(cmd.resultsDir).isEqualTo("a") } + + @Test + fun filesToDownload_parse() { + val cmd = AndroidRunCommand() + CommandLine(cmd).parse("--files-to-download=a,b") + + assertThat(cmd.filesToDownload).isEqualTo(arrayListOf("a", "b")) + } } diff --git a/test_runner/src/test/kotlin/ftl/cli/firebase/test/ios/IosRunCommandTest.kt b/test_runner/src/test/kotlin/ftl/cli/firebase/test/ios/IosRunCommandTest.kt index bab82a7c67..11b4bb7b55 100644 --- a/test_runner/src/test/kotlin/ftl/cli/firebase/test/ios/IosRunCommandTest.kt +++ b/test_runner/src/test/kotlin/ftl/cli/firebase/test/ios/IosRunCommandTest.kt @@ -69,6 +69,7 @@ class IosRunCommandTest { assertThat(cmd.repeatTests).isNull() assertThat(cmd.testTargetsAlwaysRun).isNull() assertThat(cmd.testTargets).isNull() + assertThat(cmd.filesToDownload).isNull() assertThat(cmd.test).isNull() assertThat(cmd.xctestrunFile).isNull() assertThat(cmd.xcodeVersion).isNull() @@ -207,4 +208,12 @@ class IosRunCommandTest { assertThat(cmd.resultsDir).isEqualTo("a") } + + @Test + fun filesToDownload_parse() { + val cmd = IosRunCommand() + CommandLine(cmd).parse("--files-to-download=a,b") + + assertThat(cmd.filesToDownload).isEqualTo(arrayListOf("a", "b")) + } } diff --git a/test_runner/src/test/kotlin/ftl/test/util/LocalGcs.kt b/test_runner/src/test/kotlin/ftl/test/util/LocalGcs.kt index 2c52001910..a192ba3b3f 100644 --- a/test_runner/src/test/kotlin/ftl/test/util/LocalGcs.kt +++ b/test_runner/src/test/kotlin/ftl/test/util/LocalGcs.kt @@ -1,11 +1,14 @@ package ftl.test.util +import com.google.auth.oauth2.ComputeEngineCredentials import com.google.cloud.storage.BlobInfo import ftl.gc.GcStorage import org.junit.Assert import java.nio.file.Files import java.nio.file.Path import java.nio.file.Paths +import java.util.logging.Level +import java.util.logging.Logger object LocalGcs { @@ -28,6 +31,13 @@ object LocalGcs { ) } + private fun silenceComputeEngine() { + // Set log level then access the storage var to lazy load it. + // Silence info log about "Failed to detect whether we are running on Google Compute Engine." + Logger.getLogger(ComputeEngineCredentials::class.java.name).level = Level.OFF + GcStorage.storage + } + fun uploadFiles() { val appApk = "../test_app/apks/app-debug.apk" val testApk = "../test_app/apks/app-debug-androidTest.apk" diff --git a/test_runner/src/test/kotlin/ftl/util/ArtifactRegexTest.kt b/test_runner/src/test/kotlin/ftl/util/ArtifactRegexTest.kt deleted file mode 100644 index 0242375f6e..0000000000 --- a/test_runner/src/test/kotlin/ftl/util/ArtifactRegexTest.kt +++ /dev/null @@ -1,13 +0,0 @@ -package ftl.util - -import com.google.common.truth.Truth.assertThat -import org.junit.Test - -class ArtifactRegexTest { - - @Test - fun regexExists() { - assertThat(ArtifactRegex.testResultRgx).isNotNull() - assertThat(ArtifactRegex.screenshotRgx).isNotNull() - } -} diff --git a/test_runner/src/test/kotlin/ftl/util/ArtifactsTest.kt b/test_runner/src/test/kotlin/ftl/util/ArtifactsTest.kt new file mode 100644 index 0000000000..dc210064dc --- /dev/null +++ b/test_runner/src/test/kotlin/ftl/util/ArtifactsTest.kt @@ -0,0 +1,58 @@ +package ftl.util + +import com.google.common.truth.Truth.assertThat +import ftl.args.IArgs +import ftl.test.util.FlankTestRunner +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mockito.`when` +import org.mockito.Mockito.mock + +@RunWith(FlankTestRunner::class) +class ArtifactsTest { + + private companion object { + const val sdcardScreenshots = "/sdcard/screenshots" + const val sdcardTest = "/sdcard/test" + val sdcardScreenshotsRgx = Regex("/sdcard/screenshots") + val sdcardTestRgx = Regex("/sdcard/test") + } + + private fun createDirs(dirsToDownload: List = emptyList()): IArgs { + val mock = mock(IArgs::class.java) + `when`(mock.filesToDownload).thenReturn(dirsToDownload) + return mock + } + + @Test + fun regexExists() { + assertThat(Artifacts.testResultRgx).isNotNull() + } + + @Test + fun `artifactsToDownload should return just testResult and screenshot regex if no filesToDownload`() { + assertRegexEquals( + Artifacts.regexList(createDirs()), + listOf(Artifacts.testResultRgx) + ) + } + + @Test + fun `artifactsToDownload should return testResult, screenshot regex and filesToDownload regex if one`() { + val actual = Artifacts.regexList(createDirs(listOf(sdcardScreenshots))) + val expected = listOf(Artifacts.testResultRgx, sdcardScreenshotsRgx) + assertRegexEquals(actual, expected) + } + + @Test + fun `artifactsToDownload should return testResult, screenshot regex and filesToDownload regex if multiple`() { + val actual = Artifacts.regexList(createDirs(listOf(sdcardScreenshots, sdcardTest))) + val expected = listOf(Artifacts.testResultRgx, sdcardScreenshotsRgx, sdcardTestRgx) + assertRegexEquals(actual, expected) + } + + private fun assertRegexEquals(expected: List, actual: List) { + assertThat(actual.map { it.pattern }) + .containsExactly(*(expected.map { it.pattern }.toTypedArray())) + } +}