public async Task Run_Connects_After_Cooldown_If_Connection_Fails()
        {
            var timeout  = TimeSpan.FromSeconds(7);
            var grpcHost = await CreateGrpcServer();

            var grpcClient      = grpcHost.CreateFixedClient();
            var stopTokenSource = new CancellationTokenSource(timeout);
            var verifier        = new VerifiesOnSecondAttemptVerifier();

            var connectionWasEstablished = false;
            var eventBus = new EventBus();

            eventBus.Subscribe <EndpointConnectionEvents.Connected>(args =>
            {
                connectionWasEstablished = true;
                stopTokenSource.Cancel();
            });

            var endpointConnectionManager = new EndpointConnectionManager(
                eventBus, new DelegateClientFactory(endpoint => grpcClient),
                verifier, _loggerFactory.CreateLogger <EndpointConnectionManager>()
                );
            await endpointConnectionManager.Run(
                new[] { StaticApiServer.AnyOnUri("http://localhost/") },
                new[] { new DisconnectsImmediately() },
                stopTokenSource.Token
                );

            await grpcHost.StopAsync();

            Assert.IsTrue(connectionWasEstablished);
            //  built-in cooldown is 5 seconds, make the check a little fuzzy
            Assert.IsTrue(verifier.LastAttemptDelta.Value > TimeSpan.FromSeconds(4));
        }
        public async Task Run_Persists_Endpoint_Providers_Across_Failover()
        {
            var timeout  = TimeSpan.FromSeconds(2);
            var grpcHost = await CreateGrpcServer();

            var grpcClient      = grpcHost.CreateFixedClient();
            var stopTokenSource = new CancellationTokenSource(timeout);
            var verifier        = new VerifiesOnSecondAttemptVerifier();

            var connectionWasEstablished = false;
            var connectedEndpoint        = default(ServerEndpoint);
            var eventBus = new EventBus();

            eventBus.Subscribe <EndpointConnectionEvents.Connected>(args =>
            {
                connectedEndpoint        = args.ServerEndpoint;
                connectionWasEstablished = true;
                stopTokenSource.Cancel();
            });

            var countingEndpointProvider = new CountingProxyEndpointProvider(
                StaticApiServer.AnyOnUri("http://localhost/"));
            var endpointConnectionManager = new EndpointConnectionManager(
                eventBus, new DelegateClientFactory(endpoint => grpcClient),
                verifier, _loggerFactory.CreateLogger <EndpointConnectionManager>()
                );
            await endpointConnectionManager.Run(
                new IServerEndpointProvider[]
            {
                StaticApiServer.AnyOnUri("http://localhost/"),
                countingEndpointProvider
            },
                new[] { new DisconnectsImmediately() },
                stopTokenSource.Token
                );

            await grpcHost.StopAsync();

            Assert.IsTrue(connectionWasEstablished);
            Assert.AreEqual(1, countingEndpointProvider.CallCount);
        }
        public async Task Run_Uses_2nd_Endpoint_Immediately_When_1st_Throws_Exception()
        {
            var timeout  = TimeSpan.FromSeconds(2);
            var grpcHost = await CreateGrpcServer();

            var grpcClient      = grpcHost.CreateFixedClient();
            var stopTokenSource = new CancellationTokenSource(timeout);
            var verifier        = new VerifiesOnSecondAttemptVerifier();

            var connectionWasEstablished = false;
            var connectedEndpoint        = default(ServerEndpoint);
            var eventBus = new EventBus();

            eventBus.Subscribe <EndpointConnectionEvents.Connected>(args =>
            {
                connectedEndpoint        = args.ServerEndpoint;
                connectionWasEstablished = true;
                stopTokenSource.Cancel();
            });

            var endpointConnectionManager = new EndpointConnectionManager(
                eventBus, new DelegateClientFactory(endpoint => grpcClient),
                verifier, _loggerFactory.CreateLogger <EndpointConnectionManager>()
                );
            await endpointConnectionManager.Run(
                new IServerEndpointProvider[]
            {
                new ThrowsExceptionFirstEndpointProvider(StaticApiServer.AnyOnUri("http://localhost-first/")),
                StaticApiServer.AnyOnUri("http://localhost-second/")
            },
                new[] { new NeverDisconnects() },
                stopTokenSource.Token
                );

            await grpcHost.StopAsync();

            Assert.IsTrue(connectionWasEstablished);
            Assert.AreEqual("http://localhost-second/", connectedEndpoint.Uri.OriginalString);
        }