// Copyright 2021-2025 The NATS Authors // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. using Shouldly; using ZB.MOM.NatsNet.Server.Internal; namespace ZB.MOM.NatsNet.Server.Tests.Internal; /// /// Tests for . /// Mirrors server/rate_counter_test.go: TestRateCounter (ID 2720). /// public sealed class RateCounterTests { [Fact] public void NewRateCounter_ShouldCreateWithDefaultInterval() { var counter = RateCounter.NewRateCounter(2); counter.Interval.ShouldBe(TimeSpan.FromSeconds(1)); counter.Allow().ShouldBeTrue(); counter.Allow().ShouldBeTrue(); counter.Allow().ShouldBeFalse(); } [Fact] public async Task RateCounter_ShouldAllowUpToLimitThenBlockAndReset() { // Mirror: TestRateCounter var counter = new RateCounter(10) { Interval = TimeSpan.FromMilliseconds(100) }; // First 10 calls should be allowed (counts 0–9 < limit 10). for (var i = 0; i < 10; i++) counter.Allow().ShouldBeTrue($"should allow on iteration {i}"); // Next 5 should be blocked. for (var i = 0; i < 5; i++) counter.Allow().ShouldBeFalse($"should not allow on iteration {i}"); // countBlocked returns and resets the blocked count. counter.CountBlocked().ShouldBe(5UL); counter.CountBlocked().ShouldBe(0UL); // After the window expires, should allow again. await Task.Delay(150); counter.Allow().ShouldBeTrue("should allow after window expired"); } }