Class to store all the Keep Alive properties
        public void ConnectionTimeoutTest()
        {
            // Arrange
            var connection = new Mock<Client.IConnection>();
            var transport = new Mock<IClientTransport>();

            transport.Setup(m => m.SupportsKeepAlive).Returns(true);

            // Setting the values such that a timeout happens almost instantly
            var keepAliveData = new KeepAliveData(
                timeoutWarning: TimeSpan.FromSeconds(10),
                timeout: TimeSpan.FromSeconds(1),
                checkInterval: TimeSpan.FromSeconds(2)
            );

            using (var monitor = new HeartbeatMonitor(connection.Object, new object(), keepAliveData.CheckInterval))
            {
                connection.Setup(m => m.LastMessageAt).Returns(DateTime.UtcNow);
                connection.Setup(m => m.KeepAliveData).Returns(keepAliveData);
                connection.Setup(m => m.State).Returns(ConnectionState.Connected);
                connection.Setup(m => m.Transport).Returns(transport.Object);

                monitor.Start();

                // Act - Setting timespan to be greater then timeout
                monitor.Beat(TimeSpan.FromSeconds(5));

                // Assert
                Assert.True(monitor.TimedOut);
                Assert.False(monitor.HasBeenWarned);
                transport.Verify(m => m.LostConnection(connection.Object), Times.Once());
            }
        }
示例#2
0
        public void TimeoutWarningTest()
        {
            // Arrange
            var connection = new Mock<Client.IConnection>();
            var monitor = new HeartbeatMonitor(connection.Object, new object());

            // Setting the values such that a warning is thrown almost instantly and a timeout doesn't occur
            var keepAliveData = new KeepAliveData(
                lastKeepAlive: DateTime.UtcNow,
                timeoutWarning: TimeSpan.FromSeconds(1),
                timeout: TimeSpan.FromSeconds(20),
                checkInterval: TimeSpan.FromSeconds(2)
            );

            connection.Setup(m => m.KeepAliveData).Returns(keepAliveData);
            connection.Setup(m => m.State).Returns(ConnectionState.Connected);

            // Act - Setting timespan to be greater than timeout warining but less than timeout
            monitor.Beat(TimeSpan.FromSeconds(5));

            // Assert
            Assert.True(monitor.HasBeenWarned);
            Assert.False(monitor.TimedOut);
            connection.Verify(m => m.OnConnectionSlow(), Times.Once());
        }
示例#3
0
        private Task Negotiate(IClientTransport transport)
        {
            return(transport.Negotiate(this)
                   .Then(negotiationResponse =>
            {
                VerifyProtocolVersion(negotiationResponse.ProtocolVersion);

                ConnectionId = negotiationResponse.ConnectionId;
                ConnectionToken = negotiationResponse.ConnectionToken;
                _disconnectTimeout = TimeSpan.FromSeconds(negotiationResponse.DisconnectTimeout);

                // If we have a keep alive
                if (negotiationResponse.KeepAliveTimeout != null)
                {
                    _keepAliveData = new KeepAliveData(TimeSpan.FromSeconds(negotiationResponse.KeepAliveTimeout.Value));
                }

                var data = OnSending();
                return StartTransport(data);
            })
                   .ContinueWithNotComplete(() => Disconnect()));
        }
示例#4
0
        private Task Negotiate(IClientTransport transport)
        {
            _connectionData = OnSending();

            return(transport.Negotiate(this, _connectionData)
                   .Then(negotiationResponse =>
            {
                VerifyProtocolVersion(negotiationResponse.ProtocolVersion);

                ConnectionId = negotiationResponse.ConnectionId;
                ConnectionToken = negotiationResponse.ConnectionToken;
                _disconnectTimeout = TimeSpan.FromSeconds(negotiationResponse.DisconnectTimeout);
                _totalTransportConnectTimeout = TransportConnectTimeout + TimeSpan.FromSeconds(negotiationResponse.TransportConnectTimeout);

                // Default the beat interval to be 5 seconds in case keep alive is disabled.
                var beatInterval = TimeSpan.FromSeconds(5);

                // If we have a keep alive
                if (negotiationResponse.KeepAliveTimeout != null)
                {
                    _keepAliveData = new KeepAliveData(TimeSpan.FromSeconds(negotiationResponse.KeepAliveTimeout.Value));
                    _reconnectWindow = _disconnectTimeout + _keepAliveData.Timeout;

                    beatInterval = _keepAliveData.CheckInterval;
                }
                else
                {
                    _reconnectWindow = _disconnectTimeout;
                }

                _monitor = new HeartbeatMonitor(this, _stateLock, beatInterval);

                return StartTransport();
            })
                   .ContinueWithNotComplete(() => Disconnect()));
        }
        private Task Negotiate(IClientTransport transport)
        {
            _connectionData = OnSending();

            return transport.Negotiate(this, _connectionData)
                            .Then(negotiationResponse =>
                            {
                                VerifyProtocolVersion(negotiationResponse.ProtocolVersion);

                                ConnectionId = negotiationResponse.ConnectionId;
                                ConnectionToken = negotiationResponse.ConnectionToken;
                                _disconnectTimeout = TimeSpan.FromSeconds(negotiationResponse.DisconnectTimeout);
                                TransportConnectTimeout = TransportConnectTimeout + TimeSpan.FromSeconds(negotiationResponse.TransportConnectTimeout);

                                // If we have a keep alive
                                if (negotiationResponse.KeepAliveTimeout != null)
                                {
                                    _keepAliveData = new KeepAliveData(TimeSpan.FromSeconds(negotiationResponse.KeepAliveTimeout.Value));
                                }

                                return StartTransport();
                            })
                            .ContinueWithNotComplete(() => Disconnect());
        }
