lisak
lisak

Reputation: 21981

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

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.

Upvotes: 3

Views: 1431

Answers (2)

lisak
lisak

Reputation: 21981

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
     )

Upvotes: 2

Eugene Zhulenev
Eugene Zhulenev

Reputation: 9734

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
}

Upvotes: 2

Related Questions