2017-05-10 16:20:38 +02:00
|
|
|
# Multi JVM Testing
|
2011-05-19 10:58:30 +02:00
|
|
|
|
2012-09-21 12:30:05 +02:00
|
|
|
Supports running applications (objects with main methods) and ScalaTest tests in multiple JVMs at the same time.
|
|
|
|
|
Useful for integration testing where multiple systems communicate with each other.
|
2011-07-13 11:03:49 +12:00
|
|
|
|
2017-05-10 16:20:38 +02:00
|
|
|
## Setup
|
2011-07-13 11:03:49 +12:00
|
|
|
|
2017-05-10 16:20:38 +02:00
|
|
|
The multi-JVM testing is an sbt plugin that you can find at [http://github.com/sbt/sbt-multi-jvm](http://github.com/sbt/sbt-multi-jvm).
|
2011-07-13 11:03:49 +12:00
|
|
|
|
2012-09-20 21:50:35 +02:00
|
|
|
You can add it as a plugin by adding the following to your project/plugins.sbt:
|
2011-07-13 11:03:49 +12:00
|
|
|
|
2017-05-11 11:59:28 +03:00
|
|
|
@@snip [plugins.sbt]($akka$/project/plugins.sbt) { #sbt-multi-jvm }
|
2011-07-13 11:03:49 +12:00
|
|
|
|
2017-05-10 16:20:38 +02:00
|
|
|
You can then add multi-JVM testing to `build.sbt` or `project/Build.scala` by including the `MultiJvm`
|
|
|
|
|
settings and config. Please note that MultiJvm test sources are located in `src/multi-jvm/...`,
|
|
|
|
|
and not in `src/test/...`.
|
2012-11-01 11:04:05 +01:00
|
|
|
|
2017-05-10 16:20:38 +02:00
|
|
|
You can specify JVM options for the forked JVMs:
|
2011-05-19 10:58:30 +02:00
|
|
|
|
2017-05-10 16:20:38 +02:00
|
|
|
```
|
|
|
|
|
jvmOptions in MultiJvm := Seq("-Xmx256M")
|
|
|
|
|
```
|
2011-07-13 11:03:49 +12:00
|
|
|
|
2017-05-10 16:20:38 +02:00
|
|
|
Here is an example of a [sample project](@samples@/tree/master/akka-sample-multi-node-scala) that uses the `sbt-multi-jvm` plugin.
|
2011-07-13 11:03:49 +12:00
|
|
|
|
2017-05-10 16:20:38 +02:00
|
|
|
## Running tests
|
2011-07-13 11:03:49 +12:00
|
|
|
|
2017-05-10 16:20:38 +02:00
|
|
|
The multi-JVM tasks are similar to the normal tasks: `test`, `test-only`,
|
|
|
|
|
and `run`, but are under the `multi-jvm` configuration.
|
2011-07-13 11:03:49 +12:00
|
|
|
|
2012-01-17 13:04:16 +04:00
|
|
|
So in Akka, to run all the multi-JVM tests in the akka-remote project use (at
|
2011-07-13 11:03:49 +12:00
|
|
|
the sbt prompt):
|
|
|
|
|
|
2017-05-10 16:20:38 +02:00
|
|
|
```none
|
|
|
|
|
akka-remote-tests/multi-jvm:test
|
|
|
|
|
```
|
2011-07-13 11:03:49 +12:00
|
|
|
|
2017-05-10 16:20:38 +02:00
|
|
|
Or one can change to the `akka-remote-tests` project first, and then run the
|
2011-07-13 11:03:49 +12:00
|
|
|
tests:
|
2011-05-19 10:58:30 +02:00
|
|
|
|
2017-05-10 16:20:38 +02:00
|
|
|
```none
|
|
|
|
|
project akka-remote-tests
|
|
|
|
|
multi-jvm:test
|
|
|
|
|
```
|
2011-07-13 11:03:49 +12:00
|
|
|
|
2017-05-10 16:20:38 +02:00
|
|
|
To run individual tests use `test-only`:
|
2011-07-13 11:03:49 +12:00
|
|
|
|
2017-05-10 16:20:38 +02:00
|
|
|
```none
|
|
|
|
|
multi-jvm:test-only akka.remote.RandomRoutedRemoteActor
|
|
|
|
|
```
|
2011-07-13 11:03:49 +12:00
|
|
|
|
|
|
|
|
More than one test name can be listed to run multiple specific
|
|
|
|
|
tests. Tab-completion in sbt makes it easy to complete the test names.
|
|
|
|
|
|
2017-05-10 16:20:38 +02:00
|
|
|
It's also possible to specify JVM options with `test-only` by including those
|
|
|
|
|
options after the test names and `--`. For example:
|
2011-07-13 11:03:49 +12:00
|
|
|
|
2017-05-10 16:20:38 +02:00
|
|
|
```none
|
|
|
|
|
multi-jvm:test-only akka.remote.RandomRoutedRemoteActor -- -Dsome.option=something
|
|
|
|
|
```
|
2011-07-13 11:03:49 +12:00
|
|
|
|
2017-05-10 16:20:38 +02:00
|
|
|
## Creating application tests
|
2011-05-19 10:58:30 +02:00
|
|
|
|
2012-11-01 11:04:05 +01:00
|
|
|
The tests are discovered, and combined, through a naming convention. MultiJvm test sources
|
2017-05-10 16:20:38 +02:00
|
|
|
are located in `src/multi-jvm/...`. A test is named with the following pattern:
|
2011-05-19 10:58:30 +02:00
|
|
|
|
2017-05-10 16:20:38 +02:00
|
|
|
```none
|
|
|
|
|
{TestName}MultiJvm{NodeName}
|
|
|
|
|
```
|
2011-05-19 10:58:30 +02:00
|
|
|
|
2017-05-10 16:20:38 +02:00
|
|
|
That is, each test has `MultiJvm` in the middle of its name. The part before
|
|
|
|
|
it groups together tests/applications under a single `TestName` that will run
|
|
|
|
|
together. The part after, the `NodeName`, is a distinguishing name for each
|
2011-05-19 10:58:30 +02:00
|
|
|
forked JVM.
|
|
|
|
|
|
2017-05-10 16:20:38 +02:00
|
|
|
So to create a 3-node test called `Sample`, you can create three applications
|
|
|
|
|
like the following:
|
2011-05-19 10:58:30 +02:00
|
|
|
|
2017-05-10 16:20:38 +02:00
|
|
|
```
|
|
|
|
|
package sample
|
2011-05-19 10:58:30 +02:00
|
|
|
|
2017-05-10 16:20:38 +02:00
|
|
|
object SampleMultiJvmNode1 {
|
|
|
|
|
def main(args: Array[String]) {
|
|
|
|
|
println("Hello from node 1")
|
|
|
|
|
}
|
|
|
|
|
}
|
2011-05-19 10:58:30 +02:00
|
|
|
|
2017-05-10 16:20:38 +02:00
|
|
|
object SampleMultiJvmNode2 {
|
|
|
|
|
def main(args: Array[String]) {
|
|
|
|
|
println("Hello from node 2")
|
|
|
|
|
}
|
|
|
|
|
}
|
2011-05-19 10:58:30 +02:00
|
|
|
|
2017-05-10 16:20:38 +02:00
|
|
|
object SampleMultiJvmNode3 {
|
|
|
|
|
def main(args: Array[String]) {
|
|
|
|
|
println("Hello from node 3")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
2011-05-19 10:58:30 +02:00
|
|
|
|
2017-05-10 16:20:38 +02:00
|
|
|
When you call `multi-jvm:run sample.Sample` at the sbt prompt, three JVMs will be
|
2011-05-19 10:58:30 +02:00
|
|
|
spawned, one for each node. It will look like this:
|
|
|
|
|
|
2017-05-10 16:20:38 +02:00
|
|
|
```none
|
|
|
|
|
> multi-jvm:run sample.Sample
|
|
|
|
|
...
|
|
|
|
|
[info] * sample.Sample
|
|
|
|
|
[JVM-1] Hello from node 1
|
|
|
|
|
[JVM-2] Hello from node 2
|
|
|
|
|
[JVM-3] Hello from node 3
|
|
|
|
|
[success] Total time: ...
|
|
|
|
|
```
|
2011-05-19 10:58:30 +02:00
|
|
|
|
2017-05-10 16:20:38 +02:00
|
|
|
## Changing Defaults
|
2012-11-01 11:04:05 +01:00
|
|
|
|
2014-02-07 22:31:45 -05:00
|
|
|
You can change the name of the multi-JVM test source directory by adding the following
|
2012-11-01 11:04:05 +01:00
|
|
|
configuration to your project:
|
|
|
|
|
|
2017-05-10 16:20:38 +02:00
|
|
|
```none
|
|
|
|
|
unmanagedSourceDirectories in MultiJvm <<=
|
|
|
|
|
Seq(baseDirectory(_ / "src/some_directory_here")).join
|
|
|
|
|
```
|
2011-05-19 10:58:30 +02:00
|
|
|
|
2017-05-10 16:20:38 +02:00
|
|
|
You can change what the `MultiJvm` identifier is. For example, to change it to
|
|
|
|
|
`ClusterTest` use the `multiJvmMarker` setting:
|
2012-11-01 11:04:05 +01:00
|
|
|
|
2017-05-10 16:20:38 +02:00
|
|
|
```none
|
|
|
|
|
multiJvmMarker in MultiJvm := "ClusterTest"
|
|
|
|
|
```
|
2011-05-19 10:58:30 +02:00
|
|
|
|
2017-05-10 16:20:38 +02:00
|
|
|
Your tests should now be named `{TestName}ClusterTest{NodeName}`.
|
2011-05-19 10:58:30 +02:00
|
|
|
|
2017-05-10 16:20:38 +02:00
|
|
|
## Configuration of the JVM instances
|
2011-05-23 10:45:53 +02:00
|
|
|
|
|
|
|
|
You can define specific JVM options for each of the spawned JVMs. You do that by creating
|
2017-05-10 16:20:38 +02:00
|
|
|
a file named after the node in the test with suffix `.opts` and put them in the same
|
2011-05-23 22:35:01 +02:00
|
|
|
directory as the test.
|
2011-05-23 10:45:53 +02:00
|
|
|
|
2017-05-10 16:20:38 +02:00
|
|
|
For example, to feed the JVM options `-Dakka.remote.port=9991` and `-Xmx256m` to the `SampleMultiJvmNode1`
|
|
|
|
|
let's create three `*.opts` files and add the options to them. Separate multiple options with
|
2014-02-05 09:46:42 +01:00
|
|
|
space.
|
2011-05-23 10:45:53 +02:00
|
|
|
|
2017-05-10 16:20:38 +02:00
|
|
|
`SampleMultiJvmNode1.opts`:
|
2011-05-23 10:45:53 +02:00
|
|
|
|
2017-05-10 16:20:38 +02:00
|
|
|
```
|
|
|
|
|
-Dakka.remote.port=9991 -Xmx256m
|
|
|
|
|
```
|
2011-05-23 10:45:53 +02:00
|
|
|
|
2017-05-10 16:20:38 +02:00
|
|
|
`SampleMultiJvmNode2.opts`:
|
2011-05-23 10:45:53 +02:00
|
|
|
|
2017-05-10 16:20:38 +02:00
|
|
|
```
|
|
|
|
|
-Dakka.remote.port=9992 -Xmx256m
|
|
|
|
|
```
|
2011-05-23 10:45:53 +02:00
|
|
|
|
2017-05-10 16:20:38 +02:00
|
|
|
`SampleMultiJvmNode3.opts`:
|
2011-05-23 10:45:53 +02:00
|
|
|
|
2017-05-10 16:20:38 +02:00
|
|
|
```
|
|
|
|
|
-Dakka.remote.port=9993 -Xmx256m
|
|
|
|
|
```
|
2011-05-23 10:45:53 +02:00
|
|
|
|
2017-05-10 16:20:38 +02:00
|
|
|
## ScalaTest
|
2011-05-19 10:58:30 +02:00
|
|
|
|
|
|
|
|
There is also support for creating ScalaTest tests rather than applications. To
|
|
|
|
|
do this use the same naming convention as above, but create ScalaTest suites
|
|
|
|
|
rather than objects with main methods. You need to have ScalaTest on the
|
2017-05-10 16:20:38 +02:00
|
|
|
classpath. Here is a similar example to the one above but using ScalaTest:
|
2011-05-19 10:58:30 +02:00
|
|
|
|
2017-05-10 16:20:38 +02:00
|
|
|
```
|
|
|
|
|
package sample
|
2011-05-19 10:58:30 +02:00
|
|
|
|
2017-05-10 16:20:38 +02:00
|
|
|
import org.scalatest.WordSpec
|
|
|
|
|
import org.scalatest.matchers.MustMatchers
|
2011-05-19 10:58:30 +02:00
|
|
|
|
2017-05-10 16:20:38 +02:00
|
|
|
class SpecMultiJvmNode1 extends WordSpec with MustMatchers {
|
|
|
|
|
"A node" should {
|
|
|
|
|
"be able to say hello" in {
|
|
|
|
|
val message = "Hello from node 1"
|
|
|
|
|
message must be("Hello from node 1")
|
2011-05-19 10:58:30 +02:00
|
|
|
}
|
2017-05-10 16:20:38 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class SpecMultiJvmNode2 extends WordSpec with MustMatchers {
|
|
|
|
|
"A node" should {
|
|
|
|
|
"be able to say hello" in {
|
|
|
|
|
val message = "Hello from node 2"
|
|
|
|
|
message must be("Hello from node 2")
|
2011-05-19 10:58:30 +02:00
|
|
|
}
|
2017-05-10 16:20:38 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
2011-05-19 10:58:30 +02:00
|
|
|
|
2017-05-10 16:20:38 +02:00
|
|
|
To run just these tests you would call `multi-jvm:test-only sample.Spec` at
|
2011-07-13 11:03:49 +12:00
|
|
|
the sbt prompt.
|
2012-09-20 21:50:35 +02:00
|
|
|
|
2017-05-10 16:20:38 +02:00
|
|
|
## Multi Node Additions
|
2017-02-14 13:10:23 +02:00
|
|
|
|
2017-05-10 16:20:38 +02:00
|
|
|
There has also been some additions made to the `SbtMultiJvm` plugin to accommodate the
|
|
|
|
|
@ref:[may change](../common/may-change.md) module @ref:[multi node testing](multi-node-testing.md),
|
2017-05-10 19:45:13 +02:00
|
|
|
described in that section.
|