示例#6
0
        private Task Negotiate(IClientTransport transport)
        {
            _connectionData = OnSending();

            return transport.Negotiate(this, _connectionData)
                            .Then(negotiationResponse =>
                            {
                                VerifyProtocolVersion(negotiationResponse.ProtocolVersion);

                                ConnectionId = negotiationResponse.ConnectionId;
                                ConnectionToken = negotiationResponse.ConnectionToken;
                                _disconnectTimeout = TimeSpan.FromSeconds(negotiationResponse.DisconnectTimeout);
                                _totalTransportConnectTimeout = TransportConnectTimeout + TimeSpan.FromSeconds(negotiationResponse.TransportConnectTimeout);

                                // Default the beat interval to be 5 seconds in case keep alive is disabled.
                                var beatInterval = TimeSpan.FromSeconds(5);

                                // If we have a keep alive
                                if (negotiationResponse.KeepAliveTimeout != null)
                                {
                                    _keepAliveData = new KeepAliveData(TimeSpan.FromSeconds(negotiationResponse.KeepAliveTimeout.Value));
                                    _reconnectWindow = _disconnectTimeout + _keepAliveData.Timeout;

                                    beatInterval = _keepAliveData.CheckInterval;
                                }
                                else
                                {
                                    _reconnectWindow = _disconnectTimeout;
                                }

                                _monitor = new HeartbeatMonitor(this, _stateLock, beatInterval);

                                return StartTransport();
                            })
                            .ContinueWithNotComplete(() => Disconnect());
        }
示例#7
0
        private Task Negotiate(IClientTransport transport)
        {
            // Captured and used by StartNegotiation to track attempts
            var negotiationAttempts = 0;

            Task CompleteNegotiation(NegotiationResponse negotiationResponse)
            {
                ConnectionId                  = negotiationResponse.ConnectionId;
                ConnectionToken               = negotiationResponse.ConnectionToken;
                _disconnectTimeout            = TimeSpan.FromSeconds(negotiationResponse.DisconnectTimeout);
                _totalTransportConnectTimeout = TransportConnectTimeout + TimeSpan.FromSeconds(negotiationResponse.TransportConnectTimeout);

                // Default the beat interval to be 5 seconds in case keep alive is disabled.
                var beatInterval = TimeSpan.FromSeconds(5);

                // If we have a keep alive
                if (negotiationResponse.KeepAliveTimeout != null)
                {
                    _keepAliveData   = new KeepAliveData(TimeSpan.FromSeconds(negotiationResponse.KeepAliveTimeout.Value));
                    _reconnectWindow = _disconnectTimeout + _keepAliveData.Timeout;

                    beatInterval = _keepAliveData.CheckInterval;
                }
                else
                {
                    _reconnectWindow = _disconnectTimeout;
                }

                Monitor = new HeartbeatMonitor(this, _stateLock, beatInterval);

                return(StartTransport());
            }

            Task StartNegotiation()
            {
                return(transport.Negotiate(this, _connectionData)
                       .Then(negotiationResponse =>
                {
                    VerifyProtocolVersion(negotiationResponse.ProtocolVersion);

                    if (negotiationResponse.ProtocolVersion.Equals("2.0"))
                    {
                        if (!string.IsNullOrEmpty(negotiationResponse.Error))
                        {
                            throw new StartException(string.Format(Resources.Error_ErrorFromServer, negotiationResponse.Error));
                        }
                        if (!string.IsNullOrEmpty(negotiationResponse.RedirectUrl))
                        {
                            if (!negotiationResponse.RedirectUrl.EndsWith("/"))
                            {
                                negotiationResponse.RedirectUrl += "/";
                            }

                            // Update the URL based on the redirect response and restart the negotiation
                            Url = negotiationResponse.RedirectUrl;

                            if (!string.IsNullOrEmpty(negotiationResponse.AccessToken))
                            {
                                // This will stomp on the current Authorization header, but that's by design.
                                // If the server specified a token, that is expected to overrule the token the client is currently using.
                                Headers["Authorization"] = $"Bearer {negotiationResponse.AccessToken}";
                            }

                            negotiationAttempts += 1;
                            if (negotiationAttempts >= MaxRedirects)
                            {
                                throw new InvalidOperationException(Resources.Error_NegotiationLimitExceeded);
                            }
                            return StartNegotiation();
                        }
                    }

                    return CompleteNegotiation(negotiationResponse);
                })
                       .ContinueWithNotComplete(() => Disconnect()));
            }

            _connectionData = OnSending();

            return(StartNegotiation());
        }
        public void NormalConnectionTest()
        {
            // Arrange
            var connection = new Mock<Client.IConnection>();
            var transport = new Mock<IClientTransport>();

            // Setting the values such that a timeout or timeout warning isn't issued
            var keepAliveData = new KeepAliveData(
                timeoutWarning: TimeSpan.FromSeconds(5),
                timeout: TimeSpan.FromSeconds(10),
                checkInterval: TimeSpan.FromSeconds(2)
            );

            using (var monitor = new HeartbeatMonitor(connection.Object, new object(), keepAliveData.CheckInterval))
            {
                connection.Setup(m => m.LastMessageAt).Returns(DateTime.UtcNow);
                connection.Setup(m => m.KeepAliveData).Returns(keepAliveData);
                connection.Setup(m => m.State).Returns(ConnectionState.Connected);
                connection.Setup(m => m.Transport).Returns(transport.Object);

                monitor.Start();

                // Act - Setting timespan to be less than timeout and timeout warning
                monitor.Beat(TimeSpan.FromSeconds(2));

                // Assert
                Assert.False(monitor.TimedOut);
                Assert.False(monitor.HasBeenWarned);
            }
        }