Use only the hard exit LeaderElectionSpec, see #2113
This commit is contained in:
parent
e3eec7e344
commit
59dd754819
2 changed files with 32 additions and 134 deletions
|
|
@ -1,108 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright (C) 2009-2012 Typesafe Inc. <http://www.typesafe.com>
|
|
||||||
*/
|
|
||||||
|
|
||||||
package akka.cluster
|
|
||||||
|
|
||||||
import com.typesafe.config.ConfigFactory
|
|
||||||
import akka.remote.testkit.MultiNodeConfig
|
|
||||||
import akka.remote.testkit.MultiNodeSpec
|
|
||||||
import akka.testkit._
|
|
||||||
|
|
||||||
object HardExitLeaderElectionMultiJvmSpec extends MultiNodeConfig {
|
|
||||||
val controller = role("controller")
|
|
||||||
val first = role("first")
|
|
||||||
val second = role("second")
|
|
||||||
val third = role("third")
|
|
||||||
val fourth = role("fourth")
|
|
||||||
|
|
||||||
commonConfig(debugConfig(on = false).
|
|
||||||
withFallback(ConfigFactory.parseString("""
|
|
||||||
akka.cluster.auto-down = off
|
|
||||||
""")).
|
|
||||||
withFallback(MultiNodeClusterSpec.clusterConfig))
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
class HardExitLeaderElectionMultiJvmNode1 extends HardExitLeaderElectionSpec
|
|
||||||
class HardExitLeaderElectionMultiJvmNode2 extends HardExitLeaderElectionSpec
|
|
||||||
class HardExitLeaderElectionMultiJvmNode3 extends HardExitLeaderElectionSpec
|
|
||||||
class HardExitLeaderElectionMultiJvmNode4 extends HardExitLeaderElectionSpec
|
|
||||||
class HardExitLeaderElectionMultiJvmNode5 extends HardExitLeaderElectionSpec
|
|
||||||
|
|
||||||
abstract class HardExitLeaderElectionSpec extends MultiNodeSpec(HardExitLeaderElectionMultiJvmSpec) with MultiNodeClusterSpec {
|
|
||||||
import HardExitLeaderElectionMultiJvmSpec._
|
|
||||||
|
|
||||||
override def initialParticipants = 5
|
|
||||||
|
|
||||||
lazy val firstAddress = node(first).address
|
|
||||||
|
|
||||||
// sorted in the order used by the cluster
|
|
||||||
lazy val roles = Seq(first, second, third, fourth).sorted
|
|
||||||
|
|
||||||
"A cluster of four nodes" must {
|
|
||||||
|
|
||||||
"be able to 'elect' a single leader" taggedAs LongRunningTest in {
|
|
||||||
// make sure that the node-to-join is started before other join
|
|
||||||
runOn(first) {
|
|
||||||
cluster
|
|
||||||
}
|
|
||||||
testConductor.enter("first-started")
|
|
||||||
|
|
||||||
if (mySelf != controller) {
|
|
||||||
cluster.join(firstAddress)
|
|
||||||
awaitUpConvergence(numberOfMembers = roles.size)
|
|
||||||
cluster.isLeader must be(mySelf == roles.head)
|
|
||||||
}
|
|
||||||
testConductor.enter("after")
|
|
||||||
}
|
|
||||||
|
|
||||||
def shutdownLeaderAndVerifyNewLeader(alreadyShutdown: Int): Unit = {
|
|
||||||
val currentRoles = roles.drop(alreadyShutdown)
|
|
||||||
currentRoles.size must be >= (2)
|
|
||||||
val leader = currentRoles.head
|
|
||||||
val aUser = currentRoles.last
|
|
||||||
|
|
||||||
mySelf match {
|
|
||||||
|
|
||||||
case `controller` ⇒
|
|
||||||
testConductor.enter("before-shutdown")
|
|
||||||
testConductor.shutdown(leader, 0)
|
|
||||||
testConductor.removeNode(leader)
|
|
||||||
testConductor.enter("after-shutdown", "after-down", "completed")
|
|
||||||
|
|
||||||
case `leader` ⇒
|
|
||||||
testConductor.enter("before-shutdown")
|
|
||||||
// this node will be shutdown by the controller and doesn't participate in more barriers
|
|
||||||
|
|
||||||
case `aUser` ⇒
|
|
||||||
val leaderAddress = node(leader).address
|
|
||||||
testConductor.enter("before-shutdown", "after-shutdown")
|
|
||||||
// user marks the shutdown leader as DOWN
|
|
||||||
cluster.down(leaderAddress)
|
|
||||||
testConductor.enter("after-down", "completed")
|
|
||||||
|
|
||||||
case _ if currentRoles.tail.contains(mySelf) ⇒
|
|
||||||
// remaining cluster nodes, not shutdown
|
|
||||||
testConductor.enter("before-shutdown", "after-shutdown", "after-down")
|
|
||||||
|
|
||||||
awaitUpConvergence(currentRoles.size - 1)
|
|
||||||
val nextExpectedLeader = currentRoles.tail.head
|
|
||||||
cluster.isLeader must be(mySelf == nextExpectedLeader)
|
|
||||||
|
|
||||||
testConductor.enter("completed")
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
"be able to 're-elect' a single leader after leader has left" taggedAs LongRunningTest in {
|
|
||||||
shutdownLeaderAndVerifyNewLeader(alreadyShutdown = 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
"be able to 're-elect' a single leader after leader has left (again)" taggedAs LongRunningTest in {
|
|
||||||
shutdownLeaderAndVerifyNewLeader(alreadyShutdown = 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -10,6 +10,7 @@ import akka.remote.testkit.MultiNodeSpec
|
||||||
import akka.testkit._
|
import akka.testkit._
|
||||||
|
|
||||||
object LeaderElectionMultiJvmSpec extends MultiNodeConfig {
|
object LeaderElectionMultiJvmSpec extends MultiNodeConfig {
|
||||||
|
val controller = role("controller")
|
||||||
val first = role("first")
|
val first = role("first")
|
||||||
val second = role("second")
|
val second = role("second")
|
||||||
val third = role("third")
|
val third = role("third")
|
||||||
|
|
@ -27,11 +28,12 @@ class LeaderElectionMultiJvmNode1 extends LeaderElectionSpec
|
||||||
class LeaderElectionMultiJvmNode2 extends LeaderElectionSpec
|
class LeaderElectionMultiJvmNode2 extends LeaderElectionSpec
|
||||||
class LeaderElectionMultiJvmNode3 extends LeaderElectionSpec
|
class LeaderElectionMultiJvmNode3 extends LeaderElectionSpec
|
||||||
class LeaderElectionMultiJvmNode4 extends LeaderElectionSpec
|
class LeaderElectionMultiJvmNode4 extends LeaderElectionSpec
|
||||||
|
class LeaderElectionMultiJvmNode5 extends LeaderElectionSpec
|
||||||
|
|
||||||
abstract class LeaderElectionSpec extends MultiNodeSpec(LeaderElectionMultiJvmSpec) with MultiNodeClusterSpec {
|
abstract class LeaderElectionSpec extends MultiNodeSpec(LeaderElectionMultiJvmSpec) with MultiNodeClusterSpec {
|
||||||
import LeaderElectionMultiJvmSpec._
|
import LeaderElectionMultiJvmSpec._
|
||||||
|
|
||||||
override def initialParticipants = 4
|
override def initialParticipants = 5
|
||||||
|
|
||||||
lazy val firstAddress = node(first).address
|
lazy val firstAddress = node(first).address
|
||||||
|
|
||||||
|
|
@ -47,47 +49,51 @@ abstract class LeaderElectionSpec extends MultiNodeSpec(LeaderElectionMultiJvmSp
|
||||||
}
|
}
|
||||||
testConductor.enter("first-started")
|
testConductor.enter("first-started")
|
||||||
|
|
||||||
cluster.join(firstAddress)
|
if (mySelf != controller) {
|
||||||
awaitUpConvergence(numberOfMembers = roles.size)
|
cluster.join(firstAddress)
|
||||||
cluster.isLeader must be(mySelf == roles.head)
|
awaitUpConvergence(numberOfMembers = roles.size)
|
||||||
|
cluster.isLeader must be(mySelf == roles.head)
|
||||||
|
}
|
||||||
testConductor.enter("after")
|
testConductor.enter("after")
|
||||||
}
|
}
|
||||||
|
|
||||||
def shutdownLeaderAndVerifyNewLeader(alreadyShutdown: Int): Unit = {
|
def shutdownLeaderAndVerifyNewLeader(alreadyShutdown: Int): Unit = {
|
||||||
val currentRoles = roles.drop(alreadyShutdown)
|
val currentRoles = roles.drop(alreadyShutdown)
|
||||||
currentRoles.size must be >= (2)
|
currentRoles.size must be >= (2)
|
||||||
|
val leader = currentRoles.head
|
||||||
|
val aUser = currentRoles.last
|
||||||
|
|
||||||
runOn(currentRoles.head) {
|
mySelf match {
|
||||||
cluster.shutdown()
|
|
||||||
testConductor.enter("after-shutdown")
|
|
||||||
testConductor.enter("after-down")
|
|
||||||
}
|
|
||||||
|
|
||||||
// runOn previously shutdown cluster nodes
|
case `controller` ⇒
|
||||||
if ((roles diff currentRoles).contains(mySelf)) {
|
testConductor.enter("before-shutdown")
|
||||||
testConductor.enter("after-shutdown")
|
testConductor.shutdown(leader, 0)
|
||||||
testConductor.enter("after-down")
|
testConductor.removeNode(leader)
|
||||||
}
|
testConductor.enter("after-shutdown", "after-down", "completed")
|
||||||
|
|
||||||
// runOn remaining cluster nodes
|
case `leader` ⇒
|
||||||
if (currentRoles.tail.contains(mySelf)) {
|
testConductor.enter("before-shutdown")
|
||||||
|
// this node will be shutdown by the controller and doesn't participate in more barriers
|
||||||
|
|
||||||
testConductor.enter("after-shutdown")
|
case `aUser` ⇒
|
||||||
|
val leaderAddress = node(leader).address
|
||||||
runOn(currentRoles.last) {
|
testConductor.enter("before-shutdown", "after-shutdown")
|
||||||
// user marks the shutdown leader as DOWN
|
// user marks the shutdown leader as DOWN
|
||||||
val leaderAddress = node(currentRoles.head).address
|
|
||||||
cluster.down(leaderAddress)
|
cluster.down(leaderAddress)
|
||||||
}
|
testConductor.enter("after-down", "completed")
|
||||||
|
|
||||||
testConductor.enter("after-down")
|
case _ if currentRoles.tail.contains(mySelf) ⇒
|
||||||
|
// remaining cluster nodes, not shutdown
|
||||||
|
testConductor.enter("before-shutdown", "after-shutdown", "after-down")
|
||||||
|
|
||||||
|
awaitUpConvergence(currentRoles.size - 1)
|
||||||
|
val nextExpectedLeader = currentRoles.tail.head
|
||||||
|
cluster.isLeader must be(mySelf == nextExpectedLeader)
|
||||||
|
|
||||||
|
testConductor.enter("completed")
|
||||||
|
|
||||||
awaitUpConvergence(currentRoles.size - 1)
|
|
||||||
val nextExpectedLeader = currentRoles.tail.head
|
|
||||||
cluster.isLeader must be(mySelf == nextExpectedLeader)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
testConductor.enter("after")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
"be able to 're-elect' a single leader after leader has left" taggedAs LongRunningTest in {
|
"be able to 're-elect' a single leader after leader has left" taggedAs LongRunningTest in {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue