public async void TestShutdown()
        {
            var clientManager  = new TestClientConnectionManager();
            var serviceManager = new TestServiceConnectionManager <Hub>();

            var options = new TestOptions();

            options.Value.GracefulShutdown = new GracefulShutdownOptions()
            {
                Timeout = TimeSpan.FromSeconds(1),
                Mode    = GracefulShutdownMode.WaitForClientsClose
            };

            var dispatcher = new ServiceHubDispatcher <Hub>(
                null,
                serviceManager,
                clientManager,
                null,
                options,
                NullLoggerFactory.Instance,
                new TestRouter(),
                null,
                null,
                null
                );

            await dispatcher.ShutdownAsync();

            DateTime now = DateTime.Now;

            Assert.True(now > serviceManager.StopTime);
            Assert.True(serviceManager.StopTime > clientManager.CompleteTime);
            Assert.True(clientManager.CompleteTime > serviceManager.OfflineTime);
        }
예제 #2
0
 public TestServiceConnection(TestConnectionContainer container,
                              IServiceProtocol serviceProtocol,
                              TestClientConnectionManager clientConnectionManager,
                              IConnectionFactory connectionFactory,
                              ILoggerFactory loggerFactory,
                              ConnectionDelegate connectionDelegate,
                              IClientConnectionFactory clientConnectionFactory,
                              string serverId,
                              string connectionId,
                              HubServiceEndpoint endpoint,
                              IServiceMessageHandler serviceMessageHandler,
                              IServiceEventHandler serviceEventHandler,
                              ServiceConnectionType connectionType = ServiceConnectionType.Default,
                              GracefulShutdownMode mode            = GracefulShutdownMode.Off,
                              int closeTimeOutMilliseconds         = 10000) : base(
         serviceProtocol,
         clientConnectionManager,
         connectionFactory,
         loggerFactory,
         connectionDelegate,
         clientConnectionFactory,
         serverId,
         connectionId,
         endpoint,
         serviceMessageHandler,
         serviceEventHandler,
         connectionType: connectionType,
         mode: mode,
         closeTimeOutMilliseconds: closeTimeOutMilliseconds)
 {
     _container = container;
     ClientConnectionManager = clientConnectionManager;
 }
예제 #3
0
        public async void TestShutdown()
        {
            var index          = new StrongBox <int>();
            var clientManager  = new TestClientConnectionManager(index);
            var serviceManager = new TestServiceConnectionManager <Hub>(index);

            var options = new TestOptions();

            options.Value.GracefulShutdown = new GracefulShutdownOptions()
            {
                Timeout = TimeSpan.FromSeconds(1),
                Mode    = GracefulShutdownMode.WaitForClientsClose
            };

            var dispatcher = new ServiceHubDispatcher <Hub>(
                null,
                TestHubContext <Hub> .GetInstance(),
                serviceManager,
                clientManager,
                null,
                options,
                NullLoggerFactory.Instance,
                new TestRouter(),
                null,
                null,
                null
                );

            await dispatcher.ShutdownAsync();

            Assert.Equal(3, serviceManager.StopIndex);
            Assert.Equal(2, clientManager.CompleteIndex);
            Assert.Equal(1, serviceManager.OfflineIndex);
        }
        public async void TestShutdown()
        {
            var clientManager  = new TestClientConnectionManager();
            var serviceManager = new TestServiceConnectionManager <Hub>();

            var options = new TestOptions();

            options.Value.EnableGracefulShutdown = true;
            options.Value.ServerShutdownTimeout  = TimeSpan.FromSeconds(1);

            var dispatcher = new ServiceHubDispatcher <Hub>(
                null,
                serviceManager,
                clientManager,
                null,
                options,
                NullLoggerFactory.Instance,
                new TestRouter(),
                null,
                null,
                null
                );

            await dispatcher.ShutdownAsync();

            Assert.True(clientManager.completeTime.Subtract(serviceManager.offlineTime) > TimeSpan.FromMilliseconds(100));
            Assert.True(clientManager.completeTime.Subtract(serviceManager.stopTime) < -TimeSpan.FromMilliseconds(100));
            Assert.True(serviceManager.offlineTime != serviceManager.stopTime);
        }
        public async Task ClientConnectionOutgoingAbortCanEndLifeTime()
        {
            using (StartVerifiableLog(out var loggerFactory, LogLevel.Warning, expectedErrors: c => true,
                                      logChecker: logs =>
            {
                Assert.Equal(2, logs.Count);
                Assert.Equal("SendLoopStopped", logs[0].Write.EventId.Name);
                Assert.Equal("ApplicationTaskFailed", logs[1].Write.EventId.Name);
                return(true);
            }))
            {
                var            ccm                 = new TestClientConnectionManager();
                var            ccf                 = new ClientConnectionFactory();
                var            protocol            = new ServiceProtocol();
                TestConnection transportConnection = null;
                var            connectionFactory   = new TestConnectionFactory(conn =>
                {
                    transportConnection = conn;
                    return(Task.CompletedTask);
                });
                var services          = new ServiceCollection();
                var connectionHandler = new EndlessConnectionHandler();
                services.AddSingleton(connectionHandler);
                var builder = new ConnectionBuilder(services.BuildServiceProvider());
                builder.UseConnectionHandler <EndlessConnectionHandler>();
                ConnectionDelegate handler = builder.Build();
                var connection             = new ServiceConnection(protocol, ccm, connectionFactory, loggerFactory, handler, ccf,
                                                                   "serverId", Guid.NewGuid().ToString("N"), null, null,
                                                                   closeTimeOutMilliseconds: 500);

                var connectionTask = connection.StartAsync();

                // completed handshake
                await connection.ConnectionInitializedTask.OrTimeout();

                Assert.Equal(ServiceConnectionStatus.Connected, connection.Status);
                var clientConnectionId = Guid.NewGuid().ToString();

                await transportConnection.Application.Output.WriteAsync(
                    protocol.GetMessageBytes(new OpenConnectionMessage(clientConnectionId, new Claim[] { })));

                var clientConnection = await ccm.WaitForClientConnectionAsync(clientConnectionId).OrTimeout();

                clientConnection.CancelOutgoing();

                await clientConnection.LifetimeTask.OrTimeout();

                // complete reading to end the connection
                transportConnection.Application.Output.Complete();

                // 1s for application task to timeout
                await connectionTask.OrTimeout(1000);

                Assert.Equal(ServiceConnectionStatus.Disconnected, connection.Status);
                Assert.Empty(ccm.ClientConnections);

                connectionHandler.CancellationToken.Cancel();
            }
        }
        public async Task TestServiceConnectionWithEndlessApplicationTaskNeverEnds()
        {
            var clientConnectionId = Guid.NewGuid().ToString();

            using (StartVerifiableLog(out var loggerFactory, LogLevel.Warning, expectedErrors: c => true,
                                      logChecker: logs =>
            {
                Assert.Single(logs);
                Assert.Equal("DetectedLongRunningApplicationTask", logs[0].Write.EventId.Name);
                Assert.Equal($"The connection {clientConnectionId} has a long running application logic that prevents the connection from complete.", logs[0].Write.Message);
                return(true);
            }))
            {
                var            ccm                 = new TestClientConnectionManager();
                var            ccf                 = new ClientConnectionFactory();
                var            protocol            = new ServiceProtocol();
                TestConnection transportConnection = null;
                var            connectionFactory   = new TestConnectionFactory(conn =>
                {
                    transportConnection = conn;
                    return(Task.CompletedTask);
                });
                var services          = new ServiceCollection();
                var connectionHandler = new EndlessConnectionHandler();
                services.AddSingleton(connectionHandler);
                var builder = new ConnectionBuilder(services.BuildServiceProvider());
                builder.UseConnectionHandler <EndlessConnectionHandler>();
                ConnectionDelegate handler = builder.Build();
                var connection             = new ServiceConnection(protocol, ccm, connectionFactory, loggerFactory, handler, ccf,
                                                                   "serverId", Guid.NewGuid().ToString("N"),
                                                                   null, null, null, closeTimeOutMilliseconds: 1);

                var connectionTask = connection.StartAsync();

                // completed handshake
                await connection.ConnectionInitializedTask.OrTimeout();

                Assert.Equal(ServiceConnectionStatus.Connected, connection.Status);

                await transportConnection.Application.Output.WriteAsync(
                    protocol.GetMessageBytes(new OpenConnectionMessage(clientConnectionId, new Claim[] { })));

                var clientConnection = await ccm.WaitForClientConnectionAsync(clientConnectionId).OrTimeout();

                // complete reading to end the connection
                transportConnection.Application.Output.Complete();

                // Assert timeout
                var lifetime = clientConnection.LifetimeTask;
                var task     = await Task.WhenAny(lifetime, Task.Delay(1000));

                Assert.NotEqual(lifetime, task);

                Assert.Equal(ServiceConnectionStatus.Disconnected, connection.Status);

                // since the service connection ends, the client connection is cleaned up from the collection...
                Assert.Empty(ccm.ClientConnections);
            }
        }
        public async Task ClientConnectionWithDiagnosticClientTagTest()
        {
            using (StartVerifiableLog(out var loggerFactory))
            {
                var            ccm                 = new TestClientConnectionManager();
                var            ccf                 = new ClientConnectionFactory();
                var            protocol            = new ServiceProtocol();
                TestConnection transportConnection = null;
                var            connectionFactory   = new TestConnectionFactory(conn =>
                {
                    transportConnection = conn;
                    return(Task.CompletedTask);
                });

                var diagnosticClientConnectionId = "diagnosticClient";
                var normalClientConnectionId     = "normalClient";

                var services          = new ServiceCollection();
                var connectionHandler = new DiagnosticClientConnectionHandler(diagnosticClientConnectionId);
                services.AddSingleton(connectionHandler);
                var builder = new ConnectionBuilder(services.BuildServiceProvider());
                builder.UseConnectionHandler <DiagnosticClientConnectionHandler>();
                ConnectionDelegate handler = builder.Build();

                var connection = new ServiceConnection(protocol, ccm, connectionFactory, loggerFactory, handler, ccf,
                                                       "serverId", Guid.NewGuid().ToString("N"), null, null, closeTimeOutMilliseconds: 500);

                var connectionTask = connection.StartAsync();

                // completed handshake
                await connection.ConnectionInitializedTask.OrTimeout();

                Assert.Equal(ServiceConnectionStatus.Connected, connection.Status);

                await transportConnection.Application.Output.WriteAsync(
                    protocol.GetMessageBytes(new OpenConnectionMessage(diagnosticClientConnectionId, null, new Dictionary <string, StringValues>
                {
                    { Constants.AsrsIsDiagnosticClient, "true" }
                }, null)));

                await transportConnection.Application.Output.WriteAsync(
                    protocol.GetMessageBytes(new OpenConnectionMessage(normalClientConnectionId, null)));

                var connections = await Task.WhenAll(ccm.WaitForClientConnectionAsync(normalClientConnectionId).OrTimeout(),
                                                     ccm.WaitForClientConnectionAsync(diagnosticClientConnectionId).OrTimeout());

                await Task.WhenAll(from c in connections select c.LifetimeTask.OrTimeout());

                // complete reading to end the connection
                transportConnection.Application.Output.Complete();

                // 1s for application task to timeout
                await connectionTask.OrTimeout(1000);

                Assert.Equal(ServiceConnectionStatus.Disconnected, connection.Status);
                Assert.Empty(ccm.ClientConnections);
            }
        }
        public async Task TestServiceConnectionWithNormalApplicationTask()
        {
            using (StartVerifiableLog(out var loggerFactory, LogLevel.Debug))
            {
                var            ccm                 = new TestClientConnectionManager();
                var            ccf                 = new ClientConnectionFactory();
                var            protocol            = new ServiceProtocol();
                TestConnection transportConnection = null;
                var            connectionFactory   = new TestConnectionFactory(conn =>
                {
                    transportConnection = conn;
                    return(Task.CompletedTask);
                });
                var services = new ServiceCollection();
                var builder  = new ConnectionBuilder(services.BuildServiceProvider());
                builder.UseConnectionHandler <TestConnectionHandler>();
                ConnectionDelegate handler = builder.Build();
                var connection             = new ServiceConnection(protocol, ccm, connectionFactory, loggerFactory, handler, ccf,
                                                                   "serverId", Guid.NewGuid().ToString("N"), null, null);

                var connectionTask = connection.StartAsync();

                // completed handshake
                await connection.ConnectionInitializedTask.OrTimeout();

                Assert.Equal(ServiceConnectionStatus.Connected, connection.Status);
                var clientConnectionId = Guid.NewGuid().ToString();

                await transportConnection.Application.Output.WriteAsync(
                    protocol.GetMessageBytes(new OpenConnectionMessage(clientConnectionId, new Claim[] { })));

                var clientConnection = await ccm.WaitForClientConnectionAsync(clientConnectionId).OrTimeout();

                await transportConnection.Application.Output.WriteAsync(
                    protocol.GetMessageBytes(new CloseConnectionMessage(clientConnectionId)));

                // Normal end with close message
                await ccm.WaitForClientConnectionRemovalAsync(clientConnectionId).OrTimeout();

                // another connection comes in
                clientConnectionId = Guid.NewGuid().ToString();

                await transportConnection.Application.Output.WriteAsync(
                    protocol.GetMessageBytes(new OpenConnectionMessage(clientConnectionId, new Claim[] { })));

                clientConnection = await ccm.WaitForClientConnectionAsync(clientConnectionId).OrTimeout();

                // complete reading to end the connection
                transportConnection.Application.Output.Complete();

                await connectionTask.OrTimeout();

                Assert.Equal(ServiceConnectionStatus.Disconnected, connection.Status);
                Assert.Empty(ccm.ClientConnections);
            }
        }
예제 #9
0
        private static TestServiceConnection CreateServiceConnection(Action <ConnectionBuilder> use = null,
                                                                     TestClientConnectionManager clientConnectionManager = null,
                                                                     string serverId                                  = null,
                                                                     string connectionId                              = null,
                                                                     GracefulShutdownMode?mode                        = null,
                                                                     IServiceMessageHandler messageHandler            = null,
                                                                     IServiceEventHandler eventHandler                = null,
                                                                     IClientConnectionFactory clientConnectionFactory = null,
                                                                     ILoggerFactory loggerFactory                     = null)
        {
            clientConnectionManager ??= new TestClientConnectionManager();
            clientConnectionFactory ??= new ClientConnectionFactory();

            var container         = new TestConnectionContainer();
            var connectionFactory = new TestConnectionFactory(conn =>
            {
                container.Instance = conn;
                return(Task.CompletedTask);
            });

            var services = new ServiceCollection();
            var builder  = new ConnectionBuilder(services.BuildServiceProvider());

            if (use == null)
            {
                use = (builder) => builder.UseConnectionHandler <TestConnectionHandler>();
            }
            use(builder);

            builder.UseConnectionHandler <TestConnectionHandler>();

            ConnectionDelegate handler = builder.Build();

            return(new TestServiceConnection(
                       container,
                       new ServiceProtocol(),
                       clientConnectionManager,
                       connectionFactory,
                       loggerFactory ?? NullLoggerFactory.Instance,
                       handler,
                       clientConnectionFactory,
                       serverId ?? "serverId",
                       connectionId ?? Guid.NewGuid().ToString("N"),
                       null,
                       messageHandler ?? new TestServiceMessageHandler(),
                       eventHandler ?? new TestServiceEventHandler(),
                       mode: mode ?? GracefulShutdownMode.Off
                       ));
        }
