diff --git a/buildSrc/src/main/java/com/osacky/flank/gradle/FladlePluginDelegate.kt b/buildSrc/src/main/java/com/osacky/flank/gradle/FladlePluginDelegate.kt index 87e3cfee..173ffedc 100644 --- a/buildSrc/src/main/java/com/osacky/flank/gradle/FladlePluginDelegate.kt +++ b/buildSrc/src/main/java/com/osacky/flank/gradle/FladlePluginDelegate.kt @@ -40,6 +40,8 @@ class FladlePluginDelegate { // Must be done afterEvaluate otherwise extension values will not be set. project.dependencies.add(FLADLE_CONFIG, "${base.flankCoordinates.get()}:${base.flankVersion.get()}") + if (project.hasProperty("sanityRobo")) base.sanityRobo.set(true) + // Only use automatic apk path detection for 'com.android.application' projects. project.pluginManager.withPlugin("com.android.application") { if (!base.debugApk.isPresent || !base.instrumentationApk.isPresent) { diff --git a/buildSrc/src/main/java/com/osacky/flank/gradle/FlankGradleExtension.kt b/buildSrc/src/main/java/com/osacky/flank/gradle/FlankGradleExtension.kt index c96b028f..e127ea43 100644 --- a/buildSrc/src/main/java/com/osacky/flank/gradle/FlankGradleExtension.kt +++ b/buildSrc/src/main/java/com/osacky/flank/gradle/FlankGradleExtension.kt @@ -17,6 +17,9 @@ open class FlankGradleExtension @Inject constructor(objects: ObjectFactory) : Fl @get:Input val flankCoordinates: Property = objects.property(String::class.java).convention("com.github.flank:flank") + @get:Input + val sanityRobo: Property = objects.property().convention(false) + @get:Input val flankVersion: Property = objects.property(String::class.java).convention("20.08.3") // Project id is automatically discovered by default. Use this to override the project id. diff --git a/buildSrc/src/main/java/com/osacky/flank/gradle/YamlWriter.kt b/buildSrc/src/main/java/com/osacky/flank/gradle/YamlWriter.kt index 2854b389..7ee8f76c 100644 --- a/buildSrc/src/main/java/com/osacky/flank/gradle/YamlWriter.kt +++ b/buildSrc/src/main/java/com/osacky/flank/gradle/YamlWriter.kt @@ -9,7 +9,7 @@ internal class YamlWriter { check(base.serviceAccountCredentials.isPresent) { "ServiceAccountCredentials in fladle extension not set. https://github.com/runningcode/fladle#serviceaccountcredentials" } } check(base.debugApk.isPresent) { "debugApk must be specified" } - check(base.instrumentationApk.isPresent xor !base.roboScript.isNullOrBlank()) { + check(base.sanityRobo.get() == true || (base.instrumentationApk.isPresent xor !base.roboScript.isNullOrBlank())) { """ Either instrumentationApk file or roboScript file must be specified but not both. instrumentationApk=${base.instrumentationApk.orNull} @@ -17,14 +17,16 @@ internal class YamlWriter { """.trimIndent() } + val shouldPrintTestAndRobo = base.sanityRobo.get().not() val deviceString = createDeviceString(config.devices) - val additionalProperties = writeAdditionalProperties(config) - val flankProperties = writeFlankProperties(config) + val additionalProperties = writeAdditionalProperties(config, shouldPrintTestAndRobo) + val flankProperties = writeFlankProperties(config, shouldPrintTestAndRobo) return buildString { appendln("gcloud:") appendln(" app: ${base.debugApk.get()}") - if (base.instrumentationApk.isPresent) { + // We don't want to print instrumentation apks if sanityRobo == true + if (shouldPrintTestAndRobo && base.instrumentationApk.isPresent) { appendln(" test: ${base.instrumentationApk.get()}") } appendln(deviceString) @@ -33,7 +35,7 @@ internal class YamlWriter { } } - internal fun writeFlankProperties(config: FladleConfig): String = buildString { + internal fun writeFlankProperties(config: FladleConfig, printApk: Boolean = true): String = buildString { val testShards = config.testShards val shardTime = config.shardTime val repeatTests = config.repeatTests @@ -73,7 +75,7 @@ internal class YamlWriter { } val additionalTestApks = config.additionalTestApks.getOrElse(emptyList()) - if (additionalTestApks.isNotEmpty()) { + if (printApk && additionalTestApks.isNotEmpty()) { appendln(" additional-app-test-apks:") additionalTestApks.forEach { appendln(" $it") @@ -101,7 +103,7 @@ internal class YamlWriter { appendln(" output-style: ${config.outputStyle.get()}") } - internal fun writeAdditionalProperties(config: FladleConfig): String = buildString { + internal fun writeAdditionalProperties(config: FladleConfig, printRobo: Boolean = true): String = buildString { appendln(" use-orchestrator: ${config.useOrchestrator}") appendln(" auto-google-login: ${config.autoGoogleLogin}") appendln(" record-video: ${config.recordVideo}") @@ -166,11 +168,11 @@ internal class YamlWriter { appendln(" network-profile: $it") } - config.roboScript?.let { + if (printRobo) config.roboScript?.let { appendln(" robo-script: $it") } - if (config.roboDirectives.isNotEmpty()) { + if (printRobo && config.roboDirectives.isNotEmpty()) { appendln(" robo-directives:") config.roboDirectives.forEach { val value = it.getOrElse(2) { "" }.let { stringValue -> if (stringValue.isBlank()) "\"\"" else stringValue } diff --git a/buildSrc/src/test/java/com/osacky/flank/gradle/integration/SanityRoboCheck.kt b/buildSrc/src/test/java/com/osacky/flank/gradle/integration/SanityRoboCheck.kt new file mode 100644 index 00000000..1b69f9ee --- /dev/null +++ b/buildSrc/src/test/java/com/osacky/flank/gradle/integration/SanityRoboCheck.kt @@ -0,0 +1,328 @@ +package com.osacky.flank.gradle.integration + +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.rules.TemporaryFolder + +class SanityRoboCheck { + @get:Rule + var testProjectRoot = TemporaryFolder() + + @Before + fun setUp() = testProjectRoot.newFile("flank-gradle-service.json").writeText("{}") + + @Test + fun checkSanityRoboRunSimpleCase() { + makeGradleFile(where = testProjectRoot) { + """ + |plugins { + | id "com.osacky.fladle" + |} + | + |fladle { + | serviceAccountCredentials = layout.projectDirectory.file("flank-gradle-service.json") + | debugApk = "foo.apk" + |} + """ + } + + val result = gradleRun { + arguments = listOf("writeConfigProps", "-PsanityRobo") + projectDir = testProjectRoot.root + } + + assertThat(result.output).contains("SUCCESS") + + "build/fladle/flank.yml" readAndCompareWith { + """ + |gcloud: + | app: foo.apk + | device: + | - model: NexusLowRes + | version: 28 + | + | use-orchestrator: false + | auto-google-login: false + | record-video: true + | performance-metrics: true + | timeout: 15m + | num-flaky-test-attempts: 0 + | + |flank: + | keep-file-path: false + | ignore-failed-tests: false + | disable-sharding: false + | smart-flank-disable-upload: false + | legacy-junit-result: false + | full-junit-result: false + | output-style: single + """ + } + } + + @Test + fun checkSanityRoboRunWithApksAdded() { + makeGradleFile(where = testProjectRoot) { + """ + |plugins { + | id "com.osacky.fladle" + |} + | + |fladle { + | serviceAccountCredentials = layout.projectDirectory.file("flank-gradle-service.json") + | debugApk = "foo.apk" + | instrumentationApk = "test.apk" + | additionalTestApks = [ + | "- app: debug2.apk", + | " test: test2.apk", + | "- test: test3.apk" + | ] + |} + """ + } + + val result = gradleRun { + arguments = listOf("writeConfigProps", "-PsanityRobo") + projectDir = testProjectRoot.root + } + + assertThat(result.output).contains("SUCCESS") + + "build/fladle/flank.yml" readAndCompareWith { + """ + |gcloud: + | app: foo.apk + | device: + | - model: NexusLowRes + | version: 28 + | + | use-orchestrator: false + | auto-google-login: false + | record-video: true + | performance-metrics: true + | timeout: 15m + | num-flaky-test-attempts: 0 + | + |flank: + | keep-file-path: false + | ignore-failed-tests: false + | disable-sharding: false + | smart-flank-disable-upload: false + | legacy-junit-result: false + | full-junit-result: false + | output-style: single + """ + } + } + + @Test + fun checkSanityRoboRunMultipleConfigs() { + makeGradleFile(where = testProjectRoot) { + """ + |plugins { + | id "com.osacky.fladle" + |} + | + |fladle { + | serviceAccountCredentials = layout.projectDirectory.file("flank-gradle-service.json") + | debugApk = "foo.apk" + | instrumentationApk = "test.apk" + | additionalTestApks = [ + | "- app: debug2.apk", + | " test: test2.apk", + | "- test: test3.apk" + | ] + | configs { + | orange { + | testTargets = ['override'] + | localResultsDir.set('overrideDir') + | } + | } + |} + """ + } + + val result = gradleRun { + arguments = listOf("writeConfigProps", "-PsanityRobo") + projectDir = testProjectRoot.root + } + + assertThat(result.output).contains("SUCCESS") + + "build/fladle/flank.yml" readAndCompareWith { + """ + |gcloud: + | app: foo.apk + | device: + | - model: NexusLowRes + | version: 28 + | + | use-orchestrator: false + | auto-google-login: false + | record-video: true + | performance-metrics: true + | timeout: 15m + | num-flaky-test-attempts: 0 + | + |flank: + | keep-file-path: false + | ignore-failed-tests: false + | disable-sharding: false + | smart-flank-disable-upload: false + | legacy-junit-result: false + | full-junit-result: false + | output-style: single + """ + } + + val resultOrange = gradleRun { + arguments = listOf("writeConfigPropsOrange", "-PsanityRobo") + projectDir = testProjectRoot.root + } + + assertThat(resultOrange.output).contains("SUCCESS") + + "build/fladle/orange/flank.yml" readAndCompareWith { + """ + |gcloud: + | app: foo.apk + | device: + | - model: NexusLowRes + | version: 28 + | + | use-orchestrator: false + | auto-google-login: false + | record-video: true + | performance-metrics: true + | timeout: 15m + | test-targets: + | - override + | num-flaky-test-attempts: 0 + | + |flank: + | keep-file-path: false + | ignore-failed-tests: false + | disable-sharding: false + | smart-flank-disable-upload: false + | local-result-dir: overrideDir + | legacy-junit-result: false + | full-junit-result: false + | output-style: single + """ + } + } + + @Test + fun checkSanityRoboRunRoboScript() { + makeGradleFile(where = testProjectRoot) { + """ + |plugins { + | id "com.osacky.fladle" + |} + | + |fladle { + | serviceAccountCredentials = layout.projectDirectory.file("flank-gradle-service.json") + | debugApk = "foo.apk" + | roboScript = "some/path/script.json" + |} + """ + } + + val result = gradleRun { + arguments = listOf("writeConfigProps", "-PsanityRobo") + projectDir = testProjectRoot.root + } + + assertThat(result.output).contains("SUCCESS") + + "build/fladle/flank.yml" readAndCompareWith { + """ + |gcloud: + | app: foo.apk + | device: + | - model: NexusLowRes + | version: 28 + | + | use-orchestrator: false + | auto-google-login: false + | record-video: true + | performance-metrics: true + | timeout: 15m + | num-flaky-test-attempts: 0 + | + |flank: + | keep-file-path: false + | ignore-failed-tests: false + | disable-sharding: false + | smart-flank-disable-upload: false + | legacy-junit-result: false + | full-junit-result: false + | output-style: single + """ + } + } + + @Test + fun checkSanityRoboRunRoboDirectives() { + makeGradleFile(where = testProjectRoot) { + """ + |plugins { + | id "com.osacky.fladle" + |} + | + |fladle { + | serviceAccountCredentials = layout.projectDirectory.file("flank-gradle-service.json") + | debugApk = "foo.apk" + | roboDirectives = [ + | ["click", "button1", ""], + | ["ignore", "button2"], + | ["text", "field1", "my text"], + | ] + |} + """ + } + + val result = gradleRun { + arguments = listOf("writeConfigProps", "-PsanityRobo") + projectDir = testProjectRoot.root + } + + assertThat(result.output).contains("SUCCESS") + + "build/fladle/flank.yml" readAndCompareWith { + """ + |gcloud: + | app: foo.apk + | device: + | - model: NexusLowRes + | version: 28 + | + | use-orchestrator: false + | auto-google-login: false + | record-video: true + | performance-metrics: true + | timeout: 15m + | num-flaky-test-attempts: 0 + | + |flank: + | keep-file-path: false + | ignore-failed-tests: false + | disable-sharding: false + | smart-flank-disable-upload: false + | legacy-junit-result: false + | full-junit-result: false + | output-style: single + """ + } + } + + private infix fun String.readAndCompareWith(block: () -> String) = testProjectRoot + .root + .resolve(this) + .readText() + .run { + assertThat(this).contains(block().trimMargin()) + } +} diff --git a/buildSrc/src/test/java/com/osacky/flank/gradle/integration/TestFixtures.kt b/buildSrc/src/test/java/com/osacky/flank/gradle/integration/TestFixtures.kt index 1d65a757..c2c6e865 100644 --- a/buildSrc/src/test/java/com/osacky/flank/gradle/integration/TestFixtures.kt +++ b/buildSrc/src/test/java/com/osacky/flank/gradle/integration/TestFixtures.kt @@ -1,8 +1,27 @@ package com.osacky.flank.gradle.integration +import org.gradle.testkit.runner.GradleRunner import org.junit.rules.TemporaryFolder import java.io.File fun TemporaryFolder.setupFixture(fixtureName: String) { File(this::class.java.classLoader.getResource(fixtureName)!!.file).copyRecursively(newFile(fixtureName), true) } + +internal fun makeGradleFile(where: TemporaryFolder, stringProvider: () -> String) = where + .newFile("build.gradle") + .writeText(stringProvider().trimMargin()) + +internal fun gradleRun(block: GradleRunFladle.() -> Unit) = GradleRunFladle().apply(block).run { + GradleRunner.create() + .withPluginClasspath() + .withArguments(arguments) + .forwardOutput() + .withProjectDir(projectDir) + .build() +} + +internal data class GradleRunFladle( + var arguments: List = emptyList(), + var projectDir: File? = null +)