2

I'm working on a project which uses a combination of Windows, Java, Groovy, Gradle and Cucumber. This combination gives me some problems on my Windows machine that my *NIX colleagues are not experiencing. Upon running the gradle build, gradle wants to output some reports. The location and filename of these reports is apparently determined by the definition or output of the Cucumber tests. The name used is unfortunately not something that can be used as a filename, so I'm getting an IOException for each test report.

For the Cucumber test, we use the following structure:

  Scenario Outline: Receive and parse ReturnItem from Service
    Given The message from service return item outlined in <messagePath>
    When We process the message
    Then XXX posted a message to YYY on topic <topic> with event <eventType>
    And payload matches <resultPath>

 | messagePath               | topic      | eventType  | resultPath                 |
 | /test/testxml.xml         | test_topic | EVENT_TYPE | /result/result.json        |

After running this, I receive the following exception:

Caused by: org.gradle.api.UncheckedIOException: Could not write to file 'C:\xxx\project\build\reports\tests\test\packages\| \test\testxml.xml | test_topic | EVENT_TYPE | \result\result.html'.
        at org.gradle.internal.IoActions$TextFileWriterIoAction.execute(IoActions.java:151)
        at org.gradle.internal.IoActions$TextFileWriterIoAction.execute(IoActions.java:127)
        at org.gradle.internal.IoActions.writeTextFile(IoActions.java:45)
        at org.gradle.reporting.HtmlReportRenderer$DefaultHtmlReportContext.renderHtmlPage(HtmlReportRenderer.java:118)
        at org.gradle.api.internal.tasks.testing.report.DefaultTestReport$HtmlReportFileGenerator.run(DefaultTestReport.java:147)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:300)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:292)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:174)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor.access$900(DefaultBuildOperationExecutor.java:48)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor$ParentPreservingQueueWorker.execute(DefaultBuildOperationExecutor.java:342)
        at org.gradle.internal.operations.DefaultBuildOperationQueue$WorkerRunnable.runOperation(DefaultBuildOperationQueue.java:230)
        at org.gradle.internal.operations.DefaultBuildOperationQueue$WorkerRunnable.access$600(DefaultBuildOperationQueue.java:172)
        at org.gradle.internal.operations.DefaultBuildOperationQueue$WorkerRunnable$1.call(DefaultBuildOperationQueue.java:209)
        at org.gradle.internal.operations.DefaultBuildOperationQueue$WorkerRunnable$1.call(DefaultBuildOperationQueue.java:203)
        at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:154)
        at org.gradle.internal.operations.DefaultBuildOperationQueue$WorkerRunnable.runBatch(DefaultBuildOperationQueue.java:203)
        at org.gradle.internal.operations.DefaultBuildOperationQueue$WorkerRunnable.run(DefaultBuildOperationQueue.java:177)
        ... 3 more
Caused by: java.io.IOException: Unable to create directory 'C:\xxx\project\project-test\build\reports\tests\test\packages\| \test\testxml.xml | test_topic | EVENT_TYPE | \result'
        at org.gradle.internal.IoActions$TextFileWriterIoAction.execute(IoActions.java:141)
        ... 19 more

Does anybody know how to fix this? The only 'solution' I could come up with is disabling the reports, which works, but is more a workaround than a solution. For disabling I used the following configuration in the gradle.build for this:

    apply plugin: 'java'
    apply plugin: 'groovy'

    test {
        reports {
            junitXml.enabled = false
            html.enabled = false
        }
    }

(Inspired by: How to make Gradle build produce HTML test report instead of XML default?)

Ostecke
  • 749
  • 7
  • 10

2 Answers2

1

Based upon the information provided, it looks like it's trying to create a directory called:

'C:\xxx\project\project-test\build\reports\tests\test\packages\| \test\testxml.xml | test_topic | EVENT_TYPE | \result'

Can you show the code around passing in messagePath? I suspect you are passing in the entire row of data rather than just the messagePath (I'm going to take a wild guess that you are performing a .toString() on an array instead of passing in the first element of the array)

Ardesco
  • 6,897
  • 22
  • 48
  • Thanks for the suggestion, I added the code in the original post. It does not post the whole row to the Cucumber feature, only the messagePath. I suspect that Gradle picks up the whole row though, and tries to use this to generate the test report. – Ostecke Mar 11 '19 at 12:13
  • 1
    Could be this you are suffering from: https://github.com/cucumber/cucumber-jvm/issues/468. What version of cucumber/gradle are you using? – Ardesco Mar 11 '19 at 15:17
  • Your comment led me to investigate the github issue tracker a bit more and search further. This finally led me to the solution which I posted below. Thanks for your time and attention! – Ostecke Mar 11 '19 at 17:08
1

I finally found the culprit. Apparently these filenames correspond to the default behaviour of JUnit for report generation of Cucumber tests. On *NIX, this doesn't provide any problem. On Windows however, this will result in an exception due to the pipes in the Examples. The IOException is somewhat special apparently, since the most exceptions that I found on the internet were FileNotFoundExceptions. That explains why it took me so long to find an answer, I focused on the exception.

The solution here is to use the following JUnitOption as an @CucumberOptions annotation when running the Cucumber tests: --filename-compatible-names.

A code example for Java & Spring looks like this:

@RunWith(Cucumber.class)
@CucumberOptions(junit = {"--filename-compatible-names"})
public class CucumberRunner {
}

It would be nice if these kind of non-breaking OS dependent options would be default instead of optional.

Ostecke
  • 749
  • 7
  • 10