// Tests for account claim hot-reload with diff-based update detection. // Go reference: accounts_test.go TestUpdateAccountClaims, updateAccountClaimsWithRefresh (~line 3374). using NATS.Server.Auth; namespace NATS.Server.Auth.Tests.Auth; public class AccountClaimReloadTests { // 1. First update: all provided fields are reported as changed. [Fact] public void UpdateAccountClaims_FirstUpdate_AllFieldsChanged() { var account = new Account("test"); var claims = new AccountClaimData { MaxConnections = 10, MaxSubscriptions = 100, Nkey = "NKEY123", Issuer = "ISSUER_OP", ExpiresAt = new DateTime(2030, 1, 1, 0, 0, 0, DateTimeKind.Utc), }; var result = account.UpdateAccountClaims(claims); result.Changed.ShouldBeTrue(); result.ChangedFields.ShouldContain(nameof(AccountClaimData.MaxConnections)); result.ChangedFields.ShouldContain(nameof(AccountClaimData.MaxSubscriptions)); result.ChangedFields.ShouldContain(nameof(AccountClaimData.Nkey)); result.ChangedFields.ShouldContain(nameof(AccountClaimData.Issuer)); result.ChangedFields.ShouldContain(nameof(AccountClaimData.ExpiresAt)); result.ChangedFields.Count.ShouldBe(5); } // 2. Applying the exact same claims a second time returns Changed=false. [Fact] public void UpdateAccountClaims_NoChange_ReturnsFalse() { var account = new Account("test"); var claims = new AccountClaimData { MaxConnections = 5, MaxSubscriptions = 50, Nkey = "NKEY_A", Issuer = "OP", }; account.UpdateAccountClaims(claims); var result = account.UpdateAccountClaims(claims); result.Changed.ShouldBeFalse(); result.ChangedFields.Count.ShouldBe(0); } // 3. Changing MaxConnections is detected. [Fact] public void UpdateAccountClaims_MaxConnectionsChanged_Detected() { var account = new Account("test"); var initial = new AccountClaimData { MaxConnections = 10 }; account.UpdateAccountClaims(initial); var updated = new AccountClaimData { MaxConnections = 20 }; var result = account.UpdateAccountClaims(updated); result.Changed.ShouldBeTrue(); result.ChangedFields.ShouldContain(nameof(AccountClaimData.MaxConnections)); account.MaxConnections.ShouldBe(20); } // 4. Changing MaxSubscriptions is detected. [Fact] public void UpdateAccountClaims_MaxSubscriptionsChanged_Detected() { var account = new Account("test"); var initial = new AccountClaimData { MaxSubscriptions = 100 }; account.UpdateAccountClaims(initial); var updated = new AccountClaimData { MaxSubscriptions = 200 }; var result = account.UpdateAccountClaims(updated); result.Changed.ShouldBeTrue(); result.ChangedFields.ShouldContain(nameof(AccountClaimData.MaxSubscriptions)); account.MaxSubscriptions.ShouldBe(200); } // 5. Changing Nkey is detected. [Fact] public void UpdateAccountClaims_NkeyChanged_Detected() { var account = new Account("test"); var initial = new AccountClaimData { Nkey = "OLD_NKEY" }; account.UpdateAccountClaims(initial); var updated = new AccountClaimData { Nkey = "NEW_NKEY" }; var result = account.UpdateAccountClaims(updated); result.Changed.ShouldBeTrue(); result.ChangedFields.ShouldContain(nameof(AccountClaimData.Nkey)); account.Nkey.ShouldBe("NEW_NKEY"); } // 6. Changing Issuer is detected. [Fact] public void UpdateAccountClaims_IssuerChanged_Detected() { var account = new Account("test"); var initial = new AccountClaimData { Issuer = "ISSUER_A" }; account.UpdateAccountClaims(initial); var updated = new AccountClaimData { Issuer = "ISSUER_B" }; var result = account.UpdateAccountClaims(updated); result.Changed.ShouldBeTrue(); result.ChangedFields.ShouldContain(nameof(AccountClaimData.Issuer)); account.Issuer.ShouldBe("ISSUER_B"); } // 7. A successful claim update increments the generation counter. [Fact] public void UpdateAccountClaims_IncrementsGeneration() { var account = new Account("test"); var before = account.GenerationId; var claims = new AccountClaimData { MaxConnections = 5 }; account.UpdateAccountClaims(claims); account.GenerationId.ShouldBe(before + 1); } // 8. HasClaims is false on a fresh account. [Fact] public void HasClaims_BeforeUpdate_ReturnsFalse() { var account = new Account("test"); account.HasClaims.ShouldBeFalse(); } // 9. HasClaims is true after the first update. [Fact] public void HasClaims_AfterUpdate_ReturnsTrue() { var account = new Account("test"); var claims = new AccountClaimData { MaxConnections = 1 }; account.UpdateAccountClaims(claims); account.HasClaims.ShouldBeTrue(); account.CurrentClaims.ShouldNotBeNull(); account.CurrentClaims!.MaxConnections.ShouldBe(1); } // 10. ClaimUpdateCount increments only when claims actually change. [Fact] public void ClaimUpdateCount_IncrementsOnChange() { var account = new Account("test"); account.ClaimUpdateCount.ShouldBe(0); var claimsA = new AccountClaimData { MaxConnections = 5 }; account.UpdateAccountClaims(claimsA); account.ClaimUpdateCount.ShouldBe(1); // Reapplying same claims does NOT increment count. account.UpdateAccountClaims(claimsA); account.ClaimUpdateCount.ShouldBe(1); // Applying different claims does increment. var claimsB = new AccountClaimData { MaxConnections = 10 }; account.UpdateAccountClaims(claimsB); account.ClaimUpdateCount.ShouldBe(2); } }