2012-06-01 16:50:56 +02:00
|
|
|
/**
|
2013-01-09 01:47:48 +01:00
|
|
|
* Copyright (C) 2009-2013 Typesafe Inc. <http://www.typesafe.com>
|
2012-06-01 16:50:56 +02:00
|
|
|
*/
|
|
|
|
|
package akka.cluster
|
|
|
|
|
|
|
|
|
|
import scala.collection.immutable.SortedSet
|
|
|
|
|
import com.typesafe.config.ConfigFactory
|
|
|
|
|
import akka.remote.testkit.MultiNodeConfig
|
|
|
|
|
import akka.remote.testkit.MultiNodeSpec
|
|
|
|
|
import akka.testkit._
|
2012-09-21 14:50:06 +02:00
|
|
|
import scala.concurrent.duration._
|
2012-08-14 10:58:30 +02:00
|
|
|
import akka.actor.Props
|
|
|
|
|
import akka.actor.Actor
|
2012-08-30 16:54:55 +02:00
|
|
|
import akka.cluster.MemberStatus._
|
2012-06-01 16:50:56 +02:00
|
|
|
|
|
|
|
|
object NodeLeavingAndExitingMultiJvmSpec extends MultiNodeConfig {
|
|
|
|
|
val first = role("first")
|
|
|
|
|
val second = role("second")
|
|
|
|
|
val third = role("third")
|
|
|
|
|
|
|
|
|
|
commonConfig(
|
|
|
|
|
debugConfig(on = false)
|
2012-06-04 11:58:09 +02:00
|
|
|
.withFallback(ConfigFactory.parseString("""
|
2012-07-03 11:09:34 +02:00
|
|
|
# turn off unreachable reaper
|
|
|
|
|
akka.cluster.unreachable-nodes-reaper-interval = 300 s""")
|
2012-09-06 21:48:40 +02:00
|
|
|
.withFallback(MultiNodeClusterSpec.clusterConfigWithFailureDetectorPuppet)))
|
2012-06-01 16:50:56 +02:00
|
|
|
}
|
|
|
|
|
|
2012-09-06 21:48:40 +02:00
|
|
|
class NodeLeavingAndExitingMultiJvmNode1 extends NodeLeavingAndExitingSpec
|
|
|
|
|
class NodeLeavingAndExitingMultiJvmNode2 extends NodeLeavingAndExitingSpec
|
|
|
|
|
class NodeLeavingAndExitingMultiJvmNode3 extends NodeLeavingAndExitingSpec
|
2012-06-01 16:50:56 +02:00
|
|
|
|
2012-06-04 23:21:28 +02:00
|
|
|
abstract class NodeLeavingAndExitingSpec
|
|
|
|
|
extends MultiNodeSpec(NodeLeavingAndExitingMultiJvmSpec)
|
|
|
|
|
with MultiNodeClusterSpec {
|
|
|
|
|
|
2012-06-01 16:50:56 +02:00
|
|
|
import NodeLeavingAndExitingMultiJvmSpec._
|
2012-08-14 10:58:30 +02:00
|
|
|
import ClusterEvent._
|
2012-06-01 16:50:56 +02:00
|
|
|
|
|
|
|
|
"A node that is LEAVING a non-singleton cluster" must {
|
|
|
|
|
|
2012-06-16 00:01:58 +02:00
|
|
|
"be moved to EXITING by the leader" taggedAs LongRunningTest in {
|
2012-06-01 16:50:56 +02:00
|
|
|
|
2012-06-05 14:13:44 +02:00
|
|
|
awaitClusterUp(first, second, third)
|
2012-06-01 16:50:56 +02:00
|
|
|
|
|
|
|
|
runOn(first, third) {
|
2012-07-03 11:09:34 +02:00
|
|
|
val secondAddess = address(second)
|
|
|
|
|
val exitingLatch = TestLatch()
|
2012-08-14 10:58:30 +02:00
|
|
|
cluster.subscribe(system.actorOf(Props(new Actor {
|
|
|
|
|
def receive = {
|
2012-08-30 16:54:55 +02:00
|
|
|
case state: CurrentClusterState ⇒
|
|
|
|
|
if (state.members.exists(m ⇒ m.address == secondAddess && m.status == Exiting))
|
|
|
|
|
exitingLatch.countDown()
|
2012-08-19 20:15:22 +02:00
|
|
|
case MemberExited(m) if m.address == secondAddess ⇒ exitingLatch.countDown()
|
2012-10-01 20:08:21 +02:00
|
|
|
case MemberRemoved(m) ⇒ // not tested here
|
2012-08-19 20:15:22 +02:00
|
|
|
|
2012-07-03 11:09:34 +02:00
|
|
|
}
|
2012-08-19 20:15:22 +02:00
|
|
|
})), classOf[MemberEvent])
|
2012-07-03 11:09:34 +02:00
|
|
|
enterBarrier("registered-listener")
|
|
|
|
|
|
|
|
|
|
runOn(third) {
|
|
|
|
|
cluster.leave(second)
|
|
|
|
|
}
|
|
|
|
|
enterBarrier("second-left")
|
|
|
|
|
|
2012-08-19 20:15:22 +02:00
|
|
|
val expectedAddresses = roles.toSet map address
|
2013-03-24 22:01:57 +01:00
|
|
|
awaitAssert(clusterView.members.map(_.address) must be(expectedAddresses))
|
2012-08-19 20:15:22 +02:00
|
|
|
|
2012-07-03 11:09:34 +02:00
|
|
|
// Verify that 'second' node is set to EXITING
|
|
|
|
|
exitingLatch.await
|
|
|
|
|
|
|
|
|
|
}
|
2012-06-01 16:50:56 +02:00
|
|
|
|
2012-07-03 11:09:34 +02:00
|
|
|
// node that is leaving
|
|
|
|
|
runOn(second) {
|
|
|
|
|
enterBarrier("registered-listener")
|
|
|
|
|
enterBarrier("second-left")
|
2012-06-01 16:50:56 +02:00
|
|
|
}
|
|
|
|
|
|
2012-06-15 14:39:47 +02:00
|
|
|
enterBarrier("finished")
|
2012-06-01 16:50:56 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|