Files
natsdotnet/tests/NATS.Server.Tests/Auth/AccountExpirationTests.cs
Joseph Doherty e2bfca48e4 feat: add account expiration with TTL-based cleanup (Gap 9.5)
Add ExpiresAt, IsExpired, TimeToExpiry, SetExpiration, ClearExpiration,
SetExpirationFromTtl, and GetExpirationInfo to Account. Expiry is stored
as UTC ticks in a long field (long.MinValue sentinel) for lock-free reads
via Interlocked. Add AccountExpirationInfo record. 10 new tests cover all
behaviours.
2026-02-25 12:56:48 -05:00

136 lines
4.3 KiB
C#

using NATS.Server.Auth;
using Shouldly;
namespace NATS.Server.Tests.Auth;
// Go reference: server/accounts.go — account expiry / SetExpirationTimer
public sealed class AccountExpirationTests
{
// 1. ExpiresAt_Default_IsNull
// Go reference: accounts.go — account.expiry zero-value
[Fact]
public void ExpiresAt_Default_IsNull()
{
var account = new Account("test-account");
account.ExpiresAt.ShouldBeNull();
}
// 2. SetExpiration_SetsExpiresAt
// Go reference: accounts.go — SetExpirationTimer stores expiry value
[Fact]
public void SetExpiration_SetsExpiresAt()
{
var account = new Account("test-account");
var expiresAt = new DateTime(2030, 6, 15, 12, 0, 0, DateTimeKind.Utc);
account.SetExpiration(expiresAt);
account.ExpiresAt.ShouldBe(expiresAt);
}
// 3. IsExpired_FutureDate_ReturnsFalse
// Go reference: accounts.go — isExpired() returns false when expiry is in future
[Fact]
public void IsExpired_FutureDate_ReturnsFalse()
{
var account = new Account("test-account");
account.SetExpiration(DateTime.UtcNow.AddHours(1));
account.IsExpired.ShouldBeFalse();
}
// 4. IsExpired_PastDate_ReturnsTrue
// Go reference: accounts.go — isExpired() returns true when past expiry
[Fact]
public void IsExpired_PastDate_ReturnsTrue()
{
var account = new Account("test-account");
account.SetExpiration(DateTime.UtcNow.AddHours(-1));
account.IsExpired.ShouldBeTrue();
}
// 5. ClearExpiration_RemovesExpiry
// Go reference: accounts.go — clearing expiry resets the field to zero
[Fact]
public void ClearExpiration_RemovesExpiry()
{
var account = new Account("test-account");
account.SetExpiration(DateTime.UtcNow.AddHours(1));
account.ExpiresAt.ShouldNotBeNull();
account.ClearExpiration();
account.ExpiresAt.ShouldBeNull();
}
// 6. SetExpirationFromTtl_CalculatesCorrectly
// Go reference: accounts.go — SetExpirationTimer(ttl) sets expiry = now + ttl
[Fact]
public void SetExpirationFromTtl_CalculatesCorrectly()
{
var account = new Account("test-account");
var before = DateTime.UtcNow;
account.SetExpirationFromTtl(TimeSpan.FromHours(1));
var after = DateTime.UtcNow;
account.ExpiresAt.ShouldNotBeNull();
account.ExpiresAt!.Value.ShouldBeGreaterThanOrEqualTo(before.AddHours(1));
account.ExpiresAt.Value.ShouldBeLessThanOrEqualTo(after.AddHours(1));
}
// 7. TimeToExpiry_NoExpiry_ReturnsNull
// Go reference: accounts.go — no expiry set returns nil duration
[Fact]
public void TimeToExpiry_NoExpiry_ReturnsNull()
{
var account = new Account("test-account");
account.TimeToExpiry.ShouldBeNull();
}
// 8. TimeToExpiry_Expired_ReturnsZero
// Go reference: accounts.go — already-expired account has zero remaining time
[Fact]
public void TimeToExpiry_Expired_ReturnsZero()
{
var account = new Account("test-account");
account.SetExpiration(DateTime.UtcNow.AddHours(-1));
account.TimeToExpiry.ShouldBe(TimeSpan.Zero);
}
// 9. TimeToExpiry_Future_ReturnsPositive
// Go reference: accounts.go — unexpired account returns positive remaining duration
[Fact]
public void TimeToExpiry_Future_ReturnsPositive()
{
var account = new Account("test-account");
account.SetExpiration(DateTime.UtcNow.AddHours(1));
var tte = account.TimeToExpiry;
tte.ShouldNotBeNull();
tte!.Value.ShouldBeGreaterThan(TimeSpan.Zero);
}
// 10. GetExpirationInfo_ReturnsCompleteInfo
// Go reference: accounts.go — expiry fields exposed for monitoring / JWT renewal
[Fact]
public void GetExpirationInfo_ReturnsCompleteInfo()
{
var account = new Account("info-account");
var expiresAt = DateTime.UtcNow.AddHours(2);
account.SetExpiration(expiresAt);
var info = account.GetExpirationInfo();
info.AccountName.ShouldBe("info-account");
info.HasExpiration.ShouldBeTrue();
info.ExpiresAt.ShouldBe(expiresAt);
info.IsExpired.ShouldBeFalse();
info.TimeToExpiry.ShouldNotBeNull();
info.TimeToExpiry!.Value.ShouldBeGreaterThan(TimeSpan.Zero);
}
}