Skip to content
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

Support roboTest without roboScript (sanityRobo) #177

Conversation

pawelpasterz
Copy link
Contributor

@pawelpasterz pawelpasterz commented Sep 25, 2020

Fixes #165

Flank supports roboTest without roboScript (sanityRobo) Flank/flank#1108

Sanity robo should be ONLY launched when there is NO, robo-script, test, additional-app-test-apks. This reflects gcloud's behavior

TO BE UPDATED

To run sanity robo test add -PsanityRobo to gradle command

./gradlew runFlank -PsanityRobo

With this property, fladle should skip appending config yaml file with robo-directives, robo-script, test, additional-app-test-apks
Example:

  1. Run ./gradlew -p sample-kotlin writeConfigProps -PsanityRobo from project root
  2. generated config yaml should look (no test)
gcloud:
  app: [path]
  device:
  - model: Pixel2
    version: 26
  - model: Nexus5
    version: 23

  use-orchestrator: true
  auto-google-login: false
  record-video: true
  performance-metrics: true
  timeout: 15m
  environment-variables:
    clearPackageData: true
  test-targets:
  - class com.osacky.flank.gradle.sample.ExampleInstrumentedTest#seeView
  num-flaky-test-attempts: 1

flank:
  smart-flank-gcs-path: gs://test-lab-yr9w6qsdvy45q-iurp80dm95h8a/flank/test_app_android.xml
  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

@pawelpasterz pawelpasterz force-pushed the enable-robo-test-without-roboscript branch from 17f39ee to 4978a4b Compare September 25, 2020 08:03
@pawelpasterz
Copy link
Contributor Author

Hey @runningcode please, take a look and let me know what do you think

Thanks!

Copy link
Owner

@runningcode runningcode left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @pawelpasterz. Thanks very much for doing this. A lot of people have been asking for this feature.
I also really appreciate the thorough tests.

@pawelpasterz pawelpasterz force-pushed the enable-robo-test-without-roboscript branch from 31ea174 to 779ca80 Compare September 25, 2020 10:01
@pawelpasterz pawelpasterz force-pushed the enable-robo-test-without-roboscript branch from 0671480 to 4cfe399 Compare September 28, 2020 12:33
@pawelpasterz
Copy link
Contributor Author

pawelpasterz commented Sep 28, 2020

