Skip to content

Commit

Permalink
Using Reflection to create a kestrel client for unit testing
Browse files Browse the repository at this point in the history
  • Loading branch information
wj8400684 committed Dec 8, 2024
1 parent 051e5ad commit 96eaf4a
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 47 deletions.
111 changes: 64 additions & 47 deletions test/SuperSocket.Tests/ClientTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@
using SuperSocket.Server.Abstractions;
using SuperSocket.Server.Abstractions.Session;
using System.Threading;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging.Abstractions;
using SuperSocket.Kestrel;
using SuperSocket.WebSocket;

namespace SuperSocket.Tests
Expand Down Expand Up @@ -256,78 +259,92 @@ public async Task TestCommandLine(Type hostConfiguratorType)
}
}

[Fact]
[Fact]
[Trait("Category", "TestDetachableConnection")]
public async Task TestDetachableConnection()
{
IHostConfigurator hostConfigurator = new RegularHostConfigurator();

await TestDetachableConnectionInternal(hostConfigurator, (_, socket) =>
new StreamPipeConnection(
hostConfigurator.GetClientStream(socket).Result,
socket.RemoteEndPoint,
socket.LocalEndPoint,
new ConnectionOptions
{
Logger = DefaultLoggerFactory.CreateLogger(nameof(TestDetachableConnection)),
ReadAsDemand = true
})
);

/* KestrelPipeConnection doesn't support Detach right now.
await TestDetachableConnectionInternal(new KestralConnectionHostConfigurator(), (server, socket) =>
new KestrelPipeConnection(
server.ServiceProvider.GetService<SocketConnectionContextFactory>().Create(socket),
using (var server = CreateSocketServerBuilder<TextPackageInfo, LinePipelineFilter>(hostConfigurator)
.UsePackageHandler(async (s, p) =>
{
await s.SendAsync(Utf8Encoding.GetBytes("PRE-" + p.Text + "\r\n"));
}).BuildAsServer())
{
Assert.Equal("TestServer", server.Name);

Assert.True(await server.StartAsync());
OutputHelper.WriteLine("Server started.");

using (var socket = hostConfigurator.CreateClient())
{
await TestDetachableConnectionInternal(hostConfigurator, server, ser => new StreamPipeConnection(
hostConfigurator.GetClientStream(socket).Result,
socket.RemoteEndPoint,
socket.LocalEndPoint,
new ConnectionOptions
{
Logger = DefaultLoggerFactory.CreateLogger(nameof(TestDetachableConnection)),
ReadAsDemand = false
}
)
);
*/
}
ReadAsDemand = true
}), () => socket.Connected);
}

await server.StopAsync();
}

async Task TestDetachableConnectionInternal(IHostConfigurator hostConfigurator, Func<IServer, Socket, IConnection> connectionFactory)
{
using (var server = CreateSocketServerBuilder<TextPackageInfo, LinePipelineFilter>(hostConfigurator)
.UsePackageHandler(async (s, p) =>
{
await s.SendAsync(Utf8Encoding.GetBytes("PRE-" + p.Text + "\r\n"));
}).BuildAsServer())
.ConfigureServices((ctx, services) => services.AddSocketConnectionFactory())
.UsePackageHandler(async (s, p) =>
{
await s.SendAsync(Utf8Encoding.GetBytes("PRE-" + p.Text + "\r\n"));
}).BuildAsServer())
{

Assert.Equal("TestServer", server.Name);

Assert.True(await server.StartAsync());
OutputHelper.WriteLine("Server started.");

using (var socket = hostConfigurator.CreateClient())
var connectionFactory = server.ServiceProvider
.GetRequiredService<Microsoft.AspNetCore.Connections.IConnectionFactory>();
await using (var context = await connectionFactory.ConnectAsync(hostConfigurator.GetServerEndPoint()))
{
var connection = connectionFactory(server, socket);
await TestDetachableConnectionInternal(hostConfigurator, server, ser => new KestrelPipeConnection(
context,
new ConnectionOptions
{
Logger = DefaultLoggerFactory.CreateLogger(nameof(TestDetachableConnection)),
ReadAsDemand = true
}
), () => !context.ConnectionClosed.IsCancellationRequested);
}

await TestConnection(connection);
await server.StopAsync();
}
}

OutputHelper.WriteLine("Before DetachAsync");
async Task TestDetachableConnectionInternal(IHostConfigurator hostConfigurator,
IServer server,
Func<IServer, IConnection> connectionFactory,
Func<bool> checkConnectionFactory)
{
var connection = connectionFactory(server);

await connection.DetachAsync();
await TestConnection(connection);

// the connection is still alive in the server
Assert.Equal(1, server.SessionCount);
OutputHelper.WriteLine("Before DetachAsync");

// socket.Connected is is still connected
Assert.True(socket.Connected);
await connection.DetachAsync();

// Attach the socket with another connection
connection = connectionFactory(server, socket);
// the connection is still alive in the server
Assert.Equal(1, server.SessionCount);

await TestConnection(connection);
}
// socket.Connected is is still connected
Assert.True(checkConnectionFactory());

await server.StopAsync();
}
}
// Attach the socket with another connection
connection = connectionFactory(server);

await TestConnection(connection);
}
async Task TestConnection(IConnection connection)
{
var packagePipe = connection.RunAsync(new LinePipelineFilter());
Expand Down
25 changes: 25 additions & 0 deletions test/SuperSocket.Tests/ServiceCollectionExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using System;
using Microsoft.AspNetCore.Connections;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets;
using Microsoft.Extensions.DependencyInjection;

namespace SuperSocket.Tests;

public static class ServiceCollectionExtensions
{
private const string SocketConnectionFactoryTypeName =
"Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.SocketConnectionFactory";

private static Type FindSocketConnectionFactory()
{
var assembly = typeof(SocketTransportOptions).Assembly;
var connectionFactoryType = assembly.GetType(SocketConnectionFactoryTypeName);
return connectionFactoryType ?? throw new NotSupportedException(SocketConnectionFactoryTypeName);
}

public static IServiceCollection AddSocketConnectionFactory(this IServiceCollection services)
{
var factoryType = FindSocketConnectionFactory();
return services.AddSingleton(typeof(IConnectionFactory), factoryType);
}
}

0 comments on commit 96eaf4a

Please sign in to comment.