Files
natsdotnet/tests/NATS.Server.Auth.Tests/Auth/AccountLimitsTests.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

170 lines
5.0 KiB
C#

// Tests for per-account JetStream resource limits.
// Go reference: accounts_test.go TestAccountLimits, TestJetStreamLimits.
using NATS.Server.Auth;
namespace NATS.Server.Auth.Tests.Auth;
public class AccountLimitsTests
{
[Fact]
public void TryReserveConsumer_UnderLimit_ReturnsTrue()
{
var account = new Account("test")
{
JetStreamLimits = new AccountLimits { MaxConsumers = 3 },
};
account.TryReserveConsumer().ShouldBeTrue();
account.TryReserveConsumer().ShouldBeTrue();
account.TryReserveConsumer().ShouldBeTrue();
account.ConsumerCount.ShouldBe(3);
}
[Fact]
public void TryReserveConsumer_AtLimit_ReturnsFalse()
{
var account = new Account("test")
{
JetStreamLimits = new AccountLimits { MaxConsumers = 2 },
};
account.TryReserveConsumer().ShouldBeTrue();
account.TryReserveConsumer().ShouldBeTrue();
account.TryReserveConsumer().ShouldBeFalse();
account.ConsumerCount.ShouldBe(2);
}
[Fact]
public void ReleaseConsumer_DecrementsCount()
{
var account = new Account("test")
{
JetStreamLimits = new AccountLimits { MaxConsumers = 2 },
};
account.TryReserveConsumer().ShouldBeTrue();
account.TryReserveConsumer().ShouldBeTrue();
account.ConsumerCount.ShouldBe(2);
account.ReleaseConsumer();
account.ConsumerCount.ShouldBe(1);
// Now we can reserve again
account.TryReserveConsumer().ShouldBeTrue();
account.ConsumerCount.ShouldBe(2);
}
[Fact]
public void TrackStorageDelta_UnderLimit_ReturnsTrue()
{
var account = new Account("test")
{
JetStreamLimits = new AccountLimits { MaxStorage = 1000 },
};
account.TrackStorageDelta(500).ShouldBeTrue();
account.StorageUsed.ShouldBe(500);
account.TrackStorageDelta(400).ShouldBeTrue();
account.StorageUsed.ShouldBe(900);
}
[Fact]
public void TrackStorageDelta_ExceedsLimit_ReturnsFalse()
{
var account = new Account("test")
{
JetStreamLimits = new AccountLimits { MaxStorage = 1000 },
};
account.TrackStorageDelta(800).ShouldBeTrue();
account.TrackStorageDelta(300).ShouldBeFalse(); // 800 + 300 = 1100 > 1000
account.StorageUsed.ShouldBe(800); // unchanged
}
[Fact]
public void TrackStorageDelta_NegativeDelta_ReducesUsage()
{
var account = new Account("test")
{
JetStreamLimits = new AccountLimits { MaxStorage = 1000 },
};
account.TrackStorageDelta(800).ShouldBeTrue();
account.TrackStorageDelta(-300).ShouldBeTrue(); // negative always succeeds
account.StorageUsed.ShouldBe(500);
// Now we have room again
account.TrackStorageDelta(400).ShouldBeTrue();
account.StorageUsed.ShouldBe(900);
}
[Fact]
public void MaxStorage_Zero_Unlimited()
{
var account = new Account("test")
{
JetStreamLimits = new AccountLimits { MaxStorage = 0 }, // unlimited
};
// Should accept any amount
account.TrackStorageDelta(long.MaxValue / 2).ShouldBeTrue();
account.StorageUsed.ShouldBe(long.MaxValue / 2);
}
[Fact]
public void Limits_DefaultValues_AllUnlimited()
{
var limits = AccountLimits.Unlimited;
limits.MaxStorage.ShouldBe(0);
limits.MaxStreams.ShouldBe(0);
limits.MaxConsumers.ShouldBe(0);
limits.MaxAckPending.ShouldBe(0);
limits.MaxMemoryStorage.ShouldBe(0);
limits.MaxDiskStorage.ShouldBe(0);
// Account defaults to unlimited
var account = new Account("test");
account.JetStreamLimits.ShouldBe(AccountLimits.Unlimited);
}
[Fact]
public void TryReserveStream_WithLimits_RespectsNewLimits()
{
// JetStreamLimits.MaxStreams should take precedence over MaxJetStreamStreams
var account = new Account("test")
{
MaxJetStreamStreams = 10, // legacy field
JetStreamLimits = new AccountLimits { MaxStreams = 2 }, // new limit overrides
};
account.TryReserveStream().ShouldBeTrue();
account.TryReserveStream().ShouldBeTrue();
account.TryReserveStream().ShouldBeFalse(); // limited to 2 by JetStreamLimits
account.JetStreamStreamCount.ShouldBe(2);
}
[Fact]
public void EvictOldestClient_WhenMaxConnectionsExceeded()
{
var account = new Account("test")
{
MaxConnections = 2,
};
account.AddClient(1).ShouldBeTrue();
account.AddClient(2).ShouldBeTrue();
account.AddClient(3).ShouldBeFalse(); // at limit
account.ClientCount.ShouldBe(2);
// Remove oldest, then new one can connect
account.RemoveClient(1);
account.ClientCount.ShouldBe(1);
account.AddClient(3).ShouldBeTrue();
account.ClientCount.ShouldBe(2);
}
}