Allow barrier timeouts to be shortened and other review fixes

This commit is contained in:
Björn Antonsson 2012-06-15 14:39:47 +02:00
parent b52da8d588
commit fd42c3d49a
32 changed files with 395 additions and 267 deletions

View file

@ -47,23 +47,23 @@ abstract class ClientDowningNodeThatIsUnreachableSpec
// mark 'third' node as DOWN
cluster.down(thirdAddress)
enter("down-third-node")
enterBarrier("down-third-node")
awaitUpConvergence(numberOfMembers = 3, canNotBePartOfMemberRing = Seq(thirdAddress))
cluster.latestGossip.members.exists(_.address == thirdAddress) must be(false)
}
runOn(third) {
enter("down-third-node")
enterBarrier("down-third-node")
}
runOn(second, fourth) {
enter("down-third-node")
enterBarrier("down-third-node")
awaitUpConvergence(numberOfMembers = 3, canNotBePartOfMemberRing = Seq(thirdAddress))
}
enter("await-completion")
enterBarrier("await-completion")
}
}
}

View file

@ -43,7 +43,7 @@ abstract class ClientDowningNodeThatIsUpSpec
runOn(first) {
// mark 'third' node as DOWN
cluster.down(thirdAddress)
enter("down-third-node")
enterBarrier("down-third-node")
markNodeAsUnavailable(thirdAddress)
@ -52,16 +52,16 @@ abstract class ClientDowningNodeThatIsUpSpec
}
runOn(third) {
enter("down-third-node")
enterBarrier("down-third-node")
}
runOn(second, fourth) {
enter("down-third-node")
enterBarrier("down-third-node")
awaitUpConvergence(numberOfMembers = 3, canNotBePartOfMemberRing = Seq(thirdAddress))
}
enter("await-completion")
enterBarrier("await-completion")
}
}
}

View file

@ -46,12 +46,12 @@ abstract class ConvergenceSpec
// doesn't join immediately
}
enter("after-1")
enterBarrier("after-1")
}
"not reach convergence while any nodes are unreachable" taggedAs LongRunningTest ignore {
val thirdAddress = node(third).address
enter("before-shutdown")
enterBarrier("before-shutdown")
runOn(first) {
// kill 'third' node
@ -78,7 +78,7 @@ abstract class ConvergenceSpec
}
}
enter("after-2")
enterBarrier("after-2")
}
"not move a new joining node to Up while there is no convergence" taggedAs LongRunningTest ignore {
@ -116,7 +116,7 @@ abstract class ConvergenceSpec
}
}
enter("after-3")
enterBarrier("after-3")
}
}
}

View file

@ -43,7 +43,7 @@ abstract class GossipingAccrualFailureDetectorSpec
cluster.failureDetector.isAvailable(secondAddress) must be(true)
cluster.failureDetector.isAvailable(thirdAddress) must be(true)
enter("after-1")
enterBarrier("after-1")
}
"mark node as 'unavailable' if a node in the cluster is shut down (and its heartbeats stops)" taggedAs LongRunningTest in {
@ -59,7 +59,7 @@ abstract class GossipingAccrualFailureDetectorSpec
cluster.failureDetector.isAvailable(secondAddress) must be(true)
}
enter("after-2")
enterBarrier("after-2")
}
}
}

View file

@ -46,7 +46,7 @@ abstract class LeaderDowningNodeThatIsUnreachableSpec
runOn(first) {
// kill 'fourth' node
testConductor.shutdown(fourth, 0)
enter("down-fourth-node")
enterBarrier("down-fourth-node")
// mark the node as unreachable in the failure detector
markNodeAsUnavailable(fourthAddress)
@ -57,26 +57,26 @@ abstract class LeaderDowningNodeThatIsUnreachableSpec
}
runOn(fourth) {
enter("down-fourth-node")
enterBarrier("down-fourth-node")
}
runOn(second, third) {
enter("down-fourth-node")
enterBarrier("down-fourth-node")
awaitUpConvergence(numberOfMembers = 3, canNotBePartOfMemberRing = Seq(fourthAddress), 30.seconds)
}
enter("await-completion-1")
enterBarrier("await-completion-1")
}
"be able to DOWN a 'middle' node that is UNREACHABLE" taggedAs LongRunningTest in {
val secondAddress = node(second).address
enter("before-down-second-node")
enterBarrier("before-down-second-node")
runOn(first) {
// kill 'second' node
testConductor.shutdown(second, 0)
enter("down-second-node")
enterBarrier("down-second-node")
// mark the node as unreachable in the failure detector
markNodeAsUnavailable(secondAddress)
@ -87,16 +87,16 @@ abstract class LeaderDowningNodeThatIsUnreachableSpec
}
runOn(second) {
enter("down-second-node")
enterBarrier("down-second-node")
}
runOn(third) {
enter("down-second-node")
enterBarrier("down-second-node")
awaitUpConvergence(numberOfMembers = 2, canNotBePartOfMemberRing = Seq(secondAddress), 30 seconds)
}
enter("await-completion-2")
enterBarrier("await-completion-2")
}
}
}

View file

@ -50,7 +50,7 @@ abstract class LeaderElectionSpec
assertLeaderIn(sortedRoles)
}
enter("after")
enterBarrier("after")
}
def shutdownLeaderAndVerifyNewLeader(alreadyShutdown: Int): Unit = {
@ -64,33 +64,33 @@ abstract class LeaderElectionSpec
case `controller`
val leaderAddress = node(leader).address
enter("before-shutdown")
enterBarrier("before-shutdown")
testConductor.shutdown(leader, 0)
enter("after-shutdown", "after-down", "completed")
enterBarrier("after-shutdown", "after-down", "completed")
markNodeAsUnavailable(leaderAddress)
case `leader`
enter("before-shutdown", "after-shutdown")
enterBarrier("before-shutdown", "after-shutdown")
// this node will be shutdown by the controller and doesn't participate in more barriers
case `aUser`
val leaderAddress = node(leader).address
enter("before-shutdown", "after-shutdown")
enterBarrier("before-shutdown", "after-shutdown")
// user marks the shutdown leader as DOWN
cluster.down(leaderAddress)
enter("after-down", "completed")
enterBarrier("after-down", "completed")
markNodeAsUnavailable(leaderAddress)
case _ if remainingRoles.contains(myself)
// remaining cluster nodes, not shutdown
enter("before-shutdown", "after-shutdown", "after-down")
enterBarrier("before-shutdown", "after-shutdown", "after-down")
awaitUpConvergence(currentRoles.size - 1)
val nextExpectedLeader = remainingRoles.head
cluster.isLeader must be(myself == nextExpectedLeader)
assertLeaderIn(remainingRoles)
enter("completed")
enterBarrier("completed")
}
}

View file

@ -47,12 +47,12 @@ abstract class MembershipChangeListenerExitingSpec
awaitClusterUp(first, second, third)
runOn(first) {
enter("registered-listener")
enterBarrier("registered-listener")
cluster.leave(secondAddress)
}
runOn(second) {
enter("registered-listener")
enterBarrier("registered-listener")
}
runOn(third) {
@ -63,11 +63,11 @@ abstract class MembershipChangeListenerExitingSpec
exitingLatch.countDown()
}
})
enter("registered-listener")
enterBarrier("registered-listener")
exitingLatch.await
}
enter("finished")
enterBarrier("finished")
}
}
}

View file

@ -45,19 +45,19 @@ abstract class MembershipChangeListenerJoinSpec
joinLatch.countDown()
}
})
enter("registered-listener")
enterBarrier("registered-listener")
joinLatch.await
}
runOn(second) {
enter("registered-listener")
enterBarrier("registered-listener")
cluster.join(firstAddress)
}
awaitUpConvergence(2)
enter("after")
enterBarrier("after")
}
}
}

View file

@ -44,12 +44,12 @@ abstract class MembershipChangeListenerLeavingSpec
awaitClusterUp(first, second, third)
runOn(first) {
enter("registered-listener")
enterBarrier("registered-listener")
cluster.leave(secondAddress)
}
runOn(second) {
enter("registered-listener")
enterBarrier("registered-listener")
}
runOn(third) {
@ -62,11 +62,11 @@ abstract class MembershipChangeListenerLeavingSpec
latch.countDown()
}
})
enter("registered-listener")
enterBarrier("registered-listener")
latch.await
}
enter("finished")
enterBarrier("finished")
}
}
}