예제 #10
0
        private static TestServiceConnection CreateServiceConnection(ConnectionHandler handler = null,
                                                                     TestClientConnectionManager clientConnectionManager = null,
                                                                     string serverId                                  = null,
                                                                     string connectionId                              = null,
                                                                     GracefulShutdownMode?mode                        = null,
                                                                     IServiceMessageHandler messageHandler            = null,
                                                                     IServiceEventHandler eventHandler                = null,
                                                                     IClientConnectionFactory clientConnectionFactory = null,
                                                                     HubServiceEndpoint hubServiceEndpoint            = null,
                                                                     ILoggerFactory loggerFactory                     = null)
        {
            clientConnectionManager ??= new TestClientConnectionManager();
            clientConnectionFactory ??= new TestClientConnectionFactory();

            var container         = new TestConnectionContainer();
            var connectionFactory = new TestConnectionFactory(conn =>
            {
                container.Instance = conn;
                return(Task.CompletedTask);
            });

            var services = new ServiceCollection();
            var builder  = new ConnectionBuilder(services.BuildServiceProvider());

            if (handler == null)
            {
                handler = new TestConnectionHandler();
            }

            return(new TestServiceConnection(
                       container,
                       new ServiceProtocol(),
                       clientConnectionManager,
                       connectionFactory,
                       loggerFactory ?? NullLoggerFactory.Instance,
                       handler.OnConnectedAsync,
                       clientConnectionFactory,
                       serverId ?? "serverId",
                       connectionId ?? Guid.NewGuid().ToString("N"),
                       hubServiceEndpoint ?? new TestHubServiceEndpoint(),
                       messageHandler ?? new TestServiceMessageHandler(),
                       eventHandler ?? new TestServiceEventHandler(),
                       mode: mode ?? GracefulShutdownMode.Off
                       ));
        }
