2018-10-29 17:19:37 +08:00
|
|
|
/*
|
2021-01-08 17:55:38 +01:00
|
|
|
* Copyright (C) 2009-2021 Lightbend Inc. <https://www.lightbend.com>
|
2012-06-26 09:33:46 +02:00
|
|
|
*/
|
2018-04-24 16:03:55 +01:00
|
|
|
|
2012-06-26 09:33:46 +02:00
|
|
|
package akka.cluster
|
|
|
|
|
|
2020-04-27 20:32:18 +08:00
|
|
|
import scala.concurrent.duration._
|
2012-07-26 14:47:21 +02:00
|
|
|
|
2012-06-26 09:33:46 +02:00
|
|
|
import com.typesafe.config.ConfigFactory
|
2020-04-27 20:32:18 +08:00
|
|
|
import language.postfixOps
|
|
|
|
|
|
2012-06-26 09:33:46 +02:00
|
|
|
import akka.remote.testkit.MultiNodeConfig
|
|
|
|
|
import akka.remote.testkit.MultiNodeSpec
|
2012-12-12 12:20:54 +01:00
|
|
|
import akka.remote.transport.ThrottlerTransportAdapter.Direction
|
2020-04-27 20:32:18 +08:00
|
|
|
import akka.testkit._
|
2012-06-26 09:33:46 +02:00
|
|
|
|
2014-03-07 13:20:01 +01:00
|
|
|
final case class SplitBrainMultiNodeConfig(failureDetectorPuppet: Boolean) extends MultiNodeConfig {
|
2012-06-26 09:33:46 +02:00
|
|
|
val first = role("first")
|
|
|
|
|
val second = role("second")
|
|
|
|
|
val third = role("third")
|
|
|
|
|
val fourth = role("fourth")
|
|
|
|
|
val fifth = role("fifth")
|
|
|
|
|
|
2019-10-03 14:08:43 +02:00
|
|
|
commonConfig(
|
|
|
|
|
debugConfig(on = false)
|
|
|
|
|
.withFallback(ConfigFactory.parseString("""
|
2013-04-09 16:59:30 +02:00
|
|
|
akka.remote.retry-gate-closed-for = 3 s
|
2012-06-26 09:33:46 +02:00
|
|
|
akka.cluster {
|
2019-10-03 14:08:43 +02:00
|
|
|
downing-provider-class = akka.cluster.testkit.AutoDowning
|
|
|
|
|
testkit.auto-down-unreachable-after = 1s
|
2012-06-26 09:33:46 +02:00
|
|
|
failure-detector.threshold = 4
|
2019-10-03 14:08:43 +02:00
|
|
|
}"""))
|
|
|
|
|
.withFallback(MultiNodeClusterSpec.clusterConfig(failureDetectorPuppet)))
|
2012-10-05 14:52:18 +02:00
|
|
|
|
|
|
|
|
testTransport(on = true)
|
2012-06-26 09:33:46 +02:00
|
|
|
}
|
|
|
|
|
|
2012-09-06 21:48:40 +02:00
|
|
|
class SplitBrainWithFailureDetectorPuppetMultiJvmNode1 extends SplitBrainSpec(failureDetectorPuppet = true)
|
|
|
|
|
class SplitBrainWithFailureDetectorPuppetMultiJvmNode2 extends SplitBrainSpec(failureDetectorPuppet = true)
|
|
|
|
|
class SplitBrainWithFailureDetectorPuppetMultiJvmNode3 extends SplitBrainSpec(failureDetectorPuppet = true)
|
|
|
|
|
class SplitBrainWithFailureDetectorPuppetMultiJvmNode4 extends SplitBrainSpec(failureDetectorPuppet = true)
|
|
|
|
|
class SplitBrainWithFailureDetectorPuppetMultiJvmNode5 extends SplitBrainSpec(failureDetectorPuppet = true)
|
2012-06-26 09:33:46 +02:00
|
|
|
|
2012-09-06 21:48:40 +02:00
|
|
|
class SplitBrainWithAccrualFailureDetectorMultiJvmNode1 extends SplitBrainSpec(failureDetectorPuppet = false)
|
|
|
|
|
class SplitBrainWithAccrualFailureDetectorMultiJvmNode2 extends SplitBrainSpec(failureDetectorPuppet = false)
|
|
|
|
|
class SplitBrainWithAccrualFailureDetectorMultiJvmNode3 extends SplitBrainSpec(failureDetectorPuppet = false)
|
|
|
|
|
class SplitBrainWithAccrualFailureDetectorMultiJvmNode4 extends SplitBrainSpec(failureDetectorPuppet = false)
|
|
|
|
|
class SplitBrainWithAccrualFailureDetectorMultiJvmNode5 extends SplitBrainSpec(failureDetectorPuppet = false)
|
2012-06-26 09:33:46 +02:00
|
|
|
|
2012-09-06 21:48:40 +02:00
|
|
|
abstract class SplitBrainSpec(multiNodeConfig: SplitBrainMultiNodeConfig)
|
2019-03-11 10:38:24 +01:00
|
|
|
extends MultiNodeSpec(multiNodeConfig)
|
|
|
|
|
with MultiNodeClusterSpec {
|
2012-06-26 09:33:46 +02:00
|
|
|
|
2012-09-06 21:48:40 +02:00
|
|
|
def this(failureDetectorPuppet: Boolean) = this(SplitBrainMultiNodeConfig(failureDetectorPuppet))
|
|
|
|
|
|
|
|
|
|
import multiNodeConfig._
|
2012-06-26 09:33:46 +02:00
|
|
|
|
2012-10-01 20:08:21 +02:00
|
|
|
muteMarkingAsUnreachable()
|
|
|
|
|
|
2012-10-30 15:08:41 +01:00
|
|
|
val side1 = Vector(first, second)
|
|
|
|
|
val side2 = Vector(third, fourth, fifth)
|
2012-06-26 09:33:46 +02:00
|
|
|
|
2013-01-04 11:44:12 +01:00
|
|
|
"A cluster of 5 members" must {
|
2012-06-26 09:33:46 +02:00
|
|
|
|
|
|
|
|
"reach initial convergence" taggedAs LongRunningTest in {
|
|
|
|
|
awaitClusterUp(first, second, third, fourth, fifth)
|
|
|
|
|
|
|
|
|
|
enterBarrier("after-1")
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-11 10:38:24 +01:00
|
|
|
"detect network partition and mark nodes on other side as unreachable and form new cluster" taggedAs LongRunningTest in within(
|
|
|
|
|
30 seconds) {
|
2012-06-26 09:33:46 +02:00
|
|
|
enterBarrier("before-split")
|
|
|
|
|
|
|
|
|
|
runOn(first) {
|
|
|
|
|
// split the cluster in two parts (first, second) / (third, fourth, fifth)
|
2019-02-09 15:25:39 +01:00
|
|
|
for (role1 <- side1; role2 <- side2) {
|
2012-06-26 09:33:46 +02:00
|
|
|
testConductor.blackhole(role1, role2, Direction.Both).await
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
enterBarrier("after-split")
|
|
|
|
|
|
|
|
|
|
runOn(side1: _*) {
|
2019-02-09 15:25:39 +01:00
|
|
|
for (role <- side2) markNodeAsUnavailable(role)
|
2013-09-11 16:09:51 +02:00
|
|
|
// auto-down
|
2019-03-11 10:38:24 +01:00
|
|
|
awaitMembersUp(side1.size, side2.toSet.map(address))
|
2012-06-26 09:33:46 +02:00
|
|
|
assertLeader(side1: _*)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
runOn(side2: _*) {
|
2019-02-09 15:25:39 +01:00
|
|
|
for (role <- side1) markNodeAsUnavailable(role)
|
2013-09-11 16:09:51 +02:00
|
|
|
// auto-down
|
2019-03-11 10:38:24 +01:00
|
|
|
awaitMembersUp(side2.size, side1.toSet.map(address))
|
2012-06-26 09:33:46 +02:00
|
|
|
assertLeader(side2: _*)
|
|
|
|
|
}
|
|
|
|
|
|
2013-03-05 15:32:13 +01:00
|
|
|
enterBarrier("after-2")
|
2012-06-26 09:33:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|