user479288
user479288

Reputation:

Why does Maven Surefire 3 fail to run my Cucumber test in Jenkins with Docker?

I have a Java project with some Cucumber tests and some regular JUnit tests, managed by Maven.

I want to run the tests in Jenkins, using Docker, so I wrote this Jenkinsfile:

pipeline {
    agent {
        docker {
            image 'maven:3.6.1'
        }
    }
    stages {
        stage('build') {
            steps {
                sh 'mvn clean verify -Dmaven.test.failure.ignore=true'
            }
            post {
                success {
                    junit 'target/surefire-reports/**/*.xml'
                }
            }
        }
    }
}

When I run the build, the regular tests pass but the Cucumber tests fail with:

Error Message

URI has a query component

Stacktrace

java.lang.IllegalArgumentException: URI has a query component

It's not until I disable trimStackTrace for maven-surefire-plugin that I also get the details:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <configuration>
        <trimStackTrace>false</trimStackTrace>
    </configuration>
</plugin>
java.lang.IllegalArgumentException: URI has a query component
    at java.base/java.io.File.<init>(File.java:427)
    at cucumber.runtime.io.ZipResourceIterator.<init>(ZipResourceIterator.java:22)
    at cucumber.runtime.io.ZipResourceIteratorFactory.createIterator(ZipResourceIteratorFactory.java:24)
    at cucumber.runtime.io.ZipThenFileResourceIteratorFactory.createIterator(ZipThenFileResourceIteratorFactory.java:22)
    at cucumber.runtime.io.DelegatingResourceIteratorFactory.createIterator(DelegatingResourceIteratorFactory.java:49)
    at cucumber.runtime.io.ClasspathResourceIterable.iterator(ClasspathResourceIterable.java:35)
    at cucumber.runtime.io.ResourceLoaderClassFinder.getDescendants(ResourceLoaderClassFinder.java:25)
    at cucumber.runtime.Reflections.instantiateSubclasses(Reflections.java:34)
    at cucumber.runtime.BackendModuleBackendSupplier.loadBackends(BackendModuleBackendSupplier.java:52)
    at cucumber.runtime.BackendModuleBackendSupplier.get(BackendModuleBackendSupplier.java:39)
    at cucumber.runner.ThreadLocalRunnerSupplier.createRunner(ThreadLocalRunnerSupplier.java:42)
    at cucumber.runner.ThreadLocalRunnerSupplier.access$000(ThreadLocalRunnerSupplier.java:13)
    at cucumber.runner.ThreadLocalRunnerSupplier$1.initialValue(ThreadLocalRunnerSupplier.java:22)
    at cucumber.runner.ThreadLocalRunnerSupplier$1.initialValue(ThreadLocalRunnerSupplier.java:19)
    at java.base/java.lang.ThreadLocal.setInitialValue(ThreadLocal.java:195)
    at java.base/java.lang.ThreadLocal.get(ThreadLocal.java:172)
    at cucumber.runner.ThreadLocalRunnerSupplier.get(ThreadLocalRunnerSupplier.java:38)
    at cucumber.api.junit.Cucumber$RunCucumber.evaluate(Cucumber.java:146)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:365)
    at org.apache.maven.surefire.junit4.JUnit4Provider.executeWithRerun(JUnit4Provider.java:273)
    at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:238)
    at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:159)
    at org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:384)
    at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:345)
    at org.apache.maven.surefire.booter.ForkedBooter.execute(ForkedBooter.java:126)
    at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:418)

This is quite puzzling because:

I logged in as Jenkins and looked in the workspace:

$ sudo su - jenkins

$ ls /var/lib/jenkins/workspace/question-mark-dir_master
'?'   Jenkinsfile   LICENSE   pom.xml   README.md   src   target

There's a question mark (?) directory in there, and it contains the .m2 directory, with all the artifacts needed by the project. I suspect this could be the cause of the exception, because then there are question marks in the classpath, and question marks are the ones who introduce the query component of URIs.

For the moment I can downgrade to maven-surefire-plugin version 2.22.2 as a workaround. But what is the actual problem here?

If you want to try this out, I have a MVCE. In my local Jenkins installation, I created a new project of type "Multibranch Pipeline" and in "Branch Sources" I added as the git project repository my local git project. No other changes.

screenshot

Upvotes: 1

Views: 968

Answers (1)

user479288
user479288

Reputation:

By combining TYY's comment to the question and the documentation of the maven docker image, I was able to configure the Jenkinsfile in a way that avoids creating a question mark directory.

We need to inform Maven of the user's home directory, and map that to a directory outside the container.

pipeline {
    agent {
        docker {
            image 'maven:3.6.1'
            args '-v /var/lib/jenkins:/usr/src/mymaven -w /usr/src/mymaven'
        }
    }
    stages {
        stage('build') {
            steps {
                sh 'MAVEN_OPTS="-Duser.home=/usr/src/mymaven" mvn clean verify -Dmaven.test.failure.ignore=true'
            }
            // ...
        }
    }
}
  • -v /var/lib/jenkins:/usr/src/mymaven maps the /var/lib/jenkins directory on the host to the /usr/src/mymaven directory inside the container
  • -w /usr/src/mymaven sets the working directory inside the container
  • MAVEN_OPTS="-Duser.home=/usr/src/mymaven" sets the user.home Java property for Maven

Proof that it works, on a branch of the MCVE.

Upvotes: 2

Related Questions