How do I start a server before running a test suite in SBT?

孤人 提交于 2021-02-19 04:23:07

问题


Problem is that if I do test in Test <<= (taskA, taskB) { (A, B) => A doFinally B or test in Test := (taskB dependsOn taskA).value and taskA is forked, then sbt execution doesn't continue to taskB and get's stuck indefinitely. It's caused by doFinally/dependsOn, because they probably makes it a single-threaded sequential execution. But I can't find any other way to order those 2 tasks, to make them run sequentially.

So far I've gotten this far :

lazy val startServer = taskKey[Unit]("Start PingPong Server before running Scala-JS tests")

lazy val jvm =
     project.in(file("jvm"))
        fork in (Test, runMain) := true
        startServer := {
          (runMain in Test).toTask(" com.example.PingPong").value
        }
      )

lazy val js =
    project.in(file("js"))
       test in Test <<= (startServer in Project("jvm", file("jvm")), test in(Test, fastOptStage)) {
         (startServer, test) => startServer doFinally test
       }
     )

The sbt execution stops on a task startServer that spawns a thread, even a daemon one. I tried fork in startServer := true but it didn't help.

I also tried dependsOn, but it also blocks :

test in Test := {
  (test in(Test, fastOptStage)).dependsOn(startServer in Project("jvm", file("jvm"))).value
}

If I do not start the server in the main class PingPong, it behaves as expected. Also if I do this, it works but it has a random order of execution and I don't know how to enforce it without doFinally.

test in Test := {
  (startServer in Project("jvm", file("jvm"))).value
  (test in(Test, fastOptStage)).value
}

I think I'm gonna have to try sbt-sequential or fork a new process.


回答1:


Instead of dealing with SBT I can suggest much more simple workaround. Create Class with static method to start server (it will check that server is not yet started), and in each test explicitly start this server. You'll need to set "fork in Test := true", to run server in separate JVM and shutdown it after tests finished.

I use this approach for starting Embedded Cassandra server for integration tests

In my case it's static method with Java, you can do the same with Scala and companion object.

  override def beforeAll() {
    log.info(s"Start Embedded Cassandra Server")
    EmbeddedCassandraServerHelper.startEmbeddedCassandra("/timeseries.yaml")
  }

and

public static void startEmbeddedCassandra(String yamlFile, String tmpDir) throws TTransportException, IOException, ConfigurationException {
        if (cassandraDaemon != null) {
            /* nothing to do Cassandra is already started */
            return;
        }

     // ... Start new server
}



回答2:


For some reason none of these settings forks a new process :

fork := true
fork in runMain := true
fork in Test := true
fork in (Test, runMain) := true

That's why sequential dependsOn/doFinally blocks because the process is not forked...

I tried exactly the same with revolver and it works. I recommend revolver to everybody who is trying to fork a process in sbt, because one can't rely the sbt's fork at least from this experience.

lazy val startServer = taskKey[Unit]("Start PingPong Server before running JS tests")

lazy val jvm =
     project.in(file("jvm"))
        mainClass in Revolver.reStart := Option("com.example.PingPong"),
        startServer := {
          (Revolver.reStart in Test).toTask("").value
        }
      )

lazy val js =
    project.in(file("js"))
       test in Test := (test in(Test, fastOptStage)).dependsOn(startServer in Project("jvm", file("jvm"))).value
     )


来源:https://stackoverflow.com/questions/25766797/how-do-i-start-a-server-before-running-a-test-suite-in-sbt

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!