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

Remove failure nodes from tests that passed on retry #798

Conversation

adamfilipow92
Copy link
Contributor

@adamfilipow92 adamfilipow92 commented May 19, 2020

Fixes #796

Checklist

  • Documented
  • Clean up code before mark as ready to review
  • Local merge should contains all error nodes
  • Save CI Report to local fs
  • Upload CI Report to gcs
  • Unit tested
  • release_notes.md updated

release_notes.md Outdated
@@ -1,7 +1,7 @@
## next (unreleased)

- [#779](https://github.com/Flank/flank/pull/779) Print retries & display additional info. ([jan-gogo](https://github.com/jan-gogo))
-
- [#796](https://github.com/Flank/flank/issues/796) Ability to generate XML results with passing re-runs removed. ([adamfilipow92](https://github.com/adamfilipow92))
Copy link
Contributor

Choose a reason for hiding this comment

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

Ability to generate XML results with passing re-runs removed.

In the issue, the problem described is a passing flaky test will have failure nodes. What we want to do is remove failure nodes from flaky tests so that the JUnit CI plugin passes.

I'd reword this to be something like: Remove failure nodes from tests that passed on retry so that Jenkins JUnit plugin marks them as successful.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks I updated description.

<testsuite name="" tests="1" failures="1" errors="0" skipped="0" time="2.676" timestamp="2020-05-19T14:40:18" hostname="localhost">
<properties/>
<testcase name="test" classname="com.example.test_app.InstrumentedTest" time="1.516">
<failure>
Copy link
Contributor

Choose a reason for hiding this comment

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

Let's use an example from the real XML linked to on the Slack thread from the issue.

https://firebase-community.slack.com/files/UAZSWDV4Z/F013EJLR4K1/2020-05-15_23-04-57.325000_yvmd_nexuslowres-23-en-portrait-test_results_merged.xml

I like taking bug reports and then turning them into tests to ensure they don't regress in the future. 🙂

Copy link
Contributor Author

@adamfilipow92 adamfilipow92 May 20, 2020

Choose a reason for hiding this comment

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

I think starting work from falling test is good idea. For me it can help understand problem and it's faster than running full path to reproduce problem every time and as you say we have regress protection. 🙂

@bootstraponline
Copy link
Contributor

Thanks for opening a draft pull request, it's great to get feedback quickly. 🙂

@adamfilipow92 adamfilipow92 force-pushed the #796-Ability-to-generate-XML-results-with-passing-re-runs-removed-#796 branch from 8f9d900 to 046e166 Compare May 21, 2020 11:58
@bootstraponline
Copy link
Contributor

I've been thinking about the use case more.

The current JUnit XML contains all the information which is great. This is used by tools to track test data over time. The downside is Jenkins gets confused. By default, Flank should probably produce two JUnit XMLs. One for Jenkins to read, and another that has the full information that can be uploaded into a test analytics platform.

@adamfilipow92
Copy link
Contributor Author

Right, I will keep original file and produce additional on gcs and on local fs. Additional file will be cleaned from fail nodes when one of tries pass.

@adamfilipow92
Copy link
Contributor Author

adamfilipow92 commented May 22, 2020

I noticed we have a different (probably) merge results in gcs and local fs. Maybe we should have same results in gcs and local storage? The main difference: in local file we have only one failure node and different time in test case.
gcs
<?xml version='1.0' encoding='UTF-8' ?> <testsuite name="" tests="1" failures="1" flakes="0" errors="0" skipped="0" time="2.733" hostname="localhost"> <testcase name="test" classname="com.example.test_app.InstrumentedTest" time="1.587"> <failure>java.lang.AssertionError at org.junit.Assert.fail(Assert.java:86) at org.junit.Assert.assertTrue(Assert.java:41) at org.junit.Assert.assertTrue(Assert.java:52) at com.example.test_app.BaseInstrumentedTest.testMethod(BaseInstrumentedTest.kt:35) at com.example.test_app.InstrumentedTest.test(InstrumentedTest.kt:11) at java.lang.reflect.Method.invoke(Native Method) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) at androidx.test.rule.GrantPermissionRule$RequestPermissionStatement.evaluate(GrantPermissionRule.java:134) at androidx.test.rule.ActivityTestRule$ActivityStatement.evaluate(ActivityTestRule.java:531) at com.example.test_app.screenshot.ScreenshotTestRule$apply$1.evaluate(ScreenshotTestRule.kt:58) at org.junit.rules.RunRules.evaluate(RunRules.java:20) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at androidx.test.ext.junit.runners.AndroidJUnit4.run(AndroidJUnit4.java:104) at org.junit.runners.Suite.runChild(Suite.java:128) at org.junit.runners.Suite.runChild(Suite.java:27) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.junit.runner.JUnitCore.run(JUnitCore.java:137) at org.junit.runner.JUnitCore.run(JUnitCore.java:115) at androidx.test.internal.runner.TestExecutor.execute(TestExecutor.java:56) at androidx.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:392) at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:2145) </failure> <failure>java.lang.AssertionError at org.junit.Assert.fail(Assert.java:86) at org.junit.Assert.assertTrue(Assert.java:41) at org.junit.Assert.assertTrue(Assert.java:52) at com.example.test_app.BaseInstrumentedTest.testMethod(BaseInstrumentedTest.kt:35) at com.example.test_app.InstrumentedTest.test(InstrumentedTest.kt:11) at java.lang.reflect.Method.invoke(Native Method) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) at androidx.test.rule.GrantPermissionRule$RequestPermissionStatement.evaluate(GrantPermissionRule.java:134) at androidx.test.rule.ActivityTestRule$ActivityStatement.evaluate(ActivityTestRule.java:531) at com.example.test_app.screenshot.ScreenshotTestRule$apply$1.evaluate(ScreenshotTestRule.kt:58) at org.junit.rules.RunRules.evaluate(RunRules.java:20) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at androidx.test.ext.junit.runners.AndroidJUnit4.run(AndroidJUnit4.java:104) at org.junit.runners.Suite.runChild(Suite.java:128) at org.junit.runners.Suite.runChild(Suite.java:27) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.junit.runner.JUnitCore.run(JUnitCore.java:137) at org.junit.runner.JUnitCore.run(JUnitCore.java:115) at androidx.test.internal.runner.TestExecutor.execute(TestExecutor.java:56) at androidx.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:392) at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:2145) </failure> <failure>java.lang.AssertionError at org.junit.Assert.fail(Assert.java:86) at org.junit.Assert.assertTrue(Assert.java:41) at org.junit.Assert.assertTrue(Assert.java:52) at com.example.test_app.BaseInstrumentedTest.testMethod(BaseInstrumentedTest.kt:35) at com.example.test_app.InstrumentedTest.test(InstrumentedTest.kt:11) at java.lang.reflect.Method.invoke(Native Method) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) at androidx.test.rule.GrantPermissionRule$RequestPermissionStatement.evaluate(GrantPermissionRule.java:134) at androidx.test.rule.ActivityTestRule$ActivityStatement.evaluate(ActivityTestRule.java:531) at com.example.test_app.screenshot.ScreenshotTestRule$apply$1.evaluate(ScreenshotTestRule.kt:58) at org.junit.rules.RunRules.evaluate(RunRules.java:20) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at androidx.test.ext.junit.runners.AndroidJUnit4.run(AndroidJUnit4.java:104) at org.junit.runners.Suite.runChild(Suite.java:128) at org.junit.runners.Suite.runChild(Suite.java:27) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.junit.runner.JUnitCore.run(JUnitCore.java:137) at org.junit.runner.JUnitCore.run(JUnitCore.java:115) at androidx.test.internal.runner.TestExecutor.execute(TestExecutor.java:56) at androidx.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:392) at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:2145) </failure> </testcase> </testsuite>

