diff --git a/src/core/Akka.Cluster.Tests.MultiNode/MemberWeaklyUpSpec.cs b/src/core/Akka.Cluster.Tests.MultiNode/MemberWeaklyUpSpec.cs index 5b8a6c6f99f..853098bea87 100644 --- a/src/core/Akka.Cluster.Tests.MultiNode/MemberWeaklyUpSpec.cs +++ b/src/core/Akka.Cluster.Tests.MultiNode/MemberWeaklyUpSpec.cs @@ -18,40 +18,41 @@ namespace Akka.Cluster.Tests.MultiNode { public class MemberWeaklyUpConfig : MultiNodeConfig { - public RoleName First { get; } = new RoleName("first"); - public RoleName Second { get; } = new RoleName("second"); - public RoleName Third { get; } = new RoleName("third"); - public RoleName Fourth { get; } = new RoleName("fourth"); - public RoleName Fifth { get; } = new RoleName("fifth"); + public RoleName First { get; } + public RoleName Second { get; } + public RoleName Third { get; } + public RoleName Fourth { get; } + public RoleName Fifth { get; } public MemberWeaklyUpConfig() { + First = Role("first"); + Second = Role("second"); + Third = Role("third"); + Fourth = Role("fourth"); + Fifth = Role("fifth"); + CommonConfig = DebugConfig(on: false) .WithFallback(ConfigurationFactory.ParseString(@" - akka.remote.retry-gate-closed-for = 3 s + akka.remote.retry-gate-closed-for = 3s akka.cluster.allow-weakly-up-members = on")) .WithFallback(MultiNodeClusterSpec.ClusterConfig()); TestTransport = true; } } - public class MemberWeaklyUpMultiNode1 : MemberWeaklyUpSpec { } - public class MemberWeaklyUpMultiNode2 : MemberWeaklyUpSpec { } - public class MemberWeaklyUpMultiNode3 : MemberWeaklyUpSpec { } - public class MemberWeaklyUpMultiNode4 : MemberWeaklyUpSpec { } - public class MemberWeaklyUpMultiNode5 : MemberWeaklyUpSpec { } - public abstract class MemberWeaklyUpSpec : MultiNodeClusterSpec + public class MemberWeaklyUpSpec : MultiNodeClusterSpec { private readonly MemberWeaklyUpConfig _config; private readonly ImmutableArray _side1; private readonly ImmutableArray _side2; - protected MemberWeaklyUpSpec() : this(new MemberWeaklyUpConfig()) + public MemberWeaklyUpSpec() : this(new MemberWeaklyUpConfig()) { } - protected MemberWeaklyUpSpec(MemberWeaklyUpConfig config) : base(config, typeof(MemberWeaklyUpSpec)) + private MemberWeaklyUpSpec(MemberWeaklyUpConfig config) : base(config, typeof(MemberWeaklyUpSpec)) { _config = config; _side1 = ImmutableArray.CreateRange(new[] { config.First, config.Second }); @@ -139,9 +140,14 @@ public void A_cluster_of_3_members_should_change_status_to_Up_after_healed_netwo { Within(TimeSpan.FromSeconds(20), () => { - foreach (var role1 in _side1) - foreach (var role2 in _side2) - TestConductor.PassThrough(role1, role2, ThrottleTransportAdapter.Direction.Both).Wait(TimeSpan.FromSeconds(3)); + RunOn(() => + { + foreach (var role1 in _side1) + foreach (var role2 in _side2) + { + TestConductor.PassThrough(role1, role2, ThrottleTransportAdapter.Direction.Both).Wait(TimeSpan.FromSeconds(3)); + } + }, _config.First); EnterBarrier("after-passThrough"); diff --git a/src/core/Akka.Remote.TestKit/CommandLine.cs b/src/core/Akka.Remote.TestKit/CommandLine.cs index 026ccb06e4c..24fd7813c11 100644 --- a/src/core/Akka.Remote.TestKit/CommandLine.cs +++ b/src/core/Akka.Remote.TestKit/CommandLine.cs @@ -7,6 +7,7 @@ using System; using System.Collections.Specialized; +using Akka.Configuration; namespace Akka.Remote.TestKit { @@ -33,7 +34,15 @@ public class CommandLine { if (!arg.StartsWith("-D")) continue; var tokens = arg.Substring(2).Split('='); - dictionary.Add(tokens[0], tokens[1]); + + if (tokens.Length == 2) + { + dictionary.Add(tokens[0], tokens[1]); + } + else + { + throw new ConfigurationException($"Command line parameter '{arg}' should follow the pattern [-Dmultinode.=]."); + } } return dictionary; }); diff --git a/src/core/Akka.Remote.TestKit/Controller.cs b/src/core/Akka.Remote.TestKit/Controller.cs index 2cc8eb8e3ae..d259f78062d 100644 --- a/src/core/Akka.Remote.TestKit/Controller.cs +++ b/src/core/Akka.Remote.TestKit/Controller.cs @@ -146,69 +146,52 @@ internal interface IHaveNodeInfo NodeInfo Node { get; } } - internal sealed class NodeInfo + internal sealed class NodeInfo : IEquatable { - readonly RoleName _name; - readonly Address _addr; - readonly IActorRef _fsm; - public NodeInfo(RoleName name, Address addr, IActorRef fsm) { - _name = name; - _addr = addr; - _fsm = fsm; + Name = name; + Addr = addr; + FSM = fsm; } - public RoleName Name - { - get { return _name; } - } + public RoleName Name { get; } - public Address Addr - { - get { return _addr; } - } + public Address Addr { get; } - public IActorRef FSM - { - get { return _fsm; } - } + public IActorRef FSM { get; } - bool Equals(NodeInfo other) + public bool Equals(NodeInfo other) { - return Equals(_name, other._name) && Equals(_addr, other._addr) && Equals(_fsm, other._fsm); + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + return Equals(Name, other.Name) && Equals(Addr, other.Addr) && Equals(FSM, other.FSM); } /// - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - if (ReferenceEquals(this, obj)) return true; - return obj is NodeInfo && Equals((NodeInfo) obj); - } + public override bool Equals(object obj) => obj is NodeInfo node && Equals(node); /// public override int GetHashCode() { unchecked { - int hashCode = (_name != null ? _name.GetHashCode() : 0); - hashCode = (hashCode*397) ^ (_addr != null ? _addr.GetHashCode() : 0); - hashCode = (hashCode*397) ^ (_fsm != null ? _fsm.GetHashCode() : 0); + int hashCode = (Name != null ? Name.GetHashCode() : 0); + hashCode = (hashCode*397) ^ (Addr != null ? Addr.GetHashCode() : 0); + hashCode = (hashCode*397) ^ (FSM != null ? FSM.GetHashCode() : 0); return hashCode; } } + public override string ToString() => $"NodeInfo({Name}, {Addr})"; + /// /// Compares two specified for equality. /// /// The first used for comparison /// The second used for comparison /// true if both are equal; otherwise false - public static bool operator ==(NodeInfo left, NodeInfo right) - { - return Equals(left, right); - } + public static bool operator ==(NodeInfo left, NodeInfo right) => Equals(left, right); /// /// Compares two specified for inequality. @@ -216,10 +199,7 @@ public override int GetHashCode() /// The first used for comparison /// The second used for comparison /// true if both are not equal; otherwise false - public static bool operator !=(NodeInfo left, NodeInfo right) - { - return !Equals(left, right); - } + public static bool operator !=(NodeInfo left, NodeInfo right) => !Equals(left, right); } public sealed class CreateServerFSM : INoSerializationVerificationNeeded @@ -270,23 +250,23 @@ protected override SupervisorStrategy SupervisorStrategy() { return new OneForOneStrategy(e => { - var barrierTimeout = e as BarrierCoordinator.BarrierTimeoutException; - if (barrierTimeout != null) return FailBarrier(barrierTimeout.BarrierData); - var failedBarrier = e as BarrierCoordinator.FailedBarrierException; - if (failedBarrier != null) return FailBarrier(failedBarrier.BarrierData); - var barrierEmpty = e as BarrierCoordinator.BarrierEmptyException; - if(barrierEmpty != null) return Directive.Resume; - var wrongBarrier = e as BarrierCoordinator.WrongBarrierException; - if (wrongBarrier != null) + switch (e) { - wrongBarrier.Client.Tell(new ToClient(new BarrierResult(wrongBarrier.Barrier, false))); - return FailBarrier(wrongBarrier.BarrierData); + case BarrierCoordinator.BarrierTimeoutException barrierTimeout: + return FailBarrier(barrierTimeout.BarrierData); + case BarrierCoordinator.FailedBarrierException failedBarrier: + return FailBarrier(failedBarrier.BarrierData); + case BarrierCoordinator.BarrierEmptyException barrierEmpty: + return Directive.Resume; + case BarrierCoordinator.WrongBarrierException wrongBarrier: + wrongBarrier.Client.Tell(new ToClient(new BarrierResult(wrongBarrier.Barrier, false))); + return FailBarrier(wrongBarrier.BarrierData); + case BarrierCoordinator.ClientLostException clientLost: + return FailBarrier(clientLost.BarrierData); + case BarrierCoordinator.DuplicateNodeException duplicateNode: + return FailBarrier(duplicateNode.BarrierData); + default: throw new InvalidOperationException($"Cannot process exception of type {e.GetType()}"); } - var clientLost = e as BarrierCoordinator.ClientLostException; - if (clientLost != null) return FailBarrier(clientLost.BarrierData); - var duplicateNode = e as BarrierCoordinator.DuplicateNodeException; - if (duplicateNode != null) return FailBarrier(duplicateNode.BarrierData); - throw new InvalidOperationException($"Cannot process exception of type {e.GetType()}"); }); } @@ -351,63 +331,59 @@ protected override void OnReceive(object message) } if (message is IServerOp) { - if (message is EnterBarrier) - { - _barrier.Forward(message); - return; - } - if (message is FailBarrier) + switch (message) { - _barrier.Forward(message); - return; - } - var getAddress = message as GetAddress; - if (getAddress != null) - { - var node = getAddress.Node; - if (_nodes.TryGetValue(node, out var replyNodeInfo)) - Sender.Tell(new ToClient(new AddressReply(node, replyNodeInfo.Addr))); - else - { - _addrInterest = _addrInterest.SetItem(node, - (_addrInterest.TryGetValue(node, out var existing) - ? existing - : ImmutableHashSet.Create() + case EnterBarrier _: _barrier.Forward(message); return; + case FailBarrier _: _barrier.Forward(message); return; + case GetAddress getAddress: + var node = getAddress.Node; + if (_nodes.TryGetValue(node, out var replyNodeInfo)) + Sender.Tell(new ToClient(new AddressReply(node, replyNodeInfo.Addr))); + else + { + _addrInterest = _addrInterest.SetItem(node, + (_addrInterest.TryGetValue(node, out var existing) + ? existing + : ImmutableHashSet.Create() ).Add(Sender)); - } - return; + } + return; + case Done _: return; //FIXME what should happen? } - if (message is Done) return; //FIXME what should happen? } if (message is ICommandOp) { - var throttle = message as Throttle; - if (throttle != null) - { - var t = _nodes[throttle.Target]; - _nodes[throttle.Node].FSM.Forward(new ToClient(new ThrottleMsg(t.Addr, throttle.Direction, throttle.RateMBit))); - return; - } - var disconnect = message as Disconnect; - if (disconnect != null) - { - var t = _nodes[disconnect.Target]; - _nodes[disconnect.Node].FSM.Forward((new ToClient(new DisconnectMsg(t.Addr, disconnect.Abort)))); - return; - } - var terminate = message as Terminate; - if (terminate != null) + switch (message) { - _barrier.Tell(new BarrierCoordinator.RemoveClient(terminate.Node)); - _nodes[terminate.Node].FSM.Forward(new ToClient(new TerminateMsg(terminate.ShutdownOrExit))); - _nodes = _nodes.Remove(terminate.Node); - return; - } - var remove = message as Remove; - if (remove != null) - { - _barrier.Tell(new BarrierCoordinator.RemoveClient(remove.Node)); - return; + case Throttle throttle: + { + if (!_nodes.TryGetValue(throttle.Target, out var target)) throw new IllegalActorStateException($"Throttle target {throttle.Target} was not found among nodes registered in {nameof(Controller)}: {string.Join(", ", _nodes.Keys)}"); + if (!_nodes.TryGetValue(throttle.Node, out var source)) throw new IllegalActorStateException($"Throttle source {throttle.Node} was not found among nodes registered in {nameof(Controller)}: {string.Join(", ", _nodes.Keys)}"); + + source.FSM.Forward(new ToClient(new ThrottleMsg(target.Addr, throttle.Direction, throttle.RateMBit))); + return; + } + case Disconnect disconnect: + { + if (!_nodes.TryGetValue(disconnect.Target, out var target)) throw new IllegalActorStateException($"Disconnect target {disconnect.Target} was not found among nodes registered in {nameof(Controller)}: {string.Join(", ", _nodes.Keys)}"); + if (!_nodes.TryGetValue(disconnect.Node, out var source)) throw new IllegalActorStateException($"Disconnect source {disconnect.Node} was not found among nodes registered in {nameof(Controller)}: {string.Join(", ", _nodes.Keys)}"); + + source.FSM.Forward((new ToClient(new DisconnectMsg(target.Addr, disconnect.Abort)))); + return; + } + case Terminate terminate: + { + _barrier.Tell(new BarrierCoordinator.RemoveClient(terminate.Node)); + + if (!_nodes.TryGetValue(terminate.Node, out var node)) throw new IllegalActorStateException($"Terminate target {terminate.Node} was not found among nodes registered in {nameof(Controller)}: {string.Join(", ", _nodes.Keys)}"); + + node.FSM.Forward(new ToClient(new TerminateMsg(terminate.ShutdownOrExit))); + _nodes = _nodes.Remove(terminate.Node); + return; + } + case Remove remove: + _barrier.Tell(new BarrierCoordinator.RemoveClient(remove.Node)); + return; } } if (message is GetNodes) diff --git a/src/core/Akka.Remote.TestKit/DataTypes.cs b/src/core/Akka.Remote.TestKit/DataTypes.cs index 009a954fb4b..5b62e0c751c 100644 --- a/src/core/Akka.Remote.TestKit/DataTypes.cs +++ b/src/core/Akka.Remote.TestKit/DataTypes.cs @@ -13,34 +13,25 @@ namespace Akka.Remote.TestKit { - public sealed class RoleName + public sealed class RoleName : IEquatable { - readonly string _name; - public RoleName(string name) { - _name = name; + Name = name; } - bool Equals(RoleName other) + public bool Equals(RoleName other) { - return string.Equals(_name, other._name); + if (ReferenceEquals(other, null)) return false; + if (ReferenceEquals(this, other)) return true; + return string.Equals(Name, other.Name); } /// - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != this.GetType()) return false; - return Equals((RoleName)obj); - } + public override bool Equals(object obj) => obj is RoleName role && Equals(role); /// - public override int GetHashCode() - { - return (_name != null ? _name.GetHashCode() : 0); - } + public override int GetHashCode() => (Name != null ? Name.GetHashCode() : 0); /// /// Compares two specified for equality. @@ -48,10 +39,7 @@ public override int GetHashCode() /// The first used for comparison /// The second used for comparison /// true if both are equal; otherwise false - public static bool operator ==(RoleName left, RoleName right) - { - return Equals(left, right); - } + public static bool operator ==(RoleName left, RoleName right) => Equals(left, right); /// /// Compares two specified for inequality. @@ -59,21 +47,12 @@ public override int GetHashCode() /// The first used for comparison /// The second used for comparison /// true if both are not equal; otherwise false - public static bool operator !=(RoleName left, RoleName right) - { - return !Equals(left, right); - } + public static bool operator !=(RoleName left, RoleName right) => !Equals(left, right); - public string Name - { - get { return _name; } - } + public string Name { get; } /// - public override string ToString() - { - return $"RoleName({_name})"; - } + public override string ToString() => $"RoleName({Name})"; } //TODO: This is messy, better way to do this?