using Shouldly; using Xunit; using ZB.MOM.WW.OtOpcUa.Core.Abstractions; using ZB.MOM.WW.OtOpcUa.Core.Resilience; namespace ZB.MOM.WW.OtOpcUa.Core.Tests.Resilience; [Trait("Category", "Unit")] public sealed class DriverResilienceOptionsTests { [Theory] [InlineData(DriverTier.A)] [InlineData(DriverTier.B)] [InlineData(DriverTier.C)] public void TierDefaults_Cover_EveryCapability(DriverTier tier) { var defaults = DriverResilienceOptions.GetTierDefaults(tier); foreach (var capability in Enum.GetValues()) defaults.ShouldContainKey(capability); } [Theory] [InlineData(DriverTier.A)] [InlineData(DriverTier.B)] [InlineData(DriverTier.C)] public void Write_NeverRetries_ByDefault(DriverTier tier) { var defaults = DriverResilienceOptions.GetTierDefaults(tier); defaults[DriverCapability.Write].RetryCount.ShouldBe(0); } [Theory] [InlineData(DriverTier.A)] [InlineData(DriverTier.B)] [InlineData(DriverTier.C)] public void AlarmAcknowledge_NeverRetries_ByDefault(DriverTier tier) { var defaults = DriverResilienceOptions.GetTierDefaults(tier); defaults[DriverCapability.AlarmAcknowledge].RetryCount.ShouldBe(0); } [Theory] [InlineData(DriverTier.A, DriverCapability.Read)] [InlineData(DriverTier.A, DriverCapability.HistoryRead)] [InlineData(DriverTier.B, DriverCapability.Discover)] [InlineData(DriverTier.B, DriverCapability.Probe)] [InlineData(DriverTier.C, DriverCapability.AlarmSubscribe)] public void IdempotentCapabilities_Retry_ByDefault(DriverTier tier, DriverCapability capability) { var defaults = DriverResilienceOptions.GetTierDefaults(tier); defaults[capability].RetryCount.ShouldBeGreaterThan(0); } [Fact] public void TierC_DisablesCircuitBreaker_DeferringToSupervisor() { var defaults = DriverResilienceOptions.GetTierDefaults(DriverTier.C); foreach (var (_, policy) in defaults) policy.BreakerFailureThreshold.ShouldBe(0, "Tier C breaker is handled by the Proxy supervisor (decision #68)"); } [Theory] [InlineData(DriverTier.A)] [InlineData(DriverTier.B)] public void TierAAndB_EnableCircuitBreaker(DriverTier tier) { var defaults = DriverResilienceOptions.GetTierDefaults(tier); foreach (var (_, policy) in defaults) policy.BreakerFailureThreshold.ShouldBeGreaterThan(0); } [Fact] public void Resolve_Uses_TierDefaults_When_NoOverride() { var options = new DriverResilienceOptions { Tier = DriverTier.A }; var resolved = options.Resolve(DriverCapability.Read); resolved.ShouldBe(DriverResilienceOptions.GetTierDefaults(DriverTier.A)[DriverCapability.Read]); } [Fact] public void Resolve_Uses_Override_When_Configured() { var custom = new CapabilityPolicy(TimeoutSeconds: 42, RetryCount: 7, BreakerFailureThreshold: 9); var options = new DriverResilienceOptions { Tier = DriverTier.A, CapabilityPolicies = new Dictionary { [DriverCapability.Read] = custom, }, }; options.Resolve(DriverCapability.Read).ShouldBe(custom); options.Resolve(DriverCapability.Write).ShouldBe( DriverResilienceOptions.GetTierDefaults(DriverTier.A)[DriverCapability.Write]); } }