2019-09-30 06:38:26 -07:00
---
2023-01-18 08:13:01 +01:00
project.description: Multi node testing of distributed systems built with Pekko.
2019-09-30 06:38:26 -07:00
---
2017-05-10 16:20:38 +02:00
# Multi Node Testing
2012-09-20 21:50:35 +02:00
2019-11-05 20:06:32 +01:00
## Module info
2018-05-15 18:44:33 +09:00
To use Multi Node Testing, you must add the following dependency in your project:
@@dependency [sbt,Maven,Gradle] {
2023-01-05 11:10:50 +01:00
bomGroup=org.apache.pekko bomArtifact=pekko-bom_$scala.binary.version$ bomVersionSymbols=PekkoVersion
2022-12-02 14:49:16 +01:00
symbol1=PekkoVersion
2022-12-02 04:53:48 -08:00
value1="$pekko.version$"
2022-12-03 14:18:18 +01:00
group=org.apache.pekko
2023-01-05 11:10:50 +01:00
artifact=pekko-multi-node-testkit_$scala.binary.version$
2022-12-02 14:49:16 +01:00
version=PekkoVersion
2020-12-04 13:26:42 +01:00
scope=test
2018-05-15 18:44:33 +09:00
}
2023-01-05 11:10:50 +01:00
@@project -info{ projectId="multi-node-testkit" }
2019-11-05 20:06:32 +01:00
2017-05-10 16:20:38 +02:00
## Multi Node Testing Concepts
2012-09-20 21:50:35 +02:00
2023-01-18 08:13:01 +01:00
When we talk about multi node testing in Pekko we mean the process of running coordinated tests on multiple actor
2012-09-21 12:30:05 +02:00
systems in different JVMs. The multi node testing kit consist of three main parts.
2012-09-20 21:50:35 +02:00
2019-10-01 15:29:12 +02:00
* @ref: [The Test Conductor ](#the-test-conductor ). that coordinates and controls the nodes under test.
2022-01-03 10:06:54 +02:00
* @ref: [The Multi Node Spec ](#the-multi-node-spec ). that is a convenience wrapper for starting the @apidoc [TestConductor$] and letting all
2017-05-10 16:20:38 +02:00
nodes connect to it.
2019-10-01 15:29:12 +02:00
* @ref: [The SbtMultiJvm Plugin ](#the-sbtmultijvm-plugin ). that starts tests in multiple JVMs possibly on multiple machines.
2012-09-20 21:50:35 +02:00
2017-05-10 16:20:38 +02:00
## The Test Conductor
2012-09-20 21:50:35 +02:00
2023-01-20 09:40:34 +00:00
The basis for the multi node testing is the @apidoc [TestConductor$]. It is a Pekko Extension that plugs in to the
2012-09-20 21:50:35 +02:00
network stack and it is used to coordinate the nodes participating in the test and provides several features
including:
2017-05-10 16:20:38 +02:00
* Node Address Lookup: Finding out the full path to another test node (No need to share configuration between
test nodes)
* Node Barrier Coordination: Waiting for other nodes at named barriers.
* Network Failure Injection: Throttling traffic, dropping packets, unplugging and plugging nodes back in.
2012-09-20 21:50:35 +02:00
This is a schematic overview of the test conductor.
2023-01-18 08:13:01 +01:00

2012-09-20 21:50:35 +02:00
The test conductor server is responsible for coordinating barriers and sending commands to the test conductor
2012-10-04 11:03:07 +02:00
clients that act upon them, e.g. throttling network traffic to/from another client. More information on the
2022-11-12 10:21:24 +01:00
possible operations is available in the @apidoc [remote.testconductor.Conductor ](Conductor ) API documentation.
2012-09-20 21:50:35 +02:00
2017-05-10 16:20:38 +02:00
## The Multi Node Spec
2012-09-20 21:50:35 +02:00
2022-01-03 10:06:54 +02:00
The Multi Node Spec consists of two parts. The @apidoc [MultiNodeConfig] that is responsible for common
2017-05-10 16:20:38 +02:00
configuration and enumerating and naming the nodes under test. The `MultiNodeSpec` that contains a number
2012-10-04 11:03:07 +02:00
of convenience functions for making the test nodes interact with each other. More information on the possible
2022-11-12 10:21:24 +01:00
operations is available in the @apidoc [remote.testkit.MultiNodeSpec ](MultiNodeSpec ) API documentation.
2012-09-20 21:50:35 +02:00
2017-05-10 16:20:38 +02:00
The setup of the `MultiNodeSpec` is configured through java system properties that you set on all JVMs that's going to run a
2018-05-15 08:11:03 +02:00
node under test. These can be set on the JVM command line with `-Dproperty=value` .
2012-09-20 21:50:35 +02:00
These are the available properties:
2017-05-10 16:20:38 +02:00
:
*
`multinode.max-nodes`
The maximum number of nodes that a test can have.
*
`multinode.host`
The host name or IP for this node. Must be resolvable using InetAddress.getByName.
*
`multinode.port`
The port number for this node. Defaults to 0 which will use a random port.
*
`multinode.server-host`
The host name or IP for the server node. Must be resolvable using InetAddress.getByName.
*
`multinode.server-port`
The port number for the server node. Defaults to 4711.
*
`multinode.index`
The index of this node in the sequence of roles defined for the test. The index 0 is special and that machine
will be the server. All failure injection and throttling must be done from this node.
## The SbtMultiJvm Plugin
The @ref: [SbtMultiJvm Plugin ](multi-jvm-testing.md ) has been updated to be able to run multi node tests, by
2018-05-15 08:11:03 +02:00
automatically generating the relevant `multinode.*` properties. This means that you can run multi node tests
on a single machine without any special configuration by running them as normal multi-jvm tests. These tests can
then be run distributed over multiple machines without any changes by using the multi-node additions to the
2012-09-21 12:30:05 +02:00
plugin.
2012-09-20 21:50:35 +02:00
2017-05-10 16:20:38 +02:00
### Multi Node Specific Additions
2012-09-20 21:50:35 +02:00
2017-05-10 16:20:38 +02:00
The plugin also has a number of new `multi-node-*` sbt tasks and settings to support running tests on multiple
2012-09-20 21:50:35 +02:00
machines. The necessary test classes and dependencies are packaged for distribution to other machines with
2017-05-10 16:20:38 +02:00
[SbtAssembly ](https://github.com/sbt/sbt-assembly ) into a jar file with a name on the format
`<projectName>_<scalaVersion>-<projectVersion>-multi-jvm-assembly.jar`
2012-09-20 21:50:35 +02:00
2017-05-10 16:20:38 +02:00
@@@ note
2012-09-20 21:50:35 +02:00
2017-05-10 16:20:38 +02:00
To be able to distribute and kick off the tests on multiple machines, it is assumed that both host and target
systems are POSIX like systems with `ssh` and `rsync` available.
2012-09-20 21:50:35 +02:00
2017-05-10 16:20:38 +02:00
@@@
2012-09-20 21:50:35 +02:00
2017-05-10 16:20:38 +02:00
These are the available sbt multi-node settings:
:
*
`multiNodeHosts`
A sequence of hosts to use for running the test, on the form `user@host:java` where host is the only required
part. Will override settings from file.
*
`multiNodeHostsFileName`
A file to use for reading in the hosts to use for running the test. One per line on the same format as above.
Defaults to `multi-node-test.hosts` in the base project directory.
*
`multiNodeTargetDirName`
A name for the directory on the target machine, where to copy the jar file. Defaults to `multi-node-test` in
the base directory of the ssh user used to rsync the jar file.
*
`multiNodeJavaName`
The name of the default Java executable on the target machines. Defaults to `java` .
2012-09-20 21:50:35 +02:00
Here are some examples of how you define hosts:
2017-05-10 16:20:38 +02:00
:
*
`localhost`
The current user on localhost using the default java.
*
`user1@host1`
User `user1` on host `host1` with the default java.
*
`user2@host2:/usr/lib/jvm/java-7-openjdk-amd64/bin/java`
User `user2` on host `host2` using java 7.
*
`host3:/usr/lib/jvm/java-6-openjdk-amd64/bin/java`
The current user on host `host3` using java 6.
### Running the Multi Node Tests
2012-09-20 21:50:35 +02:00
2012-09-21 12:30:05 +02:00
To run all the multi node test in multi-node mode (i.e. distributing the jar files and kicking off the tests
2017-11-09 09:16:30 +01:00
remotely) from inside sbt, use the `multiNodeTest` task:
2012-09-20 21:50:35 +02:00
2017-05-10 16:20:38 +02:00
```none
2017-11-09 09:16:30 +01:00
multiNodeTest
2017-05-10 16:20:38 +02:00
```
2012-09-20 21:50:35 +02:00
2012-09-21 12:30:05 +02:00
To run all of them in multi-jvm mode (i.e. all JVMs on the local machine) do:
2017-05-10 16:20:38 +02:00
```none
multi-jvm:test
```
2012-09-20 21:50:35 +02:00
2017-11-09 09:16:30 +01:00
To run individual tests use the `multiNodeTestOnly` task:
2012-09-20 21:50:35 +02:00
2017-05-10 16:20:38 +02:00
```none
2017-11-09 09:16:30 +01:00
multiNodeTestOnly your.MultiNodeTest
2017-05-10 16:20:38 +02:00
```
2012-09-21 12:30:05 +02:00
To run individual tests in the multi-jvm mode do:
2017-05-10 16:20:38 +02:00
```none
2017-11-09 09:16:30 +01:00
multi-jvm:testOnly your.MultiNodeTest
2017-05-10 16:20:38 +02:00
```
2012-09-20 21:50:35 +02: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
## A Multi Node Testing Example
2012-09-20 21:50:35 +02:00
2022-01-03 10:06:54 +02:00
First we need some scaffolding to hook up the @apidoc [MultiNodeSpec] with your favorite test framework. Lets define a trait
2017-05-10 16:20:38 +02:00
`STMultiNodeSpec` that uses ScalaTest to start and stop `MultiNodeSpec` .
2012-09-20 21:50:35 +02:00
2023-01-05 11:10:50 +01:00
@@snip [STMultiNodeSpec.scala ](/remote-tests/src/test/scala/org/apache/pekko/remote/testkit/STMultiNodeSpec.scala ) { #example }
2012-09-20 21:50:35 +02:00
2017-05-10 16:20:38 +02:00
Then we need to define a configuration. Lets use two nodes `"node1` and `"node2"` and call it
`MultiNodeSampleConfig` .
2012-09-20 21:50:35 +02:00
2023-01-05 11:10:50 +01:00
@@snip [MultiNodeSample.scala ](/remote-tests/src/multi-jvm/scala/org/apache/pekko/remote/sample/MultiNodeSample.scala ) { #package #config }
2012-09-20 21:50:35 +02:00
2012-09-21 12:30:05 +02:00
And then finally to the node test code. That starts the two nodes, and demonstrates a barrier, and a remote actor
2012-09-20 21:50:35 +02:00
message send/receive.
2023-01-05 11:10:50 +01:00
@@snip [MultiNodeSample.scala ](/remote-tests/src/multi-jvm/scala/org/apache/pekko/remote/sample/MultiNodeSample.scala ) { #package #spec }
2012-09-21 12:30:05 +02:00
2017-05-10 16:20:38 +02:00
## Things to Keep in Mind
2012-09-21 12:30:05 +02:00
There are a couple of things to keep in mind when writing multi node tests or else your tests might behave in
surprising ways.
2017-05-10 16:20:38 +02:00
* Don't issue a shutdown of the first node. The first node is the controller and if it shuts down your test will break.
* To be able to use `blackhole` , `passThrough` , and `throttle` you must activate the failure injector and
2022-11-12 10:21:24 +01:00
throttler transport adapters by specifying @scala [@scaladoc[testTransport(on = true) ](pekko.remote.testkit.MultiNodeConfig#testTransport(on:Boolean ):Unit)]@java [@javadoc[testTransport(true) ](pekko.remote.testkit.MultiNodeConfig#testTransport(boolean ))] in your `MultiNodeConfig` .
2017-05-10 16:20:38 +02:00
* Throttling, shutdown and other failure injections can only be done from the first node, which again is the controller.
* Don't ask for the address of a node using `node(address)` after the node has been shut down. Grab the address before
shutting down the node.
* Don't use MultiNodeSpec methods like address lookup, barrier entry et.c. from other threads than the main test
thread. This also means that you shouldn't use them from inside an actor, a future, or a scheduled task.
2012-09-21 12:30:05 +02:00
2017-05-10 16:20:38 +02:00
## Configuration
2014-03-23 18:39:55 +01:00
There are several configuration properties for the Multi-Node Testing module, please refer
2023-01-18 08:13:01 +01:00
to the @ref: [reference configuration ](general/configuration-reference.md#config-pekko-multi-node-testkit ).