using Akka.Cluster.Hosting; using Akka.Cluster.Hosting.SBR; using Shouldly; using Xunit; namespace ZB.MOM.WW.OtOpcUa.Cluster.Tests; /// /// Guards that the split-brain-resolver strategy stays set explicitly in code (arch-review 03/S1, /// premise corrected — see #11). Akka.Cluster.Hosting already enables an SBR downing provider by default /// (it applies SplitBrainResolverOption.Default when /// is null, which reads the akka.conf keep-oldest block), so the cluster is not NoDowning even /// without the typed option. These tests assert /// sets the typed /// KeepOldestOption { DownIfAlone = true } so the strategy is explicit in code rather than relying on /// the framework default — a future refactor cannot silently drop that explicitness. (Failover behaviour is /// separately verified by HardKillFailoverTests, which passes regardless of activation path.) /// public sealed class SplitBrainResolverActivationTests { private static AkkaClusterOptions SampleOptions() => new() { SeedNodes = new[] { "akka.tcp://otopcua@127.0.0.1:4053" }, Roles = new[] { "admin", "driver" }, }; /// Verifies the cluster options carry an explicit split-brain resolver strategy. [Fact] public void BuildClusterOptions_sets_an_explicit_split_brain_resolver() { var options = ServiceCollectionExtensions.BuildClusterOptions(SampleOptions()); options.SplitBrainResolver.ShouldNotBeNull( "SplitBrainResolver must be set explicitly in code — keeps the strategy independent of Akka.Cluster.Hosting's default provider rather than relying on it."); } /// Verifies the resolver is keep-oldest with down-if-alone (correct for a 2-node pair). [Fact] public void BuildClusterOptions_uses_keep_oldest_with_down_if_alone() { var options = ServiceCollectionExtensions.BuildClusterOptions(SampleOptions()); var keepOldest = options.SplitBrainResolver.ShouldBeOfType(); keepOldest.DownIfAlone.ShouldBe(true); } /// Verifies seed nodes and roles are still threaded through unchanged. [Fact] public void BuildClusterOptions_preserves_seed_nodes_and_roles() { var input = SampleOptions(); var options = ServiceCollectionExtensions.BuildClusterOptions(input); options.SeedNodes.ShouldBe(input.SeedNodes); options.Roles.ShouldBe(input.Roles); } }