private async Task SimulateRequestsAsync(CustomerThrottle ctRate,
                                                 ThrottledFunctionExecutor <TestRequest, TestResponse> tfe, TestCounter counter, CancellationToken cancellationToken)
        {
            try
            {
                while (true)
                {
                    var response = await tfe.ExecuteThrottledAsync(ctRate, new TestRequest()).ConfigureAwait(false);

                    counter.Add();

                    cancellationToken.ThrowIfCancellationRequested();
                }
            }
            catch (OperationCanceledException)
            {
            }
            catch (Exception)
            {
                throw;
            }
        }
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
        public async Task ChangingRateTest1()
#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously
        {
            Func <TestRequest, CancellationToken, Task <TestResponse> > testDelegateFunction = async(req, token) =>
            {
                return(await Task.Run(() => { return new TestResponse(); }).ConfigureAwait(false));
            };

            // customer 1: Initially 1 request per second
            CustomerThrottle customerThrottle1rate1 = CustomerThrottle.Create("1", 1);
            //  ... then 60 request per second
            CustomerThrottle customerThrottle1rate2 = CustomerThrottle.Create("1", 60);

            TestCounter testCounter1 = new TestCounter();

            CancellationTokenSource tfeTokenSource = new CancellationTokenSource();

            using (ThrottledFunctionExecutor <TestRequest, TestResponse> tfe = new ThrottledFunctionExecutor <TestRequest, TestResponse>
                                                                                   (testDelegateFunction, tfeTokenSource.Token))
            {
                CancellationTokenSource cts1 = new CancellationTokenSource();
                CancellationTokenSource cts2 = new CancellationTokenSource();

                var t1 = new Task(async() =>
                {
                    await SimulateRequestsAsync(customerThrottle1rate1, tfe, testCounter1, cts1.Token).ConfigureAwait(false);
                });

                var t2 = new Task(async() =>
                {
                    await SimulateRequestsAsync(customerThrottle1rate2, tfe, testCounter1, cts2.Token).ConfigureAwait(false);
                    return;
                });


                Stopwatch sw1 = new Stopwatch();
                Stopwatch sw2 = new Stopwatch();

                t1.Start();

                sw1.Start();

                while (true)
                {
                    Thread.Sleep(1);
                    if (sw1.Elapsed.TotalMilliseconds >= 59750)
                    {
                        break;
                    }
                }

                testCounter1.stopCount = true;
                sw1.Stop();

                cts1.Cancel();

                Task.WaitAll(t1);

                t2.Start();

                sw2.Start();
                testCounter1.stopCount = false;

                while (true)
                {
                    Thread.Sleep(1);
                    if (sw2.Elapsed.TotalMilliseconds >= 59750)
                    {
                        break;
                    }
                }

                testCounter1.stopCount = true;
                sw2.Stop();

                cts2.Cancel();

                Task.WaitAll(t2);

                // Total requests = 60 + 3600 = 3660
                // Total seconds = ~119.5
                // r/s = 30.63

                TimeSpan totalElapsed = sw1.Elapsed + sw2.Elapsed;

                Assert.AreEqual(30.63, testCounter1.count / totalElapsed.TotalSeconds, 0.75);
            }
        }
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
        public async Task ThrottlingRateOver2MinutesTest1()
#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously
        {
            Func <TestRequest, CancellationToken, Task <TestResponse> > testDelegateFunction = async(req, token) =>
            {
                return(await Task.Run(() => { return new TestResponse(); }).ConfigureAwait(false));
            };

            // customer 1: 1 request per second
            CustomerThrottle customerThrottle1 = CustomerThrottle.Create("1", 1);
            // customer 2: 2 requests per second
            CustomerThrottle customerThrottle2 = CustomerThrottle.Create("2", 2);
            // customer 3: 4 requests per second
            CustomerThrottle customerThrottle3 = CustomerThrottle.Create("3", 4);
            // customer 4: 120 requests per second
            CustomerThrottle customerThrottle4 = CustomerThrottle.Create("4", 120);

            TestCounter testCounter1 = new TestCounter();
            TestCounter testCounter2 = new TestCounter();
            TestCounter testCounter3 = new TestCounter();
            TestCounter testCounter4 = new TestCounter();

            CancellationTokenSource tokenSource = new CancellationTokenSource();

            using (ThrottledFunctionExecutor <TestRequest, TestResponse> tfe = new ThrottledFunctionExecutor <TestRequest, TestResponse>
                                                                                   (testDelegateFunction, tokenSource.Token))
            {
                var t1 = new Task(async() =>
                {
                    await SimulateRequestsAsync(customerThrottle1, tfe, testCounter1).ConfigureAwait(false);
                });

                var t2 = new Task(async() =>
                {
                    await SimulateRequestsAsync(customerThrottle2, tfe, testCounter2).ConfigureAwait(false);
                    return;
                });

                var t3 = new Task(async() =>
                {
                    await SimulateRequestsAsync(customerThrottle3, tfe, testCounter3).ConfigureAwait(false);
                    return;
                });

                var t4 = new Task(async() =>
                {
                    await SimulateRequestsAsync(customerThrottle4, tfe, testCounter4).ConfigureAwait(false);
                    return;
                });

                Stopwatch sw = new Stopwatch();
                sw.Start();

                t1.Start();
                t2.Start();
                t3.Start();
                t4.Start();

                while (true)
                {
                    Thread.Sleep(1);
                    if (sw.Elapsed.TotalMilliseconds >= 59950)
                    {
                        break;
                    }
                }

                testCounter1.stopCount = true;
                testCounter2.stopCount = true;
                testCounter3.stopCount = true;
                testCounter4.stopCount = true;

                sw.Stop();

                tokenSource.Cancel();

                Task.WaitAll(t1, t2, t3, t4);

                // customer 1: 1 request per second
                Assert.AreEqual(1, testCounter1.count / sw.Elapsed.TotalSeconds, 0.05);

                // customer 2: 2 requests per second
                Assert.AreEqual(2, testCounter2.count / sw.Elapsed.TotalSeconds, 0.10);

                // customer 3: 4 requests per second
                Assert.AreEqual(4, testCounter3.count / sw.Elapsed.TotalSeconds, 0.4);

                // customer 4: 120 requests per second
                Assert.AreEqual(120, testCounter4.count / sw.Elapsed.TotalSeconds, 12);
            }
        }