【问题标题】:Why does Maven Surefire 3 fail to run my Cucumber test in Jenkins with Docker?为什么 Maven Surefire 3 无法使用 Docker 在 Jenkins 中运行我的 Cucumber 测试?
【发布时间】:2019-05-07 13:38:51
【问题描述】:

我有一个 Java 项目,其中包含一些 Cucumber 测试和一些常规 JUnit 测试,由 Maven 管理。

我想使用 Docker 在 Jenkins 中运行测试,所以我写了这个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'
                }
            }
        }
    }
}

当我运行构建时,常规测试通过但 Cucumber 测试失败:

错误信息

URI 有一个查询组件

堆栈跟踪

java.lang.IllegalArgumentException: URI 有一个查询组件

直到我为maven-surefire-plugin 禁用trimStackTrace,我才得到详细信息:

<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)

这很令人费解,因为:

  • 在本地运行 mvn verify 时,它可以工作
  • Dockerfile 中使用agent any 时,它可以工作,而不是maven Docker 映像
  • 当使用maven-surefire-plugin 版本2.22.2 而不是3.0.0-M3 时,它可以工作

我以 Jenkins 身份登录并查看了工作区:

$ sudo su - jenkins

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

那里有一个问号 (?) 目录,它包含 .m2 目录,其中包含项目所需的所有工件。 我怀疑这可能是导致异常的原因,因为类路径中有问号,而问号是引入 URI 的查询组件的。

目前我可以降级到maven-surefire-plugin 版本2.22.2 作为解决方法。 但这里的实际问题是什么?

  • 这可能是新maven-surefire-plugin 中的错误吗?从堆栈跟踪来看,我不会打赌。
  • 是 Jenkins 还是 Maven docker 映像(哪个?)中的问题导致目录具有如此不幸的名称?
  • 我做错了吗?

如果你想试试这个,我有a MVCE。 在我的本地 Jenkins 安装中,我创建了一个类型为“Multibranch Pipeline”的新项目,并在“Branch Sources”中添加了我的本地 git 项目作为 git 项目存储库。没有其他变化。

【问题讨论】:

  • 尝试设置您的 user.home java 系统属性 [export _JAVA_OPTIONS=-Duser.home=/home/user]
  • 我刚刚尝试将Jenkinsfile 中的步骤替换为sh 'MAVEN_OPTS="-Duser.home=/var/lib/jenkins" mvn clean verify ...'。我收到一条错误消息,提示“无法在 /var/lib/jenkins/.m2/repository 创建本地存储库”。
  • 绝对是一个 Maven 问题。你得理清为什么maven会创建一个问号目录。最简单的方法是以调试模式启动 maven 并附加调试器。

标签: java maven docker jenkins cucumber-jvm


【解决方案1】:

通过结合 TYY 的 comment to the questiondocumentation of the maven docker image,我能够以一种避免创建问号目录的方式配置 Jenkinsfile

我们需要通知 Maven 用户的主目录,并将其映射到容器外的目录。

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 将主机上的/var/lib/jenkins 目录映射到容器内的/usr/src/mymaven 目录
  • -w /usr/src/mymaven 设置容器内的工作目录
  • MAVEN_OPTS="-Duser.home=/usr/src/mymaven" 为 Maven 设置 user.home Java 属性

证明它有效,在 MCVE 的 a branch 上。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-09
    • 2020-05-08
    相关资源
    最近更新 更多