public void ItAllowsBurstOfEvents() { log.WriteLine("Starting test at " + DateTimeOffset.UtcNow.ToString("HH:mm:ss.fff")); // Arrange const int EVENTS = 40; const int MAX_SPEED = EVENTS / 2; var target = new PerSecondCounter(MAX_SPEED, "test", this.targetLogger); // Act var now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); for (var i = 0; i < EVENTS; i++) { target.IncreaseAsync(CancellationToken.None).Wait(Constants.TEST_TIMEOUT); } // Assert var timepassed = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() - now; double actualSpeed = (double)EVENTS * 1000 / timepassed; log.WriteLine("Time passed: {0} msecs", timepassed); log.WriteLine("Speed: {0} events/sec", actualSpeed); Assert.InRange(actualSpeed, EVENTS * 0.9, EVENTS); }
public void ItObtainsTheDesiredFrequency_OneEventPerSecond() { log.WriteLine("Starting test at " + DateTimeOffset.UtcNow.ToString("HH:mm:ss.fff")); // Arrange const int EVENTS = 10; const int MAX_SPEED = 1; // When calculating the speed achieved, exclude the events in the last second const int EVENTS_TO_IGNORE = 1; var target = new PerSecondCounter(MAX_SPEED, "test", this.targetLogger); // Act var now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); for (var i = 0; i < EVENTS; i++) { target.IncreaseAsync(CancellationToken.None).Wait(Constants.TEST_TIMEOUT); Thread.Sleep(100); } // Assert var timepassed = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() - now; double actualSpeed = (double)(EVENTS - EVENTS_TO_IGNORE) * 1000 / timepassed; log.WriteLine("Time passed: {0} msecs", timepassed); log.WriteLine("Speed: {0} events/sec", actualSpeed); Assert.InRange(actualSpeed, MAX_SPEED * 0.9, MAX_SPEED); }
public void ItObtainsTheDesiredFrequency_SeveralEventsPerSecond() { log.WriteLine("Starting test at " + DateTimeOffset.UtcNow.ToString("HH:mm:ss.fff")); // Arrange const int EVENTS = 41; const int MAX_SPEED = 20; // TODO: investigate why this is needed, is the rate limiting not working correctly? // https://github.com/Azure/device-simulation-dotnet/issues/127 const double PRECISION = 0.05; // empiric&acceptable value looking at CI builds // When calculating the speed achieved, exclude the events in the last second const int EVENTS_TO_IGNORE = 1; var target = new PerSecondCounter(MAX_SPEED, "test", this.targetLogger); // Act var now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); var last = now; for (var i = 0; i < EVENTS; i++) { target.IncreaseAsync(CancellationToken.None).Wait(Constants.TEST_TIMEOUT); last = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); } // Assert //long timepassed = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() - now; long timepassed = last - now; double actualSpeed = (double)(EVENTS - EVENTS_TO_IGNORE) * 1000 / timepassed; log.WriteLine("Time passed: {0} msecs", timepassed); log.WriteLine("Speed: {0} events/sec", actualSpeed); Assert.InRange(actualSpeed, MAX_SPEED - (1 + PRECISION), MAX_SPEED + PRECISION); }
public void Basic() { var tps = new PerSecondCounter(); while (DateTime.Now.Millisecond > 100) { Thread.Sleep(1); } // just wait to get more of a second tps.Increment(); tps.Increment(2); Assert.Equal(0, tps.Value); Assert.Equal(0.0, tps.ValuePerSecond); Thread.Sleep(1000); Assert.Equal(3, tps.Value); Assert.Equal(3.0, tps.ValuePerSecond); Thread.Sleep(1000); Assert.Equal(0, tps.Value); Assert.Equal(0.0, tps.ValuePerSecond); }
public void ItSupportLongPeriodsWithoutEvents() { log.WriteLine("Starting test at " + DateTimeOffset.UtcNow.ToString("HH:mm:ss.fff")); // Arrange const int MAX_SPEED = 10; const int EVENTS1 = 65; const int EVENTS2 = 35; var target = new PerSecondCounter(MAX_SPEED, "test", this.targetLogger); // Act - Run 2 separate burst, separate by a pause long enough // for the internal queue to be cleaned up. var t1 = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); for (var i = 0; i < EVENTS1; i++) { target.IncreaseAsync(CancellationToken.None).Wait(TEST_TIMEOUT); } var t2 = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); Thread.Sleep(5001); var t3 = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); for (var i = 0; i < EVENTS2; i++) { target.IncreaseAsync(CancellationToken.None).Wait(TEST_TIMEOUT); } var t4 = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); // Assert Assert.InRange(t2 - t1, 6000, 7000); Assert.InRange(t4 - t3, 3000, 4000); }
public void ThrowOnOutOfRange() { Assert.Throws <ArgumentOutOfRangeException>(() => { var _ = new PerSecondCounter(99); }); Assert.Throws <ArgumentOutOfRangeException>(() => { var _ = new PerSecondCounter(10001); }); }
public void ItWorksWhenNoThrottlingIsNeeded() { // Arrange var target = new PerSecondCounter(10, "test", this.targetLogger); // Act for (var i = 0; i < 10; i++) { // Assert - there was no pause Assert.False(target.IncreaseAsync(CancellationToken.None).Result); Task.Delay(250).Wait(); } }
public void ItPausesWhenNeeded() { log.WriteLine("Starting test at " + DateTimeOffset.UtcNow.ToString("HH:mm:ss.fff")); // Arrange const int MAX_SPEED = 60; const int EVENTS = MAX_SPEED + 1; var target = new PerSecondCounter(MAX_SPEED, "test", this.targetLogger); // Act var paused = false; for (var i = 0; i < EVENTS; i++) { paused = target.IncreaseAsync(CancellationToken.None).Result; } // Assert Assert.True(paused); }
public static void Run() { Terminal.Clear(); Terminal.WriteLine(" Terminal ", ConsoleColor.Yellow, ConsoleColor.DarkGray); Terminal.WriteLine(); using var counter = new PerSecondCounter(); counter.Tick = delegate { Console.WriteLine($"TPS: {counter.ValuePerSecond} /s"); }; var limiter = new PerSecondLimiter(13); while (true) { foreach (var key in Terminal.ReadAvailableKeys()) { switch (key) { case ConsoleKey.OemPlus: limiter.PerSecondRate += 1; break; case ConsoleKey.OemMinus: if (limiter.PerSecondRate > 1) { limiter.PerSecondRate -= 1; } break; case ConsoleKey.Escape: return; } } limiter.Wait(); counter.Increment(); } }
public void FourThreadsTwentyPerSecondAreThrottledTogether() { // Arrange var events = new ConcurrentBag <DateTimeOffset>(); var target = new PerSecondCounter(20, "test", this.targetLogger); var thread1 = new Thread(() => { for (int i = 0; i < 10; i++) { target.IncreaseAsync(CancellationToken.None).Wait(); events.Add(DateTimeOffset.UtcNow); } }); var thread2 = new Thread(() => { for (int i = 0; i < 10; i++) { target.IncreaseAsync(CancellationToken.None).Wait(); events.Add(DateTimeOffset.UtcNow); } }); var thread3 = new Thread(() => { for (int i = 0; i < 10; i++) { target.IncreaseAsync(CancellationToken.None).Wait(); events.Add(DateTimeOffset.UtcNow); } }); var thread4 = new Thread(() => { for (int i = 0; i < 10; i++) { target.IncreaseAsync(CancellationToken.None).Wait(); events.Add(DateTimeOffset.UtcNow); } }); // Act while (DateTimeOffset.UtcNow.Millisecond > 200) { // wait until the next second } var now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); thread1.Start(); thread2.Start(); thread3.Start(); thread4.Start(); thread1.Join(); thread2.Join(); thread3.Join(); thread4.Join(); // Assert var passed = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() - now; var j = 0; foreach (var e in events.ToImmutableSortedSet()) { j++; log.WriteLine(j + ": " + e.ToString("hh:mm:ss.fff")); } log.WriteLine("time: " + passed); Assert.InRange(passed, 1000, 1500); }