【问题标题】:Is there a simple way to fork a server process in sbt before starting test against that server?在开始对该服务器进行测试之前,是否有一种简单的方法可以在 sbt 中分叉服务器进程?
【发布时间】:2020-09-25 06:39:17
【问题描述】:

我的 e2e 测试任务向服务器发送一些 http 请求。我想在一个单独的 jvm 上启动该服务器(基于 Play 框架),然后启动命中服务器的测试并让它完成,然后停止服务器。

到目前为止,我查看了许多 SO 线程,发现了这些选项:

  1. 使用sbt-sequential
  2. 使用sbt-revolver
  3. 使用alias

但在我的实验中,设置 fork 不起作用,即它仍然会在服务器启动时阻止执行

fork := true
fork in run := true
fork in Test := true
fork in IntegrationTest := true

sbt docs 中的 startServer/stopServer 示例似乎也在阻塞

我也尝试过从 shell 后台启动服务器,但服务器很快关闭,类似于 this question

nohup sbt -Djline.terminal=jline.UnsupportedTerminal web/run  < /dev/null > /tmp/sbt.log 2>&1 &

相关问题:

【问题讨论】:

    标签: scala sbt


    【解决方案1】:

    fork 不会并行运行任务——它只是确保测试在单独的 JVM 中运行,这有助于解决诸如关闭 webhook 或断开无法正确处理资源释放的服务(例如数据库连接从不调用断开连接)。

    如果您想使用相同的 sbt 来启动服务器并针对该实例运行测试(这听起来像是容易破解的反模式 BTW),您可以使用类似的东西:

    • reStart
    • it:test
    • reStop

    但这会很棘手,因为reStart 会立即生成,因此测试会在服务器设置开始但不一定完成时开始。竞态条件、测试失败或阻塞所有测试直到服务器完成启动。

    这就是为什么没有人这样做。更容易处理的解决方案是:

    • 在某些beforeAll 方法中启动测试中的服务器,并仅在服务器响应查询后使该方法完成
    • 使用afterAll 方法将其关闭(或以某种方式使用cats.effect.Resource 或类似方法处理这两种方法)
    • 视情况而定:
      • 按顺序运行测试以避免同时启动两个实例或
      • 为每个测试生成配置,以便它们可以并行运行而不会在端口分配上发生冲突

    其他任何东西都只是一种迟早会失败的黑客行为。

    【讨论】:

      【解决方案2】:

      回答我自己的问题,我们最终做的是

      1. 使用“sbt stage”创建独立服务器 jar 并为 Play 网络应用运行脚本(在 web/target/universal/stage/bin/ 中)
      2. 创建启动服务器的 run_integration_tests.sh shell 脚本,等待 30 秒并开始测试
      3. 在调用run_integration_tests.sh的build.sbt中添加runIntegrationTests任务,并将其添加到其中:test

      run_integration_tests.sh

      #! /bin/bash
      CURDIR=$(pwd)
      echo "Starting integration/e2e test runner"
      date >runner.log
      
      export JAVA_OPTS="-Dplay.server.http.port=9195 -Dconfig.file=$CURDIR/web/conf/application_test.conf  -Xmx2G" 
      
      rm -f "$CURDIR/web/target/universal/stage/RUNNING_PID"
      
      echo "Starting server"
      nohup web/target/universal/stage/bin/myapp >>runner.log 2>&1 &
      
      echo "Webserver PID is $pid"
      echo "Waiting for server start"
      sleep 30
      
      echo "Running the tests"
      sbt "service/test:run-main com.blah.myapp.E2ETest"
      
      ERR="$?"
      echo "Tests Done at $(date), killing server"
      kill $pid
      echo "Waiting for server exit"
      wait $pid
      echo "All done"
      if [ $ERR -ne 0 ]; then
          cat runner.log
          exit "$ERR"
      fi
      

      build.sbt:

      lazy val runIntegrationTests = taskKey[Unit]("Run integration tests")
      runIntegrationTests := {
          val s: TaskStreams = streams.value
          s.log.info("Running integration tests...")
          val shell: Seq[String] = Seq("bash", "-c")
          val runTests: Seq[String] = shell :+ "./run_integration_tests.sh"
          if ((runTests !) == 0) {
              s.log.success("Integration tests successful!")
          } else {
              s.log.error("Integration tests failed!")
              throw new IllegalStateException("Integration tests failed!")
          }
      }
      
      lazy val root = project.in(file("."))
        .aggregate(service, web, tools)
        .configs(IntegrationTest)
        .settings(Defaults.itSettings)
        .settings(
          publishLocal := {},
          publish := {},
          (test in IntegrationTest) := (runIntegrationTests dependsOn (test in IntegrationTest)).value
        )
      

      在 CI/jenkins 中调用 sbt:

        sh 'sbt clean coverage test stage it:test'
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-03-16
        • 2019-10-28
        • 1970-01-01
        • 2012-01-26
        • 1970-01-01
        • 2016-11-08
        • 2017-11-15
        • 1970-01-01
        相关资源
        最近更新 更多