and local JUnitReport.xml

<?xml version='1.0' encoding='UTF-8' ?> <testsuites> <testsuite name="NexusLowRes-28-en-portrait" tests="1" failures="1" flakes="0" errors="0" skipped="0" time="2.568" timestamp="2020-05-22T11:56:34" hostname="localhost"> <testcase name="test" classname="com.example.test_app.InstrumentedTest" time="2.568"> <failure>java.lang.AssertionError at org.junit.Assert.fail(Assert.java:86) at org.junit.Assert.assertTrue(Assert.java:41) at org.junit.Assert.assertTrue(Assert.java:52) at com.example.test_app.BaseInstrumentedTest.testMethod(BaseInstrumentedTest.kt:35) at com.example.test_app.InstrumentedTest.test(InstrumentedTest.kt:11) at java.lang.reflect.Method.invoke(Native Method) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) at androidx.test.rule.GrantPermissionRule$RequestPermissionStatement.evaluate(GrantPermissionRule.java:134) at androidx.test.rule.ActivityTestRule$ActivityStatement.evaluate(ActivityTestRule.java:531) at com.example.test_app.screenshot.ScreenshotTestRule$apply$1.evaluate(ScreenshotTestRule.kt:58) at org.junit.rules.RunRules.evaluate(RunRules.java:20) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at androidx.test.ext.junit.runners.AndroidJUnit4.run(AndroidJUnit4.java:104) at org.junit.runners.Suite.runChild(Suite.java:128) at org.junit.runners.Suite.runChild(Suite.java:27) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.junit.runner.JUnitCore.run(JUnitCore.java:137) at org.junit.runner.JUnitCore.run(JUnitCore.java:115) at androidx.test.internal.runner.TestExecutor.execute(TestExecutor.java:56) at androidx.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:392) at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:2145) </failure> <webLink>https://console.firebase.google.com/project/flank-open-source/testlab/histories/bh.da0c237aaa33732/matrices/8157421381839057662/executions/bs.afd77ec424527270/testcases/1</webLink> </testcase> </testsuite> </testsuites>
Let me know what you think.
@bootstraponline @pawelpasterz @jan-gogo @piotradamczyk5

