public void TokensBecomeAvailableAtLimitPerSecondRate() { // arrange var clock = new FakeSystemClock(); var limiter = new Limiter(new Limit(10), 50, clock); // act var initiallyAllowed = limiter.AllowN(clock.UtcNow, 50); var thenNotAllowed1 = limiter.Allow(); clock.Advance(TimeSpan.FromMilliseconds(100)); var oneTokenAvailable = limiter.Allow(); var thenNotAllowed2 = limiter.Allow(); clock.Advance(TimeSpan.FromMilliseconds(200)); var twoTokensAvailable1 = limiter.Allow(); var twoTokensAvailable2 = limiter.Allow(); var thenNotAllowed3 = limiter.Allow(); // assert initiallyAllowed.ShouldBeTrue(); thenNotAllowed1.ShouldBeFalse(); oneTokenAvailable.ShouldBeTrue(); thenNotAllowed2.ShouldBeFalse(); twoTokensAvailable1.ShouldBeTrue(); twoTokensAvailable2.ShouldBeTrue(); thenNotAllowed3.ShouldBeFalse(); }
public async Task ManyWaitsStackUp() { await Policy .Handle <ShouldAssertException>() .RetryAsync(3) .ExecuteAsync(async() => { // arrange var limiter = new Limiter(new Limit(10), 5); using var cancellation = new CancellationTokenSource(TimeSpan.FromSeconds(5)); // act while (cancellation.IsCancellationRequested == false) { var task = limiter.WaitAsync(cancellation.Token); if (!task.IsCompleted) { await task.ConfigureAwait(false); break; } } var delayOne = new Stopwatch(); delayOne.Start(); var delayTwo = new Stopwatch(); delayTwo.Start(); var delayThree = new Stopwatch(); delayThree.Start(); var waits = new List <Task> { limiter.WaitAsync(cancellation.Token), limiter.WaitAsync(cancellation.Token), limiter.WaitAsync(cancellation.Token), }; var taskOne = await Task.WhenAny(waits.ToArray()).ConfigureAwait(false); await taskOne.ConfigureAwait(false); delayOne.Stop(); waits.Remove(taskOne); var taskTwo = await Task.WhenAny(waits.ToArray()).ConfigureAwait(false); await taskTwo.ConfigureAwait(false); delayTwo.Stop(); waits.Remove(taskTwo); var taskThree = await Task.WhenAny(waits.ToArray()).ConfigureAwait(false); await taskThree.ConfigureAwait(false); delayThree.Stop(); waits.Remove(taskThree); // assert delayOne.Elapsed.ShouldBe(TimeSpan.FromMilliseconds(100), tolerance: TimeSpan.FromMilliseconds(25)); delayTwo.Elapsed.ShouldBe(TimeSpan.FromMilliseconds(200), tolerance: TimeSpan.FromMilliseconds(25)); delayThree.Elapsed.ShouldBe(TimeSpan.FromMilliseconds(300), tolerance: TimeSpan.FromMilliseconds(25)); }).ConfigureAwait(false); }
public async Task WaitAsyncCausesPauseLikeReserve() { // arrange var limiter = new Limiter(new Limit(10), 5); using var cancellation = new CancellationTokenSource(TimeSpan.FromSeconds(5)); // act while (cancellation.IsCancellationRequested == false) { var task = limiter.WaitAsync(cancellation.Token); if (!task.IsCompleted) { await task.ConfigureAwait(false); break; } } var delayOne = new Stopwatch(); delayOne.Start(); await limiter.WaitAsync(cancellation.Token).ConfigureAwait(false); delayOne.Stop(); var delayTwoMore = new Stopwatch(); delayTwoMore.Start(); await limiter.WaitAsync(2, cancellation.Token).ConfigureAwait(false); delayTwoMore.Stop(); await Task.Delay(TimeSpan.FromMilliseconds(150)).ConfigureAwait(false); var delayAlreadyAvailable = new Stopwatch(); delayAlreadyAvailable.Start(); await limiter.WaitAsync(cancellation.Token).ConfigureAwait(false); delayAlreadyAvailable.Stop(); var delayHalfAvailable = new Stopwatch(); delayHalfAvailable.Start(); await limiter.WaitAsync(cancellation.Token).ConfigureAwait(false); delayHalfAvailable.Stop(); // assert delayOne.Elapsed.ShouldBe(TimeSpan.FromMilliseconds(100), tolerance: TimeSpan.FromMilliseconds(25)); delayTwoMore.Elapsed.ShouldBe(TimeSpan.FromMilliseconds(200), tolerance: TimeSpan.FromMilliseconds(25)); delayAlreadyAvailable.Elapsed.ShouldBe(TimeSpan.Zero, tolerance: TimeSpan.FromMilliseconds(5)); delayHalfAvailable.Elapsed.ShouldBe(TimeSpan.FromMilliseconds(50), tolerance: TimeSpan.FromMilliseconds(25)); }
public void FirstTokenIsAvailable() { // arrange var clock = new FakeSystemClock(); var limiter = new Limiter(new Limit(10), 1, clock); // act var allowed = limiter.Allow(); // assert allowed.ShouldBe(true); }
/// <summary> /// Initializes a new instance of the <see cref="Reservation"/> class. /// </summary> /// <param name="limiter">The limiter.</param> /// <param name="ok">if set to <c>true</c> [ok].</param> /// <param name="tokens">The tokens.</param> /// <param name="timeToAct">The time to act.</param> /// <param name="limit">The limit.</param> public Reservation( ISystemClock clock, Limiter limiter, bool ok, double tokens = default, DateTimeOffset timeToAct = default, Limit limit = default) { _clock = clock; _limiter = limiter; Ok = ok; _tokens = tokens; TimeToAct = timeToAct; _limit = limit; }
public void AsManyAsBurstTokensAreAvailableRightAway(int burst) { // arrange var clock = new FakeSystemClock(); var limiter = new Limiter(new Limit(10), burst, clock); // act var allowed = new List <bool>(); foreach (var index in Enumerable.Range(1, burst)) { allowed.Add(limiter.Allow()); } var notAllowed = limiter.Allow(); // assert allowed.ShouldAllBe(item => item == true); notAllowed.ShouldBeFalse(); }
public void ReserveTellsYouHowLongToWait() { // arrange var clock = new FakeSystemClock(); var limiter = new Limiter(new Limit(10), 50, clock); // act var initiallyAllowed = limiter.AllowN(clock.UtcNow, 50); var thenNotAllowed1 = limiter.Allow(); var reserveOne = limiter.Reserve(); var delayOne = reserveOne.Delay(); var reserveTwoMore = limiter.Reserve(clock.UtcNow, 2); var delayTwoMore = reserveTwoMore.Delay(); clock.Advance(TimeSpan.FromMilliseconds(450)); var reserveAlreadyAvailable = limiter.Reserve(); var delayAlreadyAvailable = reserveAlreadyAvailable.Delay(); var reserveHalfAvailable = limiter.Reserve(); var delayHalfAvailable = reserveHalfAvailable.Delay(); // assert initiallyAllowed.ShouldBeTrue(); thenNotAllowed1.ShouldBeFalse(); reserveOne.Ok.ShouldBeTrue(); delayOne.ShouldBe(TimeSpan.FromMilliseconds(100)); reserveTwoMore.Ok.ShouldBeTrue(); delayTwoMore.ShouldBe(TimeSpan.FromMilliseconds(300)); reserveAlreadyAvailable.Ok.ShouldBeTrue(); delayAlreadyAvailable.ShouldBe(TimeSpan.Zero); reserveHalfAvailable.Ok.ShouldBeTrue(); delayHalfAvailable.ShouldBe(TimeSpan.FromMilliseconds(50)); }