Files
natsdotnet/tests/NATS.Server.Auth.Tests/Auth/AccountClaimReloadTests.cs
Joseph Doherty 36b9dfa654 refactor: extract NATS.Server.Auth.Tests project
Move 50 auth/accounts/permissions/JWT/NKey test files from
NATS.Server.Tests into a dedicated NATS.Server.Auth.Tests project.
Update namespaces, replace private GetFreePort/ReadUntilAsync helpers
with TestUtilities calls, replace Task.Delay with TaskCompletionSource
in test doubles, and add InternalsVisibleTo.

690 tests pass.
2026-03-12 15:54:07 -04:00

174 lines
5.9 KiB
C#

// 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);
}
}