View file

@ -46,16 +46,16 @@ abstract class MembershipChangeListenerUpSpec
latch.countDown()
}
})
enter("listener-1-registered")
enterBarrier("listener-1-registered")
cluster.join(firstAddress)
latch.await
}
runOn(third) {
enter("listener-1-registered")
enterBarrier("listener-1-registered")
}
enter("after-1")
enterBarrier("after-1")
}
"(when three nodes) after cluster convergence updates the membership table then all MembershipChangeListeners should be triggered" taggedAs LongRunningTest in {
@ -68,7 +68,7 @@ abstract class MembershipChangeListenerUpSpec
latch.countDown()
}
})
enter("listener-2-registered")
enterBarrier("listener-2-registered")
runOn(third) {
cluster.join(firstAddress)
@ -76,7 +76,7 @@ abstract class MembershipChangeListenerUpSpec
latch.await
enter("after-2")
enterBarrier("after-2")
}
}
}

View file

@ -71,14 +71,14 @@ trait MultiNodeClusterSpec extends FailureDetectorStrategy { self: MultiNodeSpec
// make sure that the node-to-join is started before other join
startClusterNode()
}
enter(roles.head.name + "-started")
enterBarrier(roles.head.name + "-started")
if (roles.tail.contains(myself)) {
cluster.join(node(roles.head).address)
}
if (upConvergence && roles.contains(myself)) {
awaitUpConvergence(numberOfMembers = roles.length)
}
enter(roles.map(_.name).mkString("-") + "-joined")
enterBarrier(roles.map(_.name).mkString("-") + "-joined")
}
/**

View file

@ -45,7 +45,7 @@ abstract class NodeJoinSpec
awaitCond(cluster.latestGossip.members.exists { member member.address == secondAddress && member.status == MemberStatus.Joining })
enter("after")
enterBarrier("after")
}
}
}

View file

@ -44,7 +44,7 @@ abstract class NodeLeavingAndExitingAndBeingRemovedSpec
runOn(first) {
cluster.leave(secondAddress)
}
enter("second-left")
enterBarrier("second-left")
runOn(first, third) {
// verify that the 'second' node is no longer part of the 'members' set
@ -59,7 +59,7 @@ abstract class NodeLeavingAndExitingAndBeingRemovedSpec
isRemoved.get.address must be(secondAddress)
}
enter("finished")
enterBarrier("finished")
}
}
}

View file

@ -50,7 +50,7 @@ abstract class NodeLeavingAndExitingSpec
runOn(first) {
cluster.leave(secondAddress)
}
enter("second-left")
enterBarrier("second-left")
runOn(first, third) {
@ -69,7 +69,7 @@ abstract class NodeLeavingAndExitingSpec
hasExited.get.address must be(secondAddress)
}
enter("finished")
enterBarrier("finished")
}
}
}

View file

@ -44,7 +44,7 @@ abstract class NodeLeavingSpec
runOn(first) {
cluster.leave(secondAddress)
}
enter("second-left")
enterBarrier("second-left")
runOn(first, third) {
awaitCond(cluster.latestGossip.members.exists(_.status == MemberStatus.Leaving))
@ -54,7 +54,7 @@ abstract class NodeLeavingSpec
hasLeft.get.address must be(secondAddress)
}
enter("finished")
enterBarrier("finished")
}
}
}

View file

@ -38,7 +38,7 @@ abstract class NodeMembershipSpec
runOn(first) {
startClusterNode()
}
enter("first-started")
enterBarrier("first-started")
runOn(first, second) {
cluster.join(firstAddress)
@ -50,7 +50,7 @@ abstract class NodeMembershipSpec
awaitCond(cluster.convergence.isDefined)
}
enter("after-1")
enterBarrier("after-1")
}
"(when three nodes) start gossiping to each other so that all nodes gets the same gossip info" taggedAs LongRunningTest in {
@ -66,7 +66,7 @@ abstract class NodeMembershipSpec
}
awaitCond(cluster.convergence.isDefined)
enter("after-2")
enterBarrier("after-2")
}
}
}

View file

@ -33,7 +33,7 @@ abstract class NodeUpSpec
awaitClusterUp(first, second)
enter("after-1")
enterBarrier("after-1")
}
"be unaffected when joining again" taggedAs LongRunningTest in {
@ -45,12 +45,12 @@ abstract class NodeUpSpec
unexpected.set(members)
}
})
enter("listener-registered")
enterBarrier("listener-registered")
runOn(second) {
cluster.join(node(first).address)
}
enter("joined-again")
enterBarrier("joined-again")
// let it run for a while to make sure that nothing bad happens
for (n 1 to 20) {
@ -59,7 +59,7 @@ abstract class NodeUpSpec
cluster.latestGossip.members.forall(_.status == MemberStatus.Up) must be(true)
}
enter("after-2")
enterBarrier("after-2")
}
}
}

View file

@ -43,7 +43,7 @@ abstract class SingletonClusterSpec
cluster.isSingletonCluster must be(false)
assertLeader(first, second)
enter("after-1")
enterBarrier("after-1")
}
"become singleton cluster when one node is shutdown" taggedAs LongRunningTest in {
@ -58,7 +58,7 @@ abstract class SingletonClusterSpec
assertLeader(first)
}
enter("after-2")
enterBarrier("after-2")
}
}
}

View file

@ -62,7 +62,7 @@ abstract class SunnyWeatherSpec
})
for (n 1 to 30) {
enter("period-" + n)
enterBarrier("period-" + n)
unexpected.get must be(null)
awaitUpConvergence(roles.size)
assertLeaderIn(roles)
@ -70,7 +70,7 @@ abstract class SunnyWeatherSpec
1.seconds.sleep
}
enter("after")
enterBarrier("after")
}
}
}

View file

@ -8,6 +8,81 @@ public final class TestConductorProtocol {
public static void registerAllExtensions(
com.google.protobuf.ExtensionRegistry registry) {
}
public enum BarrierOp
implements com.google.protobuf.ProtocolMessageEnum {
Enter(0, 1),
Fail(1, 2),
Succeeded(2, 3),
Failed(3, 4),
;
public static final int Enter_VALUE = 1;
public static final int Fail_VALUE = 2;
public static final int Succeeded_VALUE = 3;
public static final int Failed_VALUE = 4;
public final int getNumber() { return value; }
public static BarrierOp valueOf(int value) {
switch (value) {
case 1: return Enter;
case 2: return Fail;
case 3: return Succeeded;
case 4: return Failed;
default: return null;
}
}
public static com.google.protobuf.Internal.EnumLiteMap<BarrierOp>
internalGetValueMap() {
return internalValueMap;
}
private static com.google.protobuf.Internal.EnumLiteMap<BarrierOp>
internalValueMap =
new com.google.protobuf.Internal.EnumLiteMap<BarrierOp>() {
public BarrierOp findValueByNumber(int number) {
return BarrierOp.valueOf(number);
}
};
public final com.google.protobuf.Descriptors.EnumValueDescriptor
getValueDescriptor() {
return getDescriptor().getValues().get(index);
}
public final com.google.protobuf.Descriptors.EnumDescriptor
getDescriptorForType() {
return getDescriptor();
}
public static final com.google.protobuf.Descriptors.EnumDescriptor
getDescriptor() {
return akka.remote.testconductor.TestConductorProtocol.getDescriptor().getEnumTypes().get(0);
}
private static final BarrierOp[] VALUES = {
Enter, Fail, Succeeded, Failed,
};
public static BarrierOp valueOf(
com.google.protobuf.Descriptors.EnumValueDescriptor desc) {
if (desc.getType() != getDescriptor()) {
throw new java.lang.IllegalArgumentException(
"EnumValueDescriptor is not for this type.");
}
return VALUES[desc.getIndex()];
}
private final int index;
private final int value;
private BarrierOp(int index, int value) {
this.index = index;
this.value = value;
}
// @@protoc_insertion_point(enum_scope:BarrierOp)
}
public enum FailType
implements com.google.protobuf.ProtocolMessageEnum {
Throttle(0, 1),
@ -56,7 +131,7 @@ public final class TestConductorProtocol {
}
public static final com.google.protobuf.Descriptors.EnumDescriptor
getDescriptor() {
return akka.remote.testconductor.TestConductorProtocol.getDescriptor().getEnumTypes().get(0);
return akka.remote.testconductor.TestConductorProtocol.getDescriptor().getEnumTypes().get(1);
}
private static final FailType[] VALUES = {
@ -128,7 +203,7 @@ public final class TestConductorProtocol {
}
public static final com.google.protobuf.Descriptors.EnumDescriptor
getDescriptor() {
return akka.remote.testconductor.TestConductorProtocol.getDescriptor().getEnumTypes().get(1);
return akka.remote.testconductor.TestConductorProtocol.getDescriptor().getEnumTypes().get(2);
}
private static final Direction[] VALUES = {
@ -1699,17 +1774,13 @@ public final class TestConductorProtocol {
boolean hasName();
String getName();
// optional bool status = 2;
boolean hasStatus();
boolean getStatus();
// required .BarrierOp op = 2;
boolean hasOp();
akka.remote.testconductor.TestConductorProtocol.BarrierOp getOp();
// optional int64 timeout = 3;
boolean hasTimeout();
long getTimeout();
// optional bool failed = 4;
boolean hasFailed();
boolean getFailed();
}
public static final class EnterBarrier extends
com.google.protobuf.GeneratedMessage
@ -1772,14 +1843,14 @@ public final class TestConductorProtocol {
}
}
// optional bool status = 2;
public static final int STATUS_FIELD_NUMBER = 2;
private boolean status_;
public boolean hasStatus() {
// required .BarrierOp op = 2;
public static final int OP_FIELD_NUMBER = 2;
private akka.remote.testconductor.TestConductorProtocol.BarrierOp op_;
public boolean hasOp() {
return ((bitField0_ & 0x00000002) == 0x00000002);
}
public boolean getStatus() {
return status_;
public akka.remote.testconductor.TestConductorProtocol.BarrierOp getOp() {
return op_;
}
// optional int64 timeout = 3;
@ -1792,21 +1863,10 @@ public final class TestConductorProtocol {
return timeout_;
}
// optional bool failed = 4;
public static final int FAILED_FIELD_NUMBER = 4;
private boolean failed_;
public boolean hasFailed() {
return ((bitField0_ & 0x00000008) == 0x00000008);
}
public boolean getFailed() {
return failed_;
}
private void initFields() {
name_ = "";
status_ = false;
op_ = akka.remote.testconductor.TestConductorProtocol.BarrierOp.Enter;
timeout_ = 0L;
failed_ = false;
}
private byte memoizedIsInitialized = -1;
public final boolean isInitialized() {
@ -1817,6 +1877,10 @@ public final class TestConductorProtocol {
memoizedIsInitialized = 0;
return false;
}
if (!hasOp()) {
memoizedIsInitialized = 0;
return false;
}
memoizedIsInitialized = 1;
return true;
}
@ -1828,14 +1892,11 @@ public final class TestConductorProtocol {
output.writeBytes(1, getNameBytes());
}
if (((bitField0_ & 0x00000002) == 0x00000002)) {
output.writeBool(2, status_);
output.writeEnum(2, op_.getNumber());
}
if (((bitField0_ & 0x00000004) == 0x00000004)) {
output.writeInt64(3, timeout_);
}
if (((bitField0_ & 0x00000008) == 0x00000008)) {
output.writeBool(4, failed_);
}
getUnknownFields().writeTo(output);
}
@ -1851,16 +1912,12 @@ public final class TestConductorProtocol {
}
if (((bitField0_ & 0x00000002) == 0x00000002)) {
size += com.google.protobuf.CodedOutputStream
.computeBoolSize(2, status_);
.computeEnumSize(2, op_.getNumber());
}
if (((bitField0_ & 0x00000004) == 0x00000004)) {
size += com.google.protobuf.CodedOutputStream
.computeInt64Size(3, timeout_);
}
if (((bitField0_ & 0x00000008) == 0x00000008)) {
size += com.google.protobuf.CodedOutputStream
.computeBoolSize(4, failed_);
}
size += getUnknownFields().getSerializedSize();
memoizedSerializedSize = size;
return size;
@ -1987,12 +2044,10 @@ public final class TestConductorProtocol {
super.clear();
name_ = "";
bitField0_ = (bitField0_ & ~0x00000001);
status_ = false;
op_ = akka.remote.testconductor.TestConductorProtocol.BarrierOp.Enter;
bitField0_ = (bitField0_ & ~0x00000002);
timeout_ = 0L;
bitField0_ = (bitField0_ & ~0x00000004);
failed_ = false;
bitField0_ = (bitField0_ & ~0x00000008);
return this;
}
@ -2038,15 +2093,11 @@ public final class TestConductorProtocol {
if (((from_bitField0_ & 0x00000002) == 0x00000002)) {
to_bitField0_ |= 0x00000002;
}
result.status_ = status_;
result.op_ = op_;
if (((from_bitField0_ & 0x00000004) == 0x00000004)) {
to_bitField0_ |= 0x00000004;
}
result.timeout_ = timeout_;
if (((from_bitField0_ & 0x00000008) == 0x00000008)) {
to_bitField0_ |= 0x00000008;
}
result.failed_ = failed_;
result.bitField0_ = to_bitField0_;
onBuilt();
return result;
@ -2066,15 +2117,12 @@ public final class TestConductorProtocol {
if (other.hasName()) {
setName(other.getName());
}
if (other.hasStatus()) {
setStatus(other.getStatus());
if (other.hasOp()) {
setOp(other.getOp());
}
if (other.hasTimeout()) {
setTimeout(other.getTimeout());
}
if (other.hasFailed()) {
setFailed(other.getFailed());
}
this.mergeUnknownFields(other.getUnknownFields());
return this;
}
@ -2084,6 +2132,10 @@ public final class TestConductorProtocol {
return false;
}
if (!hasOp()) {
return false;
}
return true;
}
@ -2116,8 +2168,14 @@ public final class TestConductorProtocol {
break;
}
case 16: {
int rawValue = input.readEnum();
akka.remote.testconductor.TestConductorProtocol.BarrierOp value = akka.remote.testconductor.TestConductorProtocol.BarrierOp.valueOf(rawValue);
if (value == null) {
unknownFields.mergeVarintField(2, rawValue);
} else {
bitField0_ |= 0x00000002;
status_ = input.readBool();
op_ = value;
}
break;
}
case 24: {
@ -2125,11 +2183,6 @@ public final class TestConductorProtocol {
timeout_ = input.readInt64();
break;
}
case 32: {
bitField0_ |= 0x00000008;
failed_ = input.readBool();
break;
}
}
}
}
@ -2172,23 +2225,26 @@ public final class TestConductorProtocol {
onChanged();
}
// optional bool status = 2;
private boolean status_ ;
public boolean hasStatus() {
// required .BarrierOp op = 2;
private akka.remote.testconductor.TestConductorProtocol.BarrierOp op_ = akka.remote.testconductor.TestConductorProtocol.BarrierOp.Enter;
public boolean hasOp() {
return ((bitField0_ & 0x00000002) == 0x00000002);
}
public boolean getStatus() {
return status_;
public akka.remote.testconductor.TestConductorProtocol.BarrierOp getOp() {
return op_;
}
public Builder setOp(akka.remote.testconductor.TestConductorProtocol.BarrierOp value) {
if (value == null) {
throw new NullPointerException();
}
public Builder setStatus(boolean value) {
bitField0_ |= 0x00000002;
status_ = value;
op_ = value;
onChanged();
return this;
}
public Builder clearStatus() {
public Builder clearOp() {
bitField0_ = (bitField0_ & ~0x00000002);
status_ = false;
op_ = akka.remote.testconductor.TestConductorProtocol.BarrierOp.Enter;
onChanged();
return this;
}
@ -2214,27 +2270,6 @@ public final class TestConductorProtocol {
return this;
}
// optional bool failed = 4;
private boolean failed_ ;
public boolean hasFailed() {
return ((bitField0_ & 0x00000008) == 0x00000008);
}
public boolean getFailed() {
return failed_;
}
public Builder setFailed(boolean value) {
bitField0_ |= 0x00000008;
failed_ = value;
onChanged();
return this;
}
public Builder clearFailed() {
bitField0_ = (bitField0_ & ~0x00000008);
failed_ = false;
onChanged();
return this;
}
// @@protoc_insertion_point(builder_scope:EnterBarrier)
}
@ -4170,19 +4205,21 @@ public final class TestConductorProtocol {
"\0132\r.EnterBarrier\022\037\n\007failure\030\003 \001(\0132\016.Inje" +
"ctFailure\022\014\n\004done\030\004 \001(\t\022\035\n\004addr\030\005 \001(\0132\017." +
"AddressRequest\"0\n\005Hello\022\014\n\004name\030\001 \002(\t\022\031\n" +
"\007address\030\002 \002(\0132\010.Address\"M\n\014EnterBarrier" +
"\022\014\n\004name\030\001 \002(\t\022\016\n\006status\030\002 \001(\010\022\017\n\007timeou" +
"t\030\003 \001(\003\022\016\n\006failed\030\004 \001(\010\"6\n\016AddressReques" +
"t\022\014\n\004node\030\001 \002(\t\022\026\n\004addr\030\002 \001(\0132\010.Address\"" +
"G\n\007Address\022\020\n\010protocol\030\001 \002(\t\022\016\n\006system\030\002",
" \002(\t\022\014\n\004host\030\003 \002(\t\022\014\n\004port\030\004 \002(\005\"\212\001\n\rInj" +
"ectFailure\022\032\n\007failure\030\001 \002(\0162\t.FailType\022\035" +
"\n\tdirection\030\002 \001(\0162\n.Direction\022\031\n\007address" +
"\030\003 \001(\0132\010.Address\022\020\n\010rateMBit\030\006 \001(\002\022\021\n\tex" +
"itValue\030\007 \001(\005*A\n\010FailType\022\014\n\010Throttle\020\001\022" +
"\016\n\nDisconnect\020\002\022\t\n\005Abort\020\003\022\014\n\010Shutdown\020\004" +
"*,\n\tDirection\022\010\n\004Send\020\001\022\013\n\007Receive\020\002\022\010\n\004" +
"Both\020\003B\035\n\031akka.remote.testconductorH\001"
"\007address\030\002 \002(\0132\010.Address\"E\n\014EnterBarrier" +
"\022\014\n\004name\030\001 \002(\t\022\026\n\002op\030\002 \002(\0162\n.BarrierOp\022\017" +
"\n\007timeout\030\003 \001(\003\"6\n\016AddressRequest\022\014\n\004nod" +
"e\030\001 \002(\t\022\026\n\004addr\030\002 \001(\0132\010.Address\"G\n\007Addre" +
"ss\022\020\n\010protocol\030\001 \002(\t\022\016\n\006system\030\002 \002(\t\022\014\n\004",
"host\030\003 \002(\t\022\014\n\004port\030\004 \002(\005\"\212\001\n\rInjectFailu" +
"re\022\032\n\007failure\030\001 \002(\0162\t.FailType\022\035\n\tdirect" +
"ion\030\002 \001(\0162\n.Direction\022\031\n\007address\030\003 \001(\0132\010" +
".Address\022\020\n\010rateMBit\030\006 \001(\002\022\021\n\texitValue\030" +
"\007 \001(\005*;\n\tBarrierOp\022\t\n\005Enter\020\001\022\010\n\004Fail\020\002\022" +
"\r\n\tSucceeded\020\003\022\n\n\006Failed\020\004*A\n\010FailType\022\014" +
"\n\010Throttle\020\001\022\016\n\nDisconnect\020\002\022\t\n\005Abort\020\003\022" +
"\014\n\010Shutdown\020\004*,\n\tDirection\022\010\n\004Send\020\001\022\013\n\007" +
"Receive\020\002\022\010\n\004Both\020\003B\035\n\031akka.remote.testc" +
"onductorH\001"
};
com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {
@ -4210,7 +4247,7 @@ public final class TestConductorProtocol {
internal_static_EnterBarrier_fieldAccessorTable = new
com.google.protobuf.GeneratedMessage.FieldAccessorTable(
internal_static_EnterBarrier_descriptor,
new java.lang.String[] { "Name", "Status", "Timeout", "Failed", },
new java.lang.String[] { "Name", "Op", "Timeout", },
akka.remote.testconductor.TestConductorProtocol.EnterBarrier.class,
akka.remote.testconductor.TestConductorProtocol.EnterBarrier.Builder.class);
internal_static_AddressRequest_descriptor =

View file

@ -26,11 +26,17 @@ message Hello {
required Address address = 2;
}
enum BarrierOp {
Enter = 1;
Fail = 2;
Succeeded = 3;
Failed = 4;
}
message EnterBarrier {
required string name = 1;
optional bool status = 2;
required BarrierOp op = 2;
optional int64 timeout = 3;
optional bool failed = 4;
}
message AddressRequest {
@ -51,11 +57,13 @@ enum FailType {
Abort = 3;
Shutdown = 4;
}
enum Direction {
Send = 1;
Receive = 2;
Both = 3;
}
message InjectFailure {
required FailType failure = 1;
optional Direction direction = 2;

View file

@ -8,8 +8,6 @@ import RemoteConnection.getAddrString
import TestConductorProtocol._
import org.jboss.netty.channel.{ Channel, SimpleChannelUpstreamHandler, ChannelHandlerContext, ChannelStateEvent, MessageEvent }
import com.typesafe.config.ConfigFactory
import akka.util.Timeout
import akka.util.Duration
import akka.util.duration._
import akka.pattern.ask
import java.util.concurrent.TimeUnit.MILLISECONDS
@ -26,6 +24,7 @@ import akka.actor.OneForOneStrategy
import akka.actor.SupervisorStrategy
import java.util.concurrent.ConcurrentHashMap
import akka.actor.Status
import akka.util.{ Deadline, Timeout, Duration }
sealed trait Direction {
def includes(other: Direction): Boolean
@ -376,7 +375,8 @@ private[akka] class Controller(private var initialParticipants: Int, controllerP
* BarrierTimeouts in the players).
*/
override def supervisorStrategy = OneForOneStrategy() {
case BarrierTimeout(data) SupervisorStrategy.Restart
case BarrierTimeout(data) failBarrier(data)
case FailedBarrier(data) failBarrier(data)
case BarrierEmpty(data, msg) SupervisorStrategy.Resume
case WrongBarrier(name, client, data) client ! ToClient(BarrierResult(name, false)); failBarrier(data)
case ClientLost(data, node) failBarrier(data)
@ -464,7 +464,7 @@ private[akka] object BarrierCoordinator {
case class RemoveClient(name: RoleName)
case class Data(clients: Set[Controller.NodeInfo], barrier: String, arrived: List[ActorRef])
case class Data(clients: Set[Controller.NodeInfo], barrier: String, arrived: List[ActorRef], deadline: Deadline)
trait Printer { this: Product with Throwable with NoStackTrace
override def toString = productPrefix + productIterator.mkString("(", ", ", ")")
@ -472,6 +472,8 @@ private[akka] object BarrierCoordinator {
case class BarrierTimeout(data: Data)
extends RuntimeException("timeout while waiting for barrier '" + data.barrier + "'") with NoStackTrace with Printer
case class FailedBarrier(data: Data)
extends RuntimeException("failing barrier '" + data.barrier + "'") with NoStackTrace with Printer
case class DuplicateNode(data: Data, node: Controller.NodeInfo)
extends RuntimeException(node.toString) with NoStackTrace with Printer
case class WrongBarrier(barrier: String, client: ActorRef, data: Data)
@ -503,20 +505,18 @@ private[akka] class BarrierCoordinator extends Actor with LoggingFSM[BarrierCoor
// this shall be set to true if all subsequent barriers shall fail
var failed = false
var barrierTimeout: Option[auTimeout] = None
override def preRestart(reason: Throwable, message: Option[Any]) {}
override def postRestart(reason: Throwable) { failed = true }
// TODO what happens with the other waiting players in case of a test failure?
startWith(Idle, Data(Set(), "", Nil))
startWith(Idle, Data(Set(), "", Nil, null))
whenUnhandled {
case Event(n: NodeInfo, d @ Data(clients, _, _))
case Event(n: NodeInfo, d @ Data(clients, _, _, _))
if (clients.find(_.name == n.name).isDefined) throw new DuplicateNode(d, n)
stay using d.copy(clients = clients + n)
case Event(ClientDisconnected(name), d @ Data(clients, _, arrived))
case Event(ClientDisconnected(name), d @ Data(clients, _, arrived, _))
if (clients.isEmpty) throw BarrierEmpty(d, "cannot disconnect " + name + ": no client to disconnect")
(clients find (_.name == name)) match {
case None stay
@ -525,7 +525,7 @@ private[akka] class BarrierCoordinator extends Actor with LoggingFSM[BarrierCoor
}
when(Idle) {
case Event(EnterBarrier(name, timeout), d @ Data(clients, _, _))
case Event(EnterBarrier(name, timeout), d @ Data(clients, _, _, _))
if (failed)
stay replying ToClient(BarrierResult(name, false))
else if (clients.map(_.fsm) == Set(sender))
@ -533,56 +533,61 @@ private[akka] class BarrierCoordinator extends Actor with LoggingFSM[BarrierCoor
else if (clients.find(_.fsm == sender).isEmpty)
stay replying ToClient(BarrierResult(name, false))
else {
barrierTimeout = timeout
goto(Waiting) using d.copy(barrier = name, arrived = sender :: Nil)
goto(Waiting) using d.copy(barrier = name, arrived = sender :: Nil,
deadline = getDeadline(timeout))
}
case Event(RemoveClient(name), d @ Data(clients, _, _))
case Event(RemoveClient(name), d @ Data(clients, _, _, _))
if (clients.isEmpty) throw BarrierEmpty(d, "cannot remove " + name + ": no client to remove")
stay using d.copy(clients = clients filterNot (_.name == name))
}
onTransition {
case Idle -> Waiting setTimer("Timeout", StateTimeout, barrierTimeout.getOrElse[auTimeout](TestConductor().Settings.BarrierTimeout).duration, false)
case Idle -> Waiting setTimer("Timeout", StateTimeout, nextStateData.deadline - Deadline.now, false)
case Waiting -> Idle cancelTimer("Timeout")
}
when(Waiting) {
case Event(EnterBarrier(name, timeout), d @ Data(clients, barrier, arrived))
case Event(EnterBarrier(name, timeout), d @ Data(clients, barrier, arrived, deadline))
if (name != barrier) throw WrongBarrier(name, sender, d)
val together = if (clients.exists(_.fsm == sender)) sender :: arrived else arrived
handleBarrier(d.copy(arrived = together))
case Event(RemoveClient(name), d @ Data(clients, barrier, arrived))
val enterDeadline = getDeadline(timeout)
// we only allow the deadlines to get shorter
val newDeadline = if ((enterDeadline - deadline) < Duration.Zero) enterDeadline else deadline
if (newDeadline != deadline) {
cancelTimer("Timeout")
setTimer("Timeout", StateTimeout, newDeadline - Deadline.now, false)
}
handleBarrier(d.copy(arrived = together, deadline = newDeadline))
case Event(RemoveClient(name), d @ Data(clients, barrier, arrived, _))
clients find (_.name == name) match {
case None stay
case Some(client)
handleBarrier(d.copy(clients = clients - client, arrived = arrived filterNot (_ == client.fsm)))
}
case Event(FailBarrier(name), d @ Data(clients, barrier, arrived))
case Event(FailBarrier(name), d @ Data(_, barrier, _, _))
if (name != barrier) throw WrongBarrier(name, sender, d)
failed = true
handleBarrier(d, false)
case Event(StateTimeout, d @ Data(clients, barrier, arrived))
handleBarrier(d, false)
throw FailedBarrier(d)
case Event(StateTimeout, d)
throw BarrierTimeout(d)
}
initialize
def handleBarrier(data: Data, status: Boolean = true): State = {
log.debug("handleBarrier({}, {})", data, status)
if (!status) {
data.arrived foreach (_ ! ToClient(BarrierResult(data.barrier, status)))
goto(Idle) using data.copy(barrier = "", arrived = Nil)
} else if (data.arrived.isEmpty) {
def handleBarrier(data: Data): State = {
log.debug("handleBarrier({})", data)
if (data.arrived.isEmpty) {
goto(Idle) using data.copy(barrier = "")
} else if ((data.clients.map(_.fsm) -- data.arrived).isEmpty) {
data.arrived foreach (_ ! ToClient(BarrierResult(data.barrier, status)))
data.arrived foreach (_ ! ToClient(BarrierResult(data.barrier, true)))
goto(Idle) using data.copy(barrier = "", arrived = Nil)
} else {
stay using data
}
}
def getDeadline(timeout: Option[Duration]): Deadline = {
Deadline.now + timeout.getOrElse(TestConductor().Settings.BarrierTimeout.duration)
}
}

View file

@ -10,7 +10,8 @@ import akka.remote.testconductor.{ TestConductorProtocol ⇒ TCP }
import com.google.protobuf.Message
import akka.actor.Address
import org.jboss.netty.handler.codec.oneone.OneToOneDecoder
import akka.util.Timeout
import akka.util.Duration
import akka.remote.testconductor.TestConductorProtocol.BarrierOp
case class RoleName(name: String)
@ -29,7 +30,7 @@ private[akka] sealed trait ConfirmedClientOp extends ClientOp
*/
private[akka] case class Hello(name: String, addr: Address) extends NetworkOp
private[akka] case class EnterBarrier(name: String, timeout: Option[Timeout] = None) extends ServerOp with NetworkOp
private[akka] case class EnterBarrier(name: String, timeout: Option[Duration] = None) extends ServerOp with NetworkOp
private[akka] case class FailBarrier(name: String) extends ServerOp with NetworkOp
private[akka] case class BarrierResult(name: String, success: Boolean) extends UnconfirmedClientOp with NetworkOp
@ -76,12 +77,14 @@ private[akka] class MsgEncoder extends OneToOneEncoder {
w.setHello(TCP.Hello.newBuilder.setName(name).setAddress(addr))
case EnterBarrier(name, timeout)
val barrier = TCP.EnterBarrier.newBuilder.setName(name)
timeout foreach (t barrier.setTimeout(t.duration.toMillis))
timeout foreach (t barrier.setTimeout(t.toNanos))
barrier.setOp(BarrierOp.Enter)
w.setBarrier(barrier)
case BarrierResult(name, success)
w.setBarrier(TCP.EnterBarrier.newBuilder.setName(name).setStatus(success))
val res = if (success) BarrierOp.Succeeded else BarrierOp.Failed
w.setBarrier(TCP.EnterBarrier.newBuilder.setName(name).setOp(res))
case FailBarrier(name)
w.setBarrier(TCP.EnterBarrier.newBuilder.setName(name).setFailed(true))
w.setBarrier(TCP.EnterBarrier.newBuilder.setName(name).setOp(BarrierOp.Fail))
case ThrottleMsg(target, dir, rate)
w.setFailure(TCP.InjectFailure.newBuilder.setAddress(target)
.setFailure(TCP.FailType.Throttle).setDirection(dir).setRateMBit(rate))
@ -120,9 +123,13 @@ private[akka] class MsgDecoder extends OneToOneDecoder {
Hello(h.getName, h.getAddress)
} else if (w.hasBarrier) {
val barrier = w.getBarrier
if (barrier.hasStatus) BarrierResult(barrier.getName, barrier.getStatus)
else if (barrier.hasFailed) FailBarrier(barrier.getName)
else EnterBarrier(w.getBarrier.getName, if (barrier.hasTimeout) Option(Timeout.longToTimeout(barrier.getTimeout)) else None)
barrier.getOp match {
case BarrierOp.Succeeded BarrierResult(barrier.getName, true)
case BarrierOp.Failed BarrierResult(barrier.getName, false)
case BarrierOp.Fail FailBarrier(barrier.getName)
case BarrierOp.Enter EnterBarrier(barrier.getName,
if (barrier.hasTimeout) Option(Duration.fromNanos(barrier.getTimeout)) else None)
}
} else if (w.hasFailure) {
val f = w.getFailure
import TCP.{ FailType FT }

View file

@ -26,6 +26,7 @@ import org.jboss.netty.channel.WriteCompletionEvent
import java.net.ConnectException
import akka.util.Deadline
import akka.actor.Scheduler
import java.util.concurrent.TimeoutException
/**
* The Player is the client component of the
@ -79,8 +80,6 @@ trait Player { this: TestConductorExt ⇒
enter(Settings.BarrierTimeout, name)
}
case class OutOfTimeException(barrier: String) extends RuntimeException("Ran out of time while waiting for barrier '" + barrier + "'") with NoStackTrace
/**
* Enter the named barriers, one after the other, in the order given. Will
* throw an exception in case of timeouts or other errors.
@ -94,7 +93,7 @@ trait Player { this: TestConductorExt ⇒
val barrierTimeout = stop - now
if (barrierTimeout < Duration.Zero) {
client ! ToServer(FailBarrier(b))
throw OutOfTimeException(b)
throw new TimeoutException("Server timed out while waiting for barrier " + b);
}
try {
implicit val timeout = Timeout(barrierTimeout + Settings.QueryTimeout.duration)
@ -102,7 +101,8 @@ trait Player { this: TestConductorExt ⇒
} catch {
case e: AskTimeoutException
client ! ToServer(FailBarrier(b))
throw e
// Why don't TimeoutException have a constructor that takes a cause?
throw new TimeoutException("Client timed out while waiting for barrier " + b);
}
system.log.debug("passed barrier {}", b)
}

View file

@ -47,7 +47,7 @@ class LookupRemoteActorSpec extends MultiNodeSpec(LookupRemoteActorMultiJvmSpec)
val masterAddress = testConductor.getAddressFor(master).await
(hello ? "identify").await.asInstanceOf[ActorRef].path.address must equal(masterAddress)
}
enter("done")
enterBarrier("done")
}
}

View file

@ -56,7 +56,7 @@ class NewRemoteActorSpec extends MultiNodeSpec(NewRemoteActorMultiJvmSpec)
system.stop(actor)
}
enter("done")
enterBarrier("done")
}
"be locally instantiated on a remote node and be able to communicate through its RemoteActorRef (with deployOnAll)" taggedAs LongRunningTest in {
@ -74,7 +74,7 @@ class NewRemoteActorSpec extends MultiNodeSpec(NewRemoteActorMultiJvmSpec)
system.stop(actor)
}
enter("done")
enterBarrier("done")
}
}
}

View file

@ -55,11 +55,11 @@ class RandomRoutedRemoteActorSpec extends MultiNodeSpec(RandomRoutedRemoteActorM
"be locally instantiated on a remote node and be able to communicate through its RemoteActorRef" taggedAs LongRunningTest in {
runOn(first, second, third) {
enter("start", "broadcast-end", "end", "done")
enterBarrier("start", "broadcast-end", "end", "done")
}
runOn(fourth) {
enter("start")
enterBarrier("start")
val actor = system.actorOf(Props[SomeActor].withRouter(RandomRouter()), "service-hello")
actor.isInstanceOf[RoutedActorRef] must be(true)
@ -76,17 +76,17 @@ class RandomRoutedRemoteActorSpec extends MultiNodeSpec(RandomRoutedRemoteActorM
case (replyMap, address) replyMap + (address -> (replyMap(address) + 1))
}
enter("broadcast-end")
enterBarrier("broadcast-end")
actor ! Broadcast(PoisonPill)
enter("end")
enterBarrier("end")
replies.values foreach { _ must be > (0) }
replies.get(node(fourth).address) must be(None)
// shut down the actor before we let the other node(s) shut down so we don't try to send
// "Terminate" to a shut down node
system.stop(actor)
enter("done")
enterBarrier("done")
}
}
}

View file

@ -55,11 +55,11 @@ class RoundRobinRoutedRemoteActorSpec extends MultiNodeSpec(RoundRobinRoutedRemo
"be locally instantiated on a remote node and be able to communicate through its RemoteActorRef" taggedAs LongRunningTest in {
runOn(first, second, third) {
enter("start", "broadcast-end", "end", "done")
enterBarrier("start", "broadcast-end", "end", "done")
}
runOn(fourth) {
enter("start")
enterBarrier("start")
val actor = system.actorOf(Props[SomeActor].withRouter(RoundRobinRouter()), "service-hello")
actor.isInstanceOf[RoutedActorRef] must be(true)
@ -76,17 +76,17 @@ class RoundRobinRoutedRemoteActorSpec extends MultiNodeSpec(RoundRobinRoutedRemo
case (replyMap, address) replyMap + (address -> (replyMap(address) + 1))
}
enter("broadcast-end")
enterBarrier("broadcast-end")
actor ! Broadcast(PoisonPill)
enter("end")
enterBarrier("end")
replies.values foreach { _ must be(iterationCount) }
replies.get(node(fourth).address) must be(None)
// shut down the actor before we let the other node(s) shut down so we don't try to send
// "Terminate" to a shut down node
system.stop(actor)
enter("done")
enterBarrier("done")
}
}
}

View file

@ -55,11 +55,11 @@ class ScatterGatherRoutedRemoteActorSpec extends MultiNodeSpec(ScatterGatherRout
"be locally instantiated on a remote node and be able to communicate through its RemoteActorRef" taggedAs LongRunningTest in {
runOn(first, second, third) {
enter("start", "broadcast-end", "end", "done")
enterBarrier("start", "broadcast-end", "end", "done")
}
runOn(fourth) {
enter("start")
enterBarrier("start")
val actor = system.actorOf(Props[SomeActor].withRouter(ScatterGatherFirstCompletedRouter(within = 10 seconds)), "service-hello")
actor.isInstanceOf[RoutedActorRef] must be(true)
@ -76,17 +76,17 @@ class ScatterGatherRoutedRemoteActorSpec extends MultiNodeSpec(ScatterGatherRout
case (replyMap, address) replyMap + (address -> (replyMap(address) + 1))
}
enter("broadcast-end")
enterBarrier("broadcast-end")
actor ! Broadcast(PoisonPill)
enter("end")
enterBarrier("end")
replies.values.sum must be === connectionCount * iterationCount
replies.get(node(fourth).address) must be(None)
// shut down the actor before we let the other node(s) shut down so we don't try to send
// "Terminate" to a shut down node
system.stop(actor)
enter("done")
enterBarrier("done")
}
}
}

View file

@ -46,7 +46,7 @@ class TestConductorSpec extends MultiNodeSpec(TestConductorMultiJvmSpec) with Im
}), "echo")
}
enter("name")
enterBarrier("name")
}
"support throttling of network connections" taggedAs LongRunningTest in {
@ -62,7 +62,7 @@ class TestConductorSpec extends MultiNodeSpec(TestConductorMultiJvmSpec) with Im
testConductor.throttle(slave, master, Direction.Send, rateMBit = 0.01).await
}
enter("throttled_send")
enterBarrier("throttled_send")
runOn(slave) {
for (i 0 to 9) echo ! i
@ -73,14 +73,14 @@ class TestConductorSpec extends MultiNodeSpec(TestConductorMultiJvmSpec) with Im
receiveN(9) must be(1 to 9)
}
enter("throttled_send2")
enterBarrier("throttled_send2")
runOn(master) {
testConductor.throttle(slave, master, Direction.Send, -1).await
testConductor.throttle(slave, master, Direction.Receive, rateMBit = 0.01).await
}
enter("throttled_recv")
enterBarrier("throttled_recv")
runOn(slave) {
for (i 10 to 19) echo ! i
@ -98,7 +98,7 @@ class TestConductorSpec extends MultiNodeSpec(TestConductorMultiJvmSpec) with Im
receiveN(9) must be(11 to 19)
}
enter("throttled_recv2")
enterBarrier("throttled_recv2")
runOn(master) {
testConductor.throttle(slave, master, Direction.Receive, -1).await

View file

@ -32,7 +32,7 @@ object BarrierSpec {
"""
}
class BarrierSpec extends AkkaSpec(BarrierSpec.config) with ImplicitSender with BeforeAndAfterEach {
class BarrierSpec extends AkkaSpec(BarrierSpec.config) with ImplicitSender {
import BarrierSpec._
import Controller._
@ -42,10 +42,6 @@ class BarrierSpec extends AkkaSpec(BarrierSpec.config) with ImplicitSender with
val B = RoleName("b")
val C = RoleName("c")
override def afterEach {
system.eventStream.setLogLevel(Logging.WarningLevel)
}
"A BarrierCoordinator" must {
"register clients and remove them" taggedAs TimingTest in {
@ -56,7 +52,7 @@ class BarrierSpec extends AkkaSpec(BarrierSpec.config) with ImplicitSender with
EventFilter[BarrierEmpty](occurrences = 1) intercept {
b ! RemoveClient(A)
}
expectMsg(Failed(b, BarrierEmpty(Data(Set(), "", Nil), "cannot remove RoleName(a): no client to remove")))
expectMsg(Failed(b, BarrierEmpty(Data(Set(), "", Nil, null), "cannot remove RoleName(a): no client to remove")))
}
"register clients and disconnect them" taggedAs TimingTest in {
@ -66,11 +62,11 @@ class BarrierSpec extends AkkaSpec(BarrierSpec.config) with ImplicitSender with
EventFilter[ClientLost](occurrences = 1) intercept {
b ! ClientDisconnected(A)
}
expectMsg(Failed(b, ClientLost(Data(Set(), "", Nil), A)))
expectMsg(Failed(b, ClientLost(Data(Set(), "", Nil, null), A)))
EventFilter[BarrierEmpty](occurrences = 1) intercept {
b ! ClientDisconnected(A)
}
expectMsg(Failed(b, BarrierEmpty(Data(Set(), "", Nil), "cannot disconnect RoleName(a): no client to disconnect")))
expectMsg(Failed(b, BarrierEmpty(Data(Set(), "", Nil, null), "cannot disconnect RoleName(a): no client to disconnect")))
}
"fail entering barrier when nobody registered" taggedAs TimingTest in {
@ -86,7 +82,7 @@ class BarrierSpec extends AkkaSpec(BarrierSpec.config) with ImplicitSender with
barrier ! NodeInfo(B, AddressFromURIString("akka://sys"), b.ref)
a.send(barrier, EnterBarrier("bar2"))
noMsg(a, b)
within(2 second) {
within(2 seconds) {
b.send(barrier, EnterBarrier("bar2"))
a.expectMsg(ToClient(BarrierResult("bar2", true)))
b.expectMsg(ToClient(BarrierResult("bar2", true)))
@ -102,7 +98,7 @@ class BarrierSpec extends AkkaSpec(BarrierSpec.config) with ImplicitSender with
barrier ! NodeInfo(C, AddressFromURIString("akka://sys"), c.ref)
b.send(barrier, EnterBarrier("bar3"))
noMsg(a, b, c)
within(2 second) {
within(2 seconds) {
c.send(barrier, EnterBarrier("bar3"))
a.expectMsg(ToClient(BarrierResult("bar3", true)))
b.expectMsg(ToClient(BarrierResult("bar3", true)))
@ -121,7 +117,7 @@ class BarrierSpec extends AkkaSpec(BarrierSpec.config) with ImplicitSender with
barrier ! RemoveClient(A)
barrier ! ClientDisconnected(A)
noMsg(a, b, c)
b.within(2 second) {
b.within(2 seconds) {
barrier ! RemoveClient(C)
b.expectMsg(ToClient(BarrierResult("bar4", true)))
}
@ -150,7 +146,11 @@ class BarrierSpec extends AkkaSpec(BarrierSpec.config) with ImplicitSender with
EventFilter[ClientLost](occurrences = 1) intercept {
barrier ! ClientDisconnected(B)
}
expectMsg(Failed(barrier, ClientLost(Data(Set(nodeA), "bar6", a.ref :: Nil), B)))
val msg = expectMsgType[Failed]
msg match {
case Failed(barrier, thr: ClientLost) if (thr == ClientLost(Data(Set(nodeA), "bar6", a.ref :: Nil, thr.data.deadline), B))
case x fail("Expected " + Failed(barrier, ClientLost(Data(Set(nodeA), "bar6", a.ref :: Nil, null), B)) + " but got " + x)
}
}
"fail barrier with disconnecing node who already arrived" taggedAs TimingTest in {
@ -166,7 +166,11 @@ class BarrierSpec extends AkkaSpec(BarrierSpec.config) with ImplicitSender with
EventFilter[ClientLost](occurrences = 1) intercept {
barrier ! ClientDisconnected(B)
}
expectMsg(Failed(barrier, ClientLost(Data(Set(nodeA, nodeC), "bar7", a.ref :: Nil), B)))
val msg = expectMsgType[Failed]
msg match {
case Failed(barrier, thr: ClientLost) if (thr == ClientLost(Data(Set(nodeA, nodeC), "bar7", a.ref :: Nil, thr.data.deadline), B))
case x fail("Expected " + Failed(barrier, ClientLost(Data(Set(nodeA, nodeC), "bar7", a.ref :: Nil, null), B)) + " but got " + x)
}
}
"fail when entering wrong barrier" taggedAs TimingTest in {
@ -180,7 +184,11 @@ class BarrierSpec extends AkkaSpec(BarrierSpec.config) with ImplicitSender with
EventFilter[WrongBarrier](occurrences = 1) intercept {
b.send(barrier, EnterBarrier("foo"))
}
expectMsg(Failed(barrier, WrongBarrier("foo", b.ref, Data(Set(nodeA, nodeB), "bar8", a.ref :: Nil))))
val msg = expectMsgType[Failed]
msg match {
case Failed(barrier, thr: WrongBarrier) if (thr == WrongBarrier("foo", b.ref, Data(Set(nodeA, nodeB), "bar8", a.ref :: Nil, thr.data.deadline)))
case x fail("Expected " + Failed(barrier, WrongBarrier("foo", b.ref, Data(Set(nodeA, nodeB), "bar8", a.ref :: Nil, null))) + " but got " + x)
}
}
"fail barrier after first failure" taggedAs TimingTest in {
@ -189,7 +197,11 @@ class BarrierSpec extends AkkaSpec(BarrierSpec.config) with ImplicitSender with
EventFilter[BarrierEmpty](occurrences = 1) intercept {
barrier ! RemoveClient(A)
}
expectMsg(Failed(barrier, BarrierEmpty(Data(Set(), "", Nil), "cannot remove RoleName(a): no client to remove")))
val msg = expectMsgType[Failed]
msg match {
case Failed(barrier, thr: BarrierEmpty) if (thr == BarrierEmpty(Data(Set(), "", Nil, thr.data.deadline), "cannot remove RoleName(a): no client to remove"))
case x fail("Expected " + Failed(barrier, BarrierEmpty(Data(Set(), "", Nil, null), "cannot remove RoleName(a): no client to remove")) + " but got " + x)
}
barrier ! NodeInfo(A, AddressFromURIString("akka://sys"), a.ref)
a.send(barrier, EnterBarrier("bar9"))
a.expectMsg(ToClient(BarrierResult("bar9", false)))
@ -204,7 +216,11 @@ class BarrierSpec extends AkkaSpec(BarrierSpec.config) with ImplicitSender with
barrier ! nodeB
a.send(barrier, EnterBarrier("bar10"))
EventFilter[BarrierTimeout](occurrences = 1) intercept {
expectMsg(7 seconds, Failed(barrier, BarrierTimeout(Data(Set(nodeA, nodeB), "bar10", a.ref :: Nil))))
val msg = expectMsgType[Failed](7 seconds)
msg match {
case Failed(barrier, thr: BarrierTimeout) if (thr == BarrierTimeout(Data(Set(nodeA, nodeB), "bar10", a.ref :: Nil, thr.data.deadline)))
case x fail("Expected " + Failed(barrier, BarrierTimeout(Data(Set(nodeA, nodeB), "bar10", a.ref :: Nil, null))) + " but got " + x)
}
}
}
@ -217,7 +233,11 @@ class BarrierSpec extends AkkaSpec(BarrierSpec.config) with ImplicitSender with
EventFilter[DuplicateNode](occurrences = 1) intercept {
barrier ! nodeB
}
expectMsg(Failed(barrier, DuplicateNode(Data(Set(nodeA), "", Nil), nodeB)))
val msg = expectMsgType[Failed]
msg match {
case Failed(barrier, thr: DuplicateNode) if (thr == DuplicateNode(Data(Set(nodeA), "", Nil, thr.data.deadline), nodeB))
case x fail("Expected " + Failed(barrier, DuplicateNode(Data(Set(nodeA), "", Nil, null), nodeB)) + " but got " + x)
}
}
"finally have no failure messages left" taggedAs TimingTest in {
@ -267,7 +287,7 @@ class BarrierSpec extends AkkaSpec(BarrierSpec.config) with ImplicitSender with
b.expectMsg(ToClient(Done))
a.send(barrier, EnterBarrier("bar11"))
noMsg(a, b)
within(2 second) {
within(2 seconds) {
b.send(barrier, EnterBarrier("bar11"))
a.expectMsg(ToClient(BarrierResult("bar11", true)))
b.expectMsg(ToClient(BarrierResult("bar11", true)))
@ -286,7 +306,7 @@ class BarrierSpec extends AkkaSpec(BarrierSpec.config) with ImplicitSender with
c.expectMsg(ToClient(Done))
b.send(barrier, EnterBarrier("bar12"))
noMsg(a, b, c)
within(2 second) {
within(2 seconds) {
c.send(barrier, EnterBarrier("bar12"))
a.expectMsg(ToClient(BarrierResult("bar12", true)))
b.expectMsg(ToClient(BarrierResult("bar12", true)))
@ -308,7 +328,7 @@ class BarrierSpec extends AkkaSpec(BarrierSpec.config) with ImplicitSender with
barrier ! Remove(A)
barrier ! ClientDisconnected(A)
noMsg(a, b, c)
b.within(2 second) {
b.within(2 seconds) {
barrier ! Remove(C)
b.expectMsg(ToClient(BarrierResult("bar13", true)))
}
@ -391,7 +411,7 @@ class BarrierSpec extends AkkaSpec(BarrierSpec.config) with ImplicitSender with
barrier ! nodeB
a.expectMsg(ToClient(Done))
b.expectMsg(ToClient(Done))
a.send(barrier, EnterBarrier("bar18", Option(Timeout.durationToTimeout(2 seconds))))
a.send(barrier, EnterBarrier("bar18", Option(2 seconds)))
EventFilter[BarrierTimeout](occurrences = 1) intercept {
Thread.sleep(4000)
}
@ -437,16 +457,64 @@ class BarrierSpec extends AkkaSpec(BarrierSpec.config) with ImplicitSender with
barrier ! nodeB
a.expectMsg(ToClient(Done))
b.expectMsg(ToClient(Done))
a.send(barrier, EnterBarrier("bar20", Option(Timeout.durationToTimeout(2 seconds))))
a.send(barrier, EnterBarrier("bar20", Option(2 seconds)))
EventFilter[FailedBarrier](occurrences = 1) intercept {
b.send(barrier, FailBarrier("bar20"))
a.expectMsg(ToClient(BarrierResult("bar20", false)))
b.expectNoMsg(1 second)
}
a.send(barrier, EnterBarrier("bar21"))
b.send(barrier, EnterBarrier("bar21"))
a.expectMsg(ToClient(BarrierResult("bar21", false)))
b.expectMsg(ToClient(BarrierResult("bar21", false)))
}
"timeout within the shortest timeout if the new timeout is shorter" taggedAs TimingTest in {
val barrier = getController(3)
val a, b, c = TestProbe()
val nodeA = NodeInfo(A, AddressFromURIString("akka://sys"), a.ref)
val nodeB = NodeInfo(B, AddressFromURIString("akka://sys"), b.ref)
val nodeC = NodeInfo(C, AddressFromURIString("akka://sys"), c.ref)
barrier ! nodeA
barrier ! nodeB
barrier ! nodeC
a.expectMsg(ToClient(Done))
b.expectMsg(ToClient(Done))
c.expectMsg(ToClient(Done))
a.send(barrier, EnterBarrier("bar22", Option(10 seconds)))
b.send(barrier, EnterBarrier("bar22", Option(2 seconds)))
EventFilter[BarrierTimeout](occurrences = 1) intercept {
Thread.sleep(4000)
}
c.send(barrier, EnterBarrier("bar22"))
a.expectMsg(ToClient(BarrierResult("bar22", false)))
b.expectMsg(ToClient(BarrierResult("bar22", false)))
c.expectMsg(ToClient(BarrierResult("bar22", false)))
}
"timeout within the shortest timeout if the new timeout is longer" taggedAs TimingTest in {
val barrier = getController(3)
val a, b, c = TestProbe()
val nodeA = NodeInfo(A, AddressFromURIString("akka://sys"), a.ref)
val nodeB = NodeInfo(B, AddressFromURIString("akka://sys"), b.ref)
val nodeC = NodeInfo(C, AddressFromURIString("akka://sys"), c.ref)
barrier ! nodeA
barrier ! nodeB
barrier ! nodeC
a.expectMsg(ToClient(Done))
b.expectMsg(ToClient(Done))
c.expectMsg(ToClient(Done))
a.send(barrier, EnterBarrier("bar23", Option(2 seconds)))
b.send(barrier, EnterBarrier("bar23", Option(10 seconds)))
EventFilter[BarrierTimeout](occurrences = 1) intercept {
Thread.sleep(4000)
}
c.send(barrier, EnterBarrier("bar23"))
a.expectMsg(ToClient(BarrierResult("bar23", false)))
b.expectMsg(ToClient(BarrierResult("bar23", false)))
c.expectMsg(ToClient(BarrierResult("bar23", false)))
}
"finally have no failure messages left" taggedAs TimingTest in {
expectNoMsg(1 second)
}
@ -489,4 +557,7 @@ class BarrierSpec extends AkkaSpec(BarrierSpec.config) with ImplicitSender with
probes foreach (_.msgAvailable must be(false))
}
private def data(clients: Set[Controller.NodeInfo], barrier: String, arrived: List[ActorRef], previous: Data): Data = {
Data(clients, barrier, arrived, previous.deadline)
}
}

View file

@ -186,7 +186,7 @@ abstract class MultiNodeSpec(val myself: RoleName, _system: ActorSystem, _roles:
* Enter the named barriers in the order given. Use the remaining duration from
* the innermost enclosing `within` block or the default `BarrierTimeout`
*/
def enter(name: String*) {
def enterBarrier(name: String*) {
testConductor.enter(Timeout.durationToTimeout(remainingOr(testConductor.Settings.BarrierTimeout.duration)), name)
}
@ -202,13 +202,11 @@ abstract class MultiNodeSpec(val myself: RoleName, _system: ActorSystem, _roles:
/**
* Enrich `.await()` onto all Awaitables, using remaining duration from the innermost
* enclosing `within` block or BarrierTimeout.
*
* FIXME Is it really BarrierTimeout we want here? That seems like an awfully long time.
* enclosing `within` block or QueryTimeout.
*/
implicit def awaitHelper[T](w: Awaitable[T]) = new AwaitHelper(w)
class AwaitHelper[T](w: Awaitable[T]) {
def await: T = Await.result(w, remainingOr(testConductor.Settings.BarrierTimeout.duration))
def await: T = Await.result(w, remainingOr(testConductor.Settings.QueryTimeout.duration))
}
/*
@ -217,9 +215,11 @@ abstract class MultiNodeSpec(val myself: RoleName, _system: ActorSystem, _roles:
private val controllerAddr = new InetSocketAddress(nodeNames(0), 4711)
if (selfIndex == 0) {
testConductor.startController(initialParticipants, myself, controllerAddr).await
Await.result(testConductor.startController(initialParticipants, myself, controllerAddr),
testConductor.Settings.BarrierTimeout.duration)
} else {
testConductor.startClient(myself, controllerAddr).await
Await.result(testConductor.startClient(myself, controllerAddr),
testConductor.Settings.BarrierTimeout.duration)
}
// now add deployments, if so desired