using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Diagnostics.HealthChecks; using Microsoft.Extensions.Options; using Shouldly; using Xunit; using ZB.MOM.WW.Health; using ZB.MOM.WW.Health.Akka; using ZB.MOM.WW.OtOpcUa.Host.Health; namespace ZB.MOM.WW.OtOpcUa.Host.Tests.Health; /// /// Pins OtOpcUa's active-tier wiring. The rule (oldest Up member of a role) now lives in the /// shared ClusterActiveNode and is tested there against a real two-node cluster; what stays /// OtOpcUa's own decision — and what regressed in lmxopcua#494 — is which check is /// registered on the active tag, and with which roles. /// public sealed class ActiveTierRegistrationTests { private static HealthCheckRegistration ClusterPrimaryRegistration(bool hasAdmin) => new ServiceCollection() .AddOtOpcUaHealth(hasAdmin) .BuildServiceProvider() .GetRequiredService>() .Value.Registrations .Where(r => r.Name == "cluster-primary") .ShouldHaveSingleItem(); [Fact] public void Active_tier_uses_the_shared_ActiveNodeHealthCheck() { // Not a bespoke copy. Two apps in the family independently hand-rolled this check because the // shared one selected by RoleLeader; since Health 0.3.0 the shared one is the correct rule, so // a private reimplementation reappearing here would be the regression. var registration = ClusterPrimaryRegistration(hasAdmin: true); registration.Factory(new ServiceCollection().BuildServiceProvider()) .ShouldBeOfType(); } [Theory] [InlineData(true)] [InlineData(false)] public void Active_tier_check_is_registered_on_every_node_role(bool hasAdmin) { // Registered on driver-only nodes too, unlike the admin-only configdb probe. A site pair needs // an active tier just as much as the central pair does — under the old admin-scoped check all // four driver-only site nodes answered 200 and no consumer could find a site's Primary. ClusterPrimaryRegistration(hasAdmin).Tags.ShouldContain(ZbHealthTags.Active); } [Fact] public void Active_tier_check_is_not_on_the_ready_tier() { // Readiness must not depend on being the active node: a healthy standby is ready to serve, and // tagging it ready would take the whole pair out of rotation whenever one node is standby. ClusterPrimaryRegistration(hasAdmin: true).Tags.ShouldNotContain(ZbHealthTags.Ready); } }