@bootstraponline
Copy link
Contributor

I noticed we have a different (probably) merge results in gcs and local fs. Maybe we should have same results in gcs and local storage? The main difference: in local file we have only one failure node and different time in test case.

I think our merge should ideally match the gcs merge. Maybe Flank is not merging all the information correctly? The times from the API are slightly off from what FTL saves in the XML so that is expected.

import ftl.cli.firebase.test.ios.IosRunCommand
import ftl.config.Device
import ftl.config.FtlConstants
import ftl.ios.IosCatalog
import ftl.ios.Xctestrun
import ftl.run.status.asOutputStyle
import ftl.util.FlankFatalError
import ftl.util.FlankTestMethod
import ftl.util.*
Copy link
Contributor

@bootstraponline bootstraponline May 23, 2020

Choose a reason for hiding this comment

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

I think we have a lint rule against wildcard imports?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, but I not enabling check when pull request is draft. Tell me please if I should commit only checked code even if pull request is a draft. I want make all right :)

Copy link
Contributor

Choose a reason for hiding this comment

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

I think if you adjust your IDE settings then the problem will go away.

It's fine to have code that's not ready yet for a draft PR. 🙂



@CommandLine.Option(
names = ["--ci-junit-result"],
Copy link
Contributor

Choose a reason for hiding this comment

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

I think since the default use case is CI, we probably want to generate this file by default. I'm not sure we need to enable the filename to be customized, we're not providing that option for other generated files.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Alright, I will change it.

file = args.ciJUnitResultFile!!,
fileBytes = testResult.xmlToString().toByteArray(),
rootGcsBucket = args.resultsBucket,
runGcsPath = args.resultsDir!!
Copy link
Contributor

Choose a reason for hiding this comment

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

Is there a better way to handle this without force unwraps? I think the error message might be confusing if the value ends up being null.

@bootstraponline
Copy link
Contributor

To maximize compatibility, I think we should default to writing JUnitReport.xml with the flaky failure nodes removed. Then a flag, full-junit-result: false which defaults to off can be added. If full junit results is set, then we'd produce an additional report JUnitReport_full.xml that includes the full history of the test executions (including failure nodes for flaky tests that ran multiple times and passed on retry).

@adamfilipow92
Copy link
Contributor Author

To maximize compatibility, I think we should default to writing JUnitReport.xml with the flaky failure nodes removed. Then a flag, full-junit-result: false which defaults to off can be added. If full junit results is set, then we'd produce an additional report JUnitReport_full.xml that includes the full history of the test executions (including failure nodes for flaky tests that ran multiple times and passed on retry).

But what with merged file generated on gcs? It's generated outside flank by default. When we add this option we will be have locally one file without fail nodes but on gcs we will have two files (merged and cleared). It will be fine behaviour?

@jan-goral
Copy link
Contributor

But what with merged file generated on gcs? It's generated outside flank by default. When we add this option we will be have locally one file without fail nodes but on gcs we will have two files (merged and cleared). It will be fine behaviour?

There are no conflicts between those two files due to different names. I don't see any reason to touch the xml result generated outside flank

@adamfilipow92
Copy link
Contributor Author

But what with merged file generated on gcs? It's generated outside flank by default. When we add this option we will be have locally one file without fail nodes but on gcs we will have two files (merged and cleared). It will be fine behaviour?

There are no conflicts between those two files due to different names. I don't see any reason to touch the xml result generated outside flank

I don't want touching gcs result. I think about keeping in default two results locally and flag for turn off full result. It can help avoid some user confusion when we keep same amount of results locally and on gcs.
Let me know what you think.

@bootstraponline
Copy link
Contributor

bootstraponline commented May 26, 2020

Here's my understanding of the current state and the desired state. Let me know your thoughts. 🙂

Current State

$ flank --version
version: local_snapshot
revision: e95ac5c67e9c0ae576922845ea2760488a5267a0
gcloud:
  app: ../test_app/apks/app-debug.apk
  test: ./src/test/kotlin/ftl/fixtures/tmp/apk/app-debug-androidTest_155.apk
flank:
  max-test-shards: 2

Google Cloud Storage

  • 2020-05-25/matrix_0/NexusLowRes-28-en-portrait-shard_0/test_result_1.xml
  • 2020-05-25/matrix_0/NexusLowRes-28-en-portrait-shard_1/test_result_1.xml
  • 2020-05-25/matrix_0/NexusLowRes-28-en-portrait-test_results_merged.xml

Flank

  • /results/2020-05-25/JUnitReport.xml
  • /results/2020-05-25/matrix_0/NexusLowRes-28-en-portrait-shard_0/test_result_1.xml
  • /results/2020-05-25/matrix_0/NexusLowRes-28-en-portrait-shard_1/test_result_1.xml

Desired State

Google Cloud Storage

  • 2020-05-25/matrix_0/NexusLowRes-28-en-portrait-shard_0/test_result_1.xml
  • 2020-05-25/matrix_0/NexusLowRes-28-en-portrait-shard_1/test_result_1.xml
  • 2020-05-25/matrix_0/NexusLowRes-28-en-portrait-test_results_merged.xml

Flank

  • /results/2020-05-25/JUnitReport.xml

Flank should use the API to merge all the *-test_results_merged.xml files. Then if the full-junit-result flag is enabled, we'd produce results/JUnitReport_full.xml in addition to results/JUnitReport.xml This is backwards compatible. We'd leave all the other artifacts in the GCS bucket unless the user opts in to downloading them via files-to-download.

There's a ticket to upload all the Flank generated reports to the GCS bucket, however that can be resolved in a dedicated pull request. #750

@adamfilipow92
Copy link
Contributor Author

adamfilipow92 commented May 26, 2020

I thinking about JUnitReportFull as local equivalent of test_results_merged.xml so I wanted generate that in default. But we don't need full JUnitReport in most cases so you have right we should default not generate it. Sorry for this thread but I want fully understand case.

There's a ticket to upload all the Flank generated reports to the GCS bucket, however that can be resolved in a dedicated pull request. #750

Now I have done upload JUnitReport.xml to gcs. It's fine or disable and come back to this in
#750?

@adamfilipow92 adamfilipow92 force-pushed the #796-Ability-to-generate-XML-results-with-passing-re-runs-removed-#796 branch from 40cffae to 9f516e9 Compare May 26, 2020 08:16
@codecov-commenter
Copy link

codecov-commenter commented May 26, 2020

Codecov Report

Merging #798 into master will decrease coverage by 0.59%.
The diff coverage is 42.37%.

Impacted file tree graph

@@             Coverage Diff              @@
##             master     #798      +/-   ##
============================================
- Coverage     78.82%   78.22%   -0.60%     
+ Complexity      669      667       -2     
============================================
  Files           148      149       +1     
  Lines          2966     3004      +38     
  Branches        431      437       +6     
============================================
+ Hits           2338     2350      +12     
- Misses          354      375      +21     
- Partials        274      279       +5     

@adamfilipow92 adamfilipow92 marked this pull request as ready for review May 26, 2020 08:36
@bootstraponline
Copy link
Contributor

Now I have done upload JUnitReport.xml to gcs. It's fine or disable and come back to this in
#750?

I think that's great. #750 is about uploading all the reports Flank generates (not just junit xml) to gcs so that there's a copy in the cloud.

@pawelpasterz
Copy link
Contributor

So to ensure we are on the same page, #750 will be resolved within this PR as well?

@@ -24,5 +21,23 @@ object JUnitReport : IReport {
} else {
write(matrices, output, args)
}

result?.let {
uploadToGcStorage(it, args)
Copy link
Contributor

Choose a reason for hiding this comment

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

Why not call GcStorage.uploadCiJUnitXml directly and pass reportPath(matrices, args).let(::File).name as fileName argument?. Is simpler, there is no needs for override fun reportPath, private fun uploadToGcStorage and val fileName.

Copy link
Contributor Author

@adamfilipow92 adamfilipow92 May 27, 2020

Choose a reason for hiding this comment

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

@jan-gogo you thinking about something like:

GcStorage.uploadCiJUnitXml(result, args, reportPath(matrices, args).let { ::File }.name)

?

I think we don't need execute reportPath because it's inside make additional work
check

  fun reportPath(matrices: MatrixMap, args: IArgs): String {
        val path = resolveLocalRunPath(matrices, args)
        return Paths.get(path, reportName() + extension).toString()
    }

we dont need val path = resolveLocalRunPath(matrices, args)
so maybe make something like:

 private val fileName = "${reportName()}$extension"
    override fun run(matrices: MatrixMap, result: JUnitTestResult?, printToStdout: Boolean, args: IArgs) {
        if(result == null){
            return
        }
        val output = result.xmlToString()

        if (printToStdout) {
            print(output)
        } else {
            write(matrices, output, args)
        }

        GcStorage.uploadCiJUnitXml(result, args, fileName)
    }

or

private fun createReportFileName() = "${reportName()}$extension"
    override fun run(matrices: MatrixMap, result: JUnitTestResult?, printToStdout: Boolean, args: IArgs) {
        if(result == null){
            return
        }
        val output = result.xmlToString()

        if (printToStdout) {
            print(output)
        } else {
            write(matrices, output, args)
        }

        GcStorage.uploadCiJUnitXml(result, args, createReportFileName())
    }

Tell me what do you think please.

Copy link
Contributor

@jan-goral jan-goral May 27, 2020

Choose a reason for hiding this comment

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

not GcStorage.uploadCiJUnitXml(result, args, reportPath(matrices, args).let { ::File }.name)
but GcStorage.uploadCiJUnitXml(result, args, reportPath(matrices, args).let(::File).name)

I know that it make additional operations, but it's small impact on performance, and gives less additional code to maintain.

@@ -10,3 +10,11 @@ internal fun List<TestExecution>.createJUnitTestResult() = JUnitTestResult(
.createJUnitTestSuites()
.toMutableList()
)

internal fun List<TestExecution>.createJUnitTestResultForCi() = JUnitTestResult(
Copy link
Contributor

Choose a reason for hiding this comment

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

Instead of duplicating code here and in 2 other places you can do something like this:

internal fun List<TestExecution>.createJUnitTestResult(
    withStackTraces: Boolean = true
) = JUnitTestResult(
    testsuites = this
        .createTestExecutionDataListAsync()
        .prepareForJUnitResult()
        .let { executionDataList ->
            if (withStackTraces) executionDataList
            else executionDataList.removeStackTraces()
        }
        .createJUnitTestSuites()
        .toMutableList()
)

I think replacing 3 functions for argument + condition is good trade off. Less duplicated code to maintain.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Right, I will change it.

@@ -1,3 +1,4 @@
gcloud:
test: ./src/test/kotlin/ftl/fixtures/tmp/earlgrey_example.zip
xctestrun-file: ./src/test/kotlin/ftl/fixtures/tmp/EarlGreyExampleSwiftTests_iphoneos13.4-arm64e.xctestrun
results-dir: test_dir
Copy link
Contributor

Choose a reason for hiding this comment

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

Empty line

@adamfilipow92 adamfilipow92 force-pushed the #796-Ability-to-generate-XML-results-with-passing-re-runs-removed-#796 branch from d1297b2 to cab9686 Compare May 27, 2020 14:23
@bootstraponline
Copy link
Contributor

So to ensure we are on the same page, #750 will be resolved within this PR as well?

My preference is for one PR to solve one issue so that the PR is smaller and easier to review. It's not a hard requirement though. If it's a simple change we can resolve #750 in this PR.

@adamfilipow92
Copy link
Contributor Author

So to ensure we are on the same page, #750 will be resolved within this PR as well?

My preference is for one PR to solve one issue so that the PR is smaller and easier to review. It's not a hard requirement though. If it's a simple change we can resolve #750 in this PR.

This pr have started review so I prefer solve #750 in other pr. As you say smaller pr == better. But it's only my point of view. So tell me please what you think.

@bootstraponline
Copy link
Contributor

This pr have started review so I prefer solve #750 in other pr. As you say smaller pr == better. But it's only my point of view. So tell me please what you think.

Sounds good, let's save #750 for a new PR.

@bootstraponline bootstraponline changed the title #796 Ability to generate XML results with passing re-runs removed Remove failure nodes from tests that passed on retry May 27, 2020
@@ -11,6 +11,10 @@ internal fun List<TestExecutionData>.prepareForJUnitResult(): List<TestExecution
.reduceToPrimarySteps()
.reduceTestCases()

internal fun List<TestExecutionData>.prepareJUnitResultForCi() = this
Copy link
Contributor

Choose a reason for hiding this comment

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

Delete unused function

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

@@ -199,4 +199,10 @@ abstract class CommonRunCommand {
"which don't support ansi codes, to avoid corrupted output use `single` or `verbose`."]
)
var outputStyle: String? = null

@CommandLine.Option(
names = ["--full-junit-result"],
Copy link
Contributor

Choose a reason for hiding this comment

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

When you are adding new option you should update also flank.yml, flank.ios.yml and README.md.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

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.

Ability to generate XML results with passing re-runs removed
5 participants