As discussed with @runningcode, changing approach a bit

  1. sanityRobo won't be able to set via gradle property
  2. Sanity robo run will ONLY be launched when ALL conditions are met:
    a) no instrumentationApk, roboScript, roboDirectives, additionalTestApks are set
    b) sanityRobo is explicitly set true (this will turn off autodetection feature for apks/scripts
    fladle {
        sanityRobo = true
    }
  3. If sanityRobo = true and at least one of instrumentationApk, roboScript, roboDirectives, additionalTestApks is set as well, an error will be thrown

@pawelpasterz pawelpasterz marked this pull request as draft September 29, 2020 10:44
@pawelpasterz pawelpasterz force-pushed the enable-robo-test-without-roboscript branch 2 times, most recently from ac2ba00 to a3ef5d3 Compare September 29, 2020 13:09
Copy link
Owner

@runningcode runningcode left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i haven't finished looking but just some comments! looks pretty good. i will make some suggestions on the error messages in my next pass.

@@ -115,6 +80,9 @@ open class FlankGradleExtension @Inject constructor(objects: ObjectFactory) : Fl
name = it,
projectId = objects.property<String>().convention(projectId),
serviceAccountCredentials = objects.fileProperty().convention(serviceAccountCredentials),
debugApk = objects.property<String>().convention(debugApk),
instrumentationApk = objects.property<String>().convention(instrumentationApk),
sanityRobo = objects.property<Boolean>().convention(false),
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't we be passing the value from the base here?

Copy link
Contributor Author

@pawelpasterz pawelpasterz Sep 29, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we shouldn't. Assuming we have sanityRobo = true in the base config that would propagate this to the additional configs. My idea was, every config has it's own sanityRobo value (default false) that is independent of the rest. I am thinking about the case when user want runFlank to be sanity robo test and all the rest (runFlank[name1], runFlank[name2]) are 'normal' test runs

Of course, I can change it to behave otherwise.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You make a good point here. I think we want consistency though. All other values are inherited. We shouldn't assume that users will not try to have multiple different sanityRobo configs which inherit from the base.
Let's pass the value from the base here as well.

@pawelpasterz pawelpasterz force-pushed the enable-robo-test-without-roboscript branch from 8dee5d4 to f726143 Compare September 30, 2020 10:42
Copy link
Owner

@runningcode runningcode left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very nice. I went through all of it. I had a few questions about the test cases and error messages but otherwise the overall approach looks like what we want!

@@ -153,6 +153,7 @@ fun org.gradle.api.publish.maven.MavenPom.configureForFladle(pluginName: String)
tasks.withType(Test::class.java).configureEach {
// Test fixtures are stored in here so we should re-run tests if the test projects change.
inputs.dir("src/test/resources")
maxParallelForks = Runtime.getRuntime().availableProcessors()
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we make this change separately? How does it affect the performance of the tests?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we make this change separately?

sure

How does it affect the performance of the tests?

On my machine, ./gradlew test took 1m 41s (without parallelism) and 1m 10s (with parallelism)
So it's not something crucial (IMO) but a nice-to-have feature.


private fun FladleConfigImpl.checkAndValidateConfig() {
if (sanityRobo.getOrElse(false)) when {
roboDirectives.isNotPresentOrEmpty -> throwAdditionalConfigError("roboDirectives", name)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is the ordering different for the property validation?
can we make both methods the same and just replace an empty base config name "" with base?

Although base could be the name of the configuration. I don't have a better idea though.

Copy link
Contributor Author

@pawelpasterz pawelpasterz Oct 1, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, nice catch. This is old implementation before I've added some new properties to FladleConfig, thanks!

if (base.instrumentationApk.isPresent) {
appendln(" test: ${base.instrumentationApk.get()}")
appendln(" app: ${config.debugApk.get()}")
// We don't want to print instrumentation apks if sanityRobo == true
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't we throw an error here if sanityRobo is true?

Copy link
Contributor Author

@pawelpasterz pawelpasterz Oct 1, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sanity run validation if the user sets instrumentationApk explicitly and this occurs before findDebugAndInstrumentationApk (autodetection ) is invoked (in FlankPluginDelegate). The autodetection feature sets app apk and test apk only for base config and then those values are used for inner (or would should I name those additional ?) configs.

So actually this is applicable only for case when base config is intended to be sanity robo run and the rest 'normal'

Logic could be simplified if we would agree that base config can't be sanity robo

@@ -45,4 +48,12 @@ data class FladleConfigImpl(
override val outputStyle: Property<String>,
override val legacyJunitResult: Property<Boolean>,
override val fullJunitResult: Property<Boolean>
) : FladleConfig
) : FladleConfig {
fun sanityRoboRun() {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this method. Its a good compromise!
Can we rename it to clearPropertiesForSanityRobo()? And add a bit of javadoc explaining which fields are being cleared?

@@ -57,7 +62,7 @@ internal class YamlWriter {
appendProperty(config.outputStyle, name = "output-style")
}

internal fun writeAdditionalProperties(config: FladleConfig): String = buildString {
internal fun writeAdditionalProperties(config: FladleConfig, printRobo: Boolean = true): String = buildString {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instead of having a boolean passed in to this function, maybe we can just separate it in to two functions? I think that would make the code more readable.
i have an intrinsic dislike of boolean parameters to functions 😆

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, I can remove this logic entirely since now we have sanityRobo in FladleConfig

}

@Test
fun `test auto configuration with sanityRobo set (base config)`() {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

very nice test. thank you!

@pawelpasterz pawelpasterz force-pushed the enable-robo-test-without-roboscript branch from f602526 to 65213bd Compare October 1, 2020 06:33
@pawelpasterz
Copy link
Contributor Author

pawelpasterz commented Oct 1, 2020

Hey @runningcode , ready for another review round :)

Copy link
Owner

@runningcode runningcode left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright, looking very good. Another round of comments and hopefully we can merge this very soon.

@@ -40,6 +40,9 @@ class FladlePluginDelegate {
// Must be done afterEvaluate otherwise extension values will not be set.
project.dependencies.add(FLADLE_CONFIG, "${base.flankCoordinates.get()}:${base.flankVersion.get()}")

checkIfSanityAndValidateConfigs(base)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's move this to be the first line in createTasksForConfig
that way the next line can be removed as well.

@@ -115,6 +80,9 @@ open class FlankGradleExtension @Inject constructor(objects: ObjectFactory) : Fl
name = it,
projectId = objects.property<String>().convention(projectId),
serviceAccountCredentials = objects.fileProperty().convention(serviceAccountCredentials),
debugApk = objects.property<String>().convention(debugApk),
instrumentationApk = objects.property<String>().convention(instrumentationApk),
sanityRobo = objects.property<Boolean>().convention(false),
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You make a good point here. I think we want consistency though. All other values are inherited. We shouldn't assume that users will not try to have multiple different sanityRobo configs which inherit from the base.
Let's pass the value from the base here as well.

}
is FladleConfigImpl -> config.checkAndValidateConfig(config.name) { option, name ->
"Incorrect [$name] configuration. [$option] can't be used together with sanityRobo. " +
"If you want to launch robo test run without robo script place only clearPropertiesForSanityRobo() into [$name] configuration"
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"If you want to launch robo test run without robo script place only clearPropertiesForSanityRobo() into [$name] configuration"
"To configure sanityRobo, add clearPropertiesForSanityRobo() into [$name] configuration"

I'm changing the wording here a bit because a robo test run could also be with the robo directives. In that case, these instructions could be confusing. Let's refer specifically to sanityRobo here.

"Incorrect [$name] configuration. [$option] can't be used together with sanityRobo. " +
"If you want to launch robo test run without robo script place only clearPropertiesForSanityRobo() into [$name] configuration"
}
else -> throw GradleException("Unable to check for sanity, check config type")
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's throw an IllegalStateException and add the config's class name (or just toString() to the message.
This will help with debugging down the line.


private fun FladleConfig.checkAndValidateConfig(name: String = "base", message: (String, String) -> String) {
if (sanityRobo.getOrElse(false)) when {
roboDirectives.isNotPresentOrEmpty -> throw GradleException(message("roboDirectives", name))
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think an IllegalArgumentException might be better here.

}

private fun FladleConfig.checkAndValidateConfig(name: String = "base", message: (String, String) -> String) {
if (sanityRobo.getOrElse(false)) when {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should just get the default value since it is already set to false. Adding a getOrElse(false) here is like adding a second default value.

Suggested change
if (sanityRobo.getOrElse(false)) when {
if (sanityRobo.get()) when {

@runningcode runningcode marked this pull request as ready for review October 1, 2020 19:30
@runningcode
Copy link
Owner

I'm going to merge and fix the rest of the comments on master so we can release this!

@runningcode runningcode merged commit 4fa1199 into runningcode:master Oct 1, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support for Robo Tests without Robo script
2 participants