Brought multi-jvm testing doc up-to-date.

This commit is contained in:
Eugene Vigdorchik 2012-01-17 13:04:16 +04:00
parent e5a8b7ae92
commit 16c41269bd

View file

@ -22,17 +22,17 @@ You can add it as a plugin by adding the following to your plugins/build.sbt::
resolvers += Classpaths.typesafeResolver resolvers += Classpaths.typesafeResolver
addSbtPlugin("com.typesafe.sbtmultijvm" % "sbt-multi-jvm" % "0.1.7") addSbtPlugin("com.typesafe.sbtmultijvm" % "sbt-multi-jvm" % "0.1.9")
You can then add multi-JVM testing to a project by including the ``MultiJvm`` You can then add multi-JVM testing to a project by including the ``MultiJvm``
settings and config. For example, here is how the akka-cluster project adds settings and config. For example, here is how the akka-remote project adds
multi-JVM testing:: multi-JVM testing::
import MultiJvmPlugin.{ MultiJvm, extraOptions } import MultiJvmPlugin.{ MultiJvm, extraOptions }
lazy val cluster = Project( lazy val cluster = Project(
id = "akka-cluster", id = "akka-remote",
base = file("akka-cluster"), base = file("akka-remote"),
settings = defaultSettings ++ MultiJvmPlugin.settings ++ Seq( settings = defaultSettings ++ MultiJvmPlugin.settings ++ Seq(
extraOptions in MultiJvm <<= (sourceDirectory in MultiJvm) { src => extraOptions in MultiJvm <<= (sourceDirectory in MultiJvm) { src =>
(name: String) => (src ** (name + ".conf")).get.headOption.map("-Dconfig.file=" + _.absolutePath).toSeq (name: String) => (src ** (name + ".conf")).get.headOption.map("-Dconfig.file=" + _.absolutePath).toSeq
@ -52,26 +52,26 @@ Running tests
The multi-jvm tasks are similar to the normal tasks: ``test``, ``test-only``, The multi-jvm tasks are similar to the normal tasks: ``test``, ``test-only``,
and ``run``, but are under the ``multi-jvm`` configuration. and ``run``, but are under the ``multi-jvm`` configuration.
So in Akka, to run all the multi-JVM tests in the akka-cluster project use (at So in Akka, to run all the multi-JVM tests in the akka-remote project use (at
the sbt prompt): the sbt prompt):
.. code-block:: none .. code-block:: none
akka-cluster/multi-jvm:test akka-remote/multi-jvm:test
Or one can change to the ``akka-cluster`` project first, and then run the Or one can change to the ``akka-remote`` project first, and then run the
tests: tests:
.. code-block:: none .. code-block:: none
project akka-cluster project akka-remote
multi-jvm:test multi-jvm:test
To run individual tests use ``test-only``: To run individual tests use ``test-only``:
.. code-block:: none .. code-block:: none
multi-jvm:test-only akka.cluster.deployment.Deployment multi-jvm:test-only akka.remote.RandomRoutedRemoteActor
More than one test name can be listed to run multiple specific 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. tests. Tab-completion in sbt makes it easy to complete the test names.
@ -81,7 +81,7 @@ options after the test names and ``--``. For example:
.. code-block:: none .. code-block:: none
multi-jvm:test-only akka.cluster.deployment.Deployment -- -Dsome.option=something multi-jvm:test-only akka.remote.RandomRoutedRemoteActor -- -Dsome.option=something
Creating application tests Creating application tests
@ -233,18 +233,23 @@ To run just these tests you would call ``multi-jvm:test-only sample.Spec`` at
the sbt prompt. the sbt prompt.
ZookeeperBarrier Barriers
================ ========
When running multi-JVM tests it's common to need to coordinate timing across When running multi-JVM tests it's common to need to coordinate timing across
nodes. To do this there is a ZooKeeper-based double-barrier (there is both an nodes. To do this, multi-JVM test framework has the notion of a double-barrier
entry barrier and an exit barrier). ClusterNodes also have support for creating (there is both an entry barrier and an exit barrier).
barriers easily. To wait at the entry use the ``enter`` method. To wait at the To wait at the entry use the ``enter`` method. To wait at the
exit use the ``leave`` method. It's also possible t pass a block of code which exit use the ``leave`` method. It's also possible to pass a block of code which
will be run between the barriers. will be run between the barriers.
When creating a barrier you pass it a name and the number of nodes that are There are 2 implementations of the barrier: one is used for coordinating JVMs
expected to arrive at the barrier. You can also pass a timeout. The default running on a single machine and is based on local files, another used in a distributed
scenario (see below) and is based on apache ZooKeeper. These two cases
are differentiated with ``test.hosts`` property defined. The choice for a proper barrier
implementation is made in ``AkkaRemoteSpec`` which is a base class for all multi-JVM tests.
When creating a barrier you pass it a name. You can also pass a timeout. The default
timeout is 60 seconds. timeout is 60 seconds.
Here is an example of coordinating the starting of two nodes and then running Here is an example of coordinating the starting of two nodes and then running
@ -258,21 +263,17 @@ something in coordination::
import akka.cluster._ import akka.cluster._
object SampleMultiJvmSpec { object SampleMultiJvmSpec extends AbstractRemoteActorMultiJvmSpec {
val NrOfNodes = 2 val NrOfNodes = 2
def commonConfig = ConfigFactory.parseString("""
// Declare your configuration here.
""")
} }
class SampleMultiJvmNode1 extends WordSpec with MustMatchers with BeforeAndAfterAll { class SampleMultiJvmNode1 extends AkkaRemoteSpec(SampleMultiJvmSpec.nodeConfigs(0))
with WordSpec with MustMatchers {
import SampleMultiJvmSpec._ import SampleMultiJvmSpec._
override def beforeAll() = {
Cluster.startLocalCluster()
}
override def afterAll() = {
Cluster.shutdownLocalCluster()
}
"A cluster" must { "A cluster" must {
"have jvm options" in { "have jvm options" in {
@ -281,16 +282,15 @@ something in coordination::
} }
"be able to start all nodes" in { "be able to start all nodes" in {
LocalCluster.barrier("start", NrOfNodes) { barrier("start")
Cluster.node.start() println("All nodes are started!")
} barrier("end")
Cluster.node.isRunning must be(true)
Cluster.node.shutdown()
} }
} }
} }
class SampleMultiJvmNode2 extends WordSpec with MustMatchers { class SampleMultiJvmNode2 extends AkkaRemoteSpec(SampleMultiJvmSpec.nodeConfigs(1))
with WordSpec with MustMatchers {
import SampleMultiJvmSpec._ import SampleMultiJvmSpec._
"A cluster" must { "A cluster" must {
@ -301,30 +301,13 @@ something in coordination::
} }
"be able to start all nodes" in { "be able to start all nodes" in {
LocalCluster.barrier("start", NrOfNodes) { barrier("start")
Cluster.node.start() println("All nodes are started!")
} barrier("end")
Cluster.node.isRunning must be(true)
Cluster.node.shutdown()
} }
} }
} }
An example output from this would be:
.. code-block:: none
> multi-jvm:test-only sample.Sample
...
[info] Starting JVM-Node1 for example.SampleMultiJvmNode1
[info] Starting JVM-Node2 for example.SampleMultiJvmNode2
[JVM-Node1] Loading config [akka.conf] from the application classpath.
[JVM-Node2] Loading config [akka.conf] from the application classpath.
...
[JVM-Node2] Hello from node 2
[JVM-Node1] Hello from node 1
[success]
NetworkFailureTest NetworkFailureTest
================== ==================
@ -376,4 +359,8 @@ is deleted.
Each test machine starts a node in zookeeper server ensemble that can be used for synchronization. Since Each test machine starts a node in zookeeper server ensemble that can be used for synchronization. Since
the server is started on a fixed port, it's not currently possible to run more than one test session on the the server is started on a fixed port, it's not currently possible to run more than one test session on the
same machine at the same time. same machine at the same time.
The machines that are used for testing (slaves) should have ssh access to the outside world and be able to talk
to each other with the internal addresses given. On the master machine ssh client is required. Obviosly git
and sbt should be installed on both master and slave machines.