private TestServiceConnection MockServiceConnection(IConnectionFactory serviceConnectionFactory = null, IClientConnectionFactory clientConnectionFactory = null, ILoggerFactory loggerFactory = null, GracefulShutdownMode mode = GracefulShutdownMode.Off) { clientConnectionFactory ??= new ClientConnectionFactory(); serviceConnectionFactory ??= new TestConnectionFactory(conn => Task.CompletedTask); loggerFactory ??= NullLoggerFactory.Instance; var services = new ServiceCollection(); var connectionHandler = new EndlessConnectionHandler(); services.AddSingleton(connectionHandler); var builder = new ConnectionBuilder(services.BuildServiceProvider()); builder.UseConnectionHandler <EndlessConnectionHandler>(); ConnectionDelegate handler = builder.Build(); return(new TestServiceConnection( serviceConnectionFactory, clientConnectionFactory, loggerFactory, handler, mode: mode )); }
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); } }