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); } }
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 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); } }
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); } }