public async Task Executor_should_execute_tasks_until_disposal()
        {
            var task1Name  = "task1";
            var task2Name  = "task2";
            var countdown1 = new AsyncCountdown(task1Name, 10);
            var counter1   = new AsyncCounter();
            var countdown2 = new AsyncCountdown(task2Name, 10);
            var counter2   = new AsyncCounter();

            using (var executor = ContinuousTaskExecutor <string> .StartExecutor(Mock.Of <ITimeCoordinator>()))
            {
                Assert.True(executor.TryRegisterTaskFor(task1Name, (item, token) => StartTaskAsync(countdown1, counter1, token)));
                await countdown1.WaitAsync(_testTimeout);

                Assert.True(executor.TryRegisterTaskFor(task2Name, (item, token) => StartTaskAsync(countdown2, counter2, token)));
                await countdown2.WaitAsync(_testTimeout);

                // check that task 1 still works
                await countdown1.ResetTo(10).WaitAsync(_testTimeout);
            }

            var expected1 = counter1.Value;
            var expected2 = counter2.Value;
            await Task.Delay(200);

            Assert.Equal(expected1, counter1.Value);
            Assert.Equal(expected2, counter2.Value);
        }
        public async Task Executor_should_continue_processing_other_tasks_when_one_finish()
        {
            var task1Name     = "task1";
            var task2Name     = "task2";
            var countdown1    = new AsyncCountdown(task1Name, 10);
            var task2Finished = new SemaphoreSlim(0);

            using (var executor = ContinuousTaskExecutor <string> .StartExecutor(Mock.Of <ITimeCoordinator>()))
            {
                executor.FinishedTaskFor += item =>
                {
                    if (item == task2Name)
                    {
                        task2Finished.Release();
                    }
                };

                Assert.True(executor.TryRegisterTaskFor(task1Name, (item, token) => StartTaskAsync(token, b => b.WithCountdown(countdown1))));
                await countdown1.WaitAsync(_testTimeout);

                Assert.True(executor.TryRegisterTaskFor(task2Name, (item, token) => Task.Delay(25, token)));

                await task2Finished.WaitAsync(_testTimeout);

                // check that task 1 still works
                await countdown1.ResetTo(10).WaitAsync(_testTimeout);
            }
        }
        public async Task Monitor_should_start_checking_the_health_of_endpoints_until_disposed()
        {
            var endpoint1Countdown = new AsyncCountdown("endpoint1", 2);
            var endpoint2Countdown = new AsyncCountdown("endpoint2", 1);
            var endpoint3Countdown = new AsyncCountdown("endpoint3", 2);

            var counters     = new[] { new AsyncCounter(), new AsyncCounter(), new AsyncCounter() };
            var healthCheck1 = _awaitableFactory.Return(new HealthInfo(HealthStatus.Healthy)).WithCountdown(endpoint1Countdown).WithCounter(counters[0]);
            var healthCheck2 = _awaitableFactory.Return(new HealthInfo(HealthStatus.Healthy)).WithCountdown(endpoint2Countdown).WithCounter(counters[1]);
            var healthCheck3 = _awaitableFactory.Return(new HealthInfo(HealthStatus.Healthy)).WithCountdown(endpoint3Countdown).WithCounter(counters[2]);

            _mockHealthMonitor.Setup(cfg => cfg.CheckHealthAsync("address1", It.IsAny <CancellationToken>())).Returns(healthCheck1.RunAsync);
            _mockHealthMonitor.Setup(cfg => cfg.CheckHealthAsync("address2", It.IsAny <CancellationToken>())).Returns(healthCheck2.RunAsync);
            _mockHealthMonitor.Setup(cfg => cfg.CheckHealthAsync("address3", It.IsAny <CancellationToken>())).Returns(healthCheck3.RunAsync);

            var endpoint1 = _endpointRegistry.TryRegister(CreateEndpointIdentity("address1"));

            _endpointRegistry.TryRegister(CreateEndpointIdentity("address2"));

            using (CreateEndpointMonitor(TimeSpan.FromMilliseconds(50)))
            {
                await endpoint1Countdown.WaitAsync(TestMaxWaitTime);

                await endpoint2Countdown.WaitAsync(TestMaxWaitTime);

                _endpointRegistry.TryRegister(CreateEndpointIdentity("address3"));
                await endpoint3Countdown.WaitAsync(TestMaxWaitTime);

                _endpointRegistry.TryUnregister(endpoint1.Identity);
                // ensure that endpoint 2 still is running, and give time for endpoint 1 to shutdown
                await endpoint2Countdown.ResetTo(10).WaitAsync(TestMaxWaitTime);

                // ensure that endpoint 1 calls does not change, while endpoint 2 still runs
                await AssertValueDidNotChangedAfterOperationAsync(
                    () => counters[0].Value,
                    () => endpoint2Countdown.ResetTo(10).WaitAsync(TestMaxWaitTime));
            }

            await AssertValueDidNotChangedAfterOperationAsync(() => counters.Sum(c => c.Value), () => Task.Delay(200));
        }