using Shouldly; using Xunit; using ZB.MOM.WW.OtOpcUa.Core.Authorization; namespace ZB.MOM.WW.OtOpcUa.Core.Tests.Authorization; [Trait("Category", "Unit")] public sealed class UserAuthorizationStateTests { private static readonly DateTime Now = new(2026, 4, 19, 12, 0, 0, DateTimeKind.Utc); private static UserAuthorizationState Fresh(DateTime resolved) => new() { SessionId = "s", ClusterId = "c1", LdapGroups = ["cn=ops"], MembershipResolvedUtc = resolved, AuthGenerationId = 1, MembershipVersion = 1, }; [Fact] public void FreshlyResolved_Is_NotStale_NorNeedsRefresh() { var session = Fresh(Now); session.IsStale(Now.AddMinutes(1)).ShouldBeFalse(); session.NeedsRefresh(Now.AddMinutes(1)).ShouldBeFalse(); } [Fact] public void NeedsRefresh_FiresAfter_FreshnessInterval() { var session = Fresh(Now); session.NeedsRefresh(Now.AddMinutes(16)).ShouldBeFalse("past freshness but also past the 5-min staleness ceiling — should be Stale, not NeedsRefresh"); } [Fact] public void NeedsRefresh_TrueBetween_Freshness_And_Staleness_Windows() { // Custom: freshness=2 min, staleness=10 min → between 2 and 10 min NeedsRefresh fires. var session = Fresh(Now) with { MembershipFreshnessInterval = TimeSpan.FromMinutes(2), AuthCacheMaxStaleness = TimeSpan.FromMinutes(10), }; session.NeedsRefresh(Now.AddMinutes(5)).ShouldBeTrue(); session.IsStale(Now.AddMinutes(5)).ShouldBeFalse(); } [Fact] public void IsStale_TrueAfter_StalenessWindow() { var session = Fresh(Now); session.IsStale(Now.AddMinutes(6)).ShouldBeTrue("default AuthCacheMaxStaleness is 5 min"); } }