예제 #11
0
        public async Task ClientConnectionContextAbortCanSendOutCloseMessage()
        {
            using (StartVerifiableLog(out var loggerFactory, LogLevel.Trace, expectedErrors: c => true,
                                      logChecker: logs =>
            {
                return(true);
            }))
            {
                var            ccm                 = new TestClientConnectionManager();
                var            ccf                 = new ClientConnectionFactory();
                var            protocol            = new ServiceProtocol();
                TestConnection transportConnection = null;
                var            connectionFactory   = new TestConnectionFactory(conn =>
                {
                    transportConnection = conn;
                    return(Task.CompletedTask);
                });

                var services          = new ServiceCollection();
                var lastWill          = "This is the last will";
                var connectionHandler = new LastWillConnectionHandler(lastWill);
                services.AddSingleton(connectionHandler);
                var builder = new ConnectionBuilder(services.BuildServiceProvider());
                builder.UseConnectionHandler <LastWillConnectionHandler>();
                ConnectionDelegate handler = builder.Build();

                var connection = new ServiceConnection(protocol, ccm, connectionFactory, loggerFactory, handler, ccf,
                                                       "serverId", Guid.NewGuid().ToString("N"), null, null, closeTimeOutMilliseconds: 500);

                var connectionTask = connection.StartAsync();

                // completed handshake
                await connection.ConnectionInitializedTask.OrTimeout();

                Assert.Equal(ServiceConnectionStatus.Connected, connection.Status);
                var clientConnectionId = Guid.NewGuid().ToString();

                await transportConnection.Application.Output.WriteAsync(
                    protocol.GetMessageBytes(new OpenConnectionMessage(clientConnectionId, new Claim[] { })));

                var clientConnection = await ccm.WaitForClientConnectionAsync(clientConnectionId).OrTimeout();

                await clientConnection.LifetimeTask.OrTimeout();

                transportConnection.Transport.Output.Complete();
                var input = await transportConnection.Application.Input.ReadAsync();

                var buffer   = input.Buffer;
                var canParse = protocol.TryParseMessage(ref buffer, out var msg);
                Assert.True(canParse);
                var message = msg as ConnectionDataMessage;
                Assert.NotNull(message);

                Assert.Equal(clientConnectionId, message.ConnectionId);
                Assert.Equal(lastWill, Encoding.UTF8.GetString(message.Payload.First.ToArray()));

                // complete reading to end the connection
                transportConnection.Application.Output.Complete();

                // 1s for application task to timeout
                await connectionTask.OrTimeout(1000);

                Assert.Equal(ServiceConnectionStatus.Disconnected, connection.Status);
                Assert.Empty(ccm.ClientConnections);
            }
        }
예제 #12
0
        public async Task TestServiceConnectionWithErrorApplicationTask()
        {
            using (StartVerifiableLog(out var loggerFactory, LogLevel.Warning, expectedErrors: c => true,
                                      logChecker: logs =>
            {
                Assert.Equal(2, logs.Count);
                Assert.Equal("SendLoopStopped", logs[0].Write.EventId.Name);
                Assert.Equal("ApplicationTaskFailed", logs[1].Write.EventId.Name);
                return(true);
            }))
            {
                var            ccm                 = new TestClientConnectionManager();
                var            ccf                 = new ClientConnectionFactory();
                var            protocol            = new ServiceProtocol();
                TestConnection transportConnection = null;
                var            connectionFactory   = new TestConnectionFactory(conn =>
                {
                    transportConnection = conn;
                    return(Task.CompletedTask);
                });
                var services          = new ServiceCollection();
                var errorTcs          = new TaskCompletionSource <Exception>();
                var connectionHandler = new ErrorConnectionHandler(errorTcs);
                services.AddSingleton(connectionHandler);
                var builder = new ConnectionBuilder(services.BuildServiceProvider());

                builder.UseConnectionHandler <ErrorConnectionHandler>();
                ConnectionDelegate handler = builder.Build();

                var connection = new ServiceConnection(protocol, ccm, connectionFactory, loggerFactory, handler, ccf,
                                                       "serverId", Guid.NewGuid().ToString("N"), null, null);

                var connectionTask = connection.StartAsync();

                // completed handshake
                await connection.ConnectionInitializedTask.OrTimeout();

                Assert.Equal(ServiceConnectionStatus.Connected, connection.Status);
                var clientConnectionId = Guid.NewGuid().ToString();

                await transportConnection.Application.Output.WriteAsync(
                    protocol.GetMessageBytes(new OpenConnectionMessage(clientConnectionId, new Claim[] { })));

                var clientConnection = await ccm.WaitForClientConnectionAsync(clientConnectionId).OrTimeout();

                errorTcs.SetException(new InvalidOperationException("error operation"));

                await clientConnection.LifetimeTask.OrTimeout();

                // Should complete the connection when application throws
                await ccm.WaitForClientConnectionRemovalAsync(clientConnectionId).OrTimeout();

                // Application task should not affect the underlying service connection
                Assert.Equal(ServiceConnectionStatus.Connected, connection.Status);

                // complete reading to end the connection
                transportConnection.Application.Output.Complete();

                await connectionTask.OrTimeout();

                Assert.Equal(ServiceConnectionStatus.Disconnected, connection.Status);
                Assert.Empty(ccm.ClientConnections);
            }
        }