Skip to content

Commit beb1ef4

Browse files
committed
test: 增加 DefaultSocketClient 单元测试
1 parent 4ef5169 commit beb1ef4

File tree

2 files changed

+231
-51
lines changed

2 files changed

+231
-51
lines changed
Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the Apache 2.0 License
3+
// See the LICENSE file in the project root for more information.
4+
// Maintainer: Argo Zhang([email protected]) Website: https://www.blazor.zone
5+
6+
using Microsoft.Extensions.Logging;
7+
using System.Net;
8+
using System.Net.Sockets;
9+
using System.Reflection;
10+
11+
namespace UnitTest.Services;
12+
13+
public class DefaultSocketClientTest
14+
{
15+
[Fact]
16+
public void Logger_Null()
17+
{
18+
// 测试 Logger 为 null 的情况
19+
var client = CreateClient();
20+
var baseType = client.GetType().BaseType;
21+
Assert.NotNull(baseType);
22+
23+
// 获取 Logger 字段设置为 null 测试 Log 不会抛出异常
24+
var propertyInfo = baseType.GetProperty("Logger", BindingFlags.Public | BindingFlags.Instance);
25+
Assert.NotNull(propertyInfo);
26+
27+
propertyInfo.SetValue(client, null);
28+
29+
var methodInfo = baseType.GetMethod("Log", BindingFlags.NonPublic | BindingFlags.Instance);
30+
Assert.NotNull(methodInfo);
31+
methodInfo.Invoke(client, [LogLevel.Information, null!, "Test log message"]);
32+
}
33+
34+
[Fact]
35+
public async Task DefaultSocketClient_Ok()
36+
{
37+
var port = 8894;
38+
var server = StartTcpServer(port, MockDelimiterPackageAsync);
39+
var client = CreateClient();
40+
41+
// 获得 Client 泛型属性
42+
var baseType = client.GetType().BaseType;
43+
Assert.NotNull(baseType);
44+
45+
// 建立连接
46+
var connect = await client.ConnectAsync("localhost", port);
47+
Assert.True(connect);
48+
49+
var propertyInfo = baseType.GetProperty("Client", BindingFlags.NonPublic | BindingFlags.Instance);
50+
Assert.NotNull(propertyInfo);
51+
var instance = propertyInfo.GetValue(client);
52+
Assert.NotNull(instance);
53+
54+
ISocketClient socketClient = (ISocketClient)instance;
55+
Assert.NotNull(socketClient);
56+
Assert.True(socketClient.IsConnected);
57+
58+
await socketClient.CloseAsync();
59+
Assert.False(socketClient.IsConnected);
60+
61+
var buffer = new byte[10];
62+
var len = await socketClient.ReceiveAsync(buffer);
63+
Assert.Equal(0, len);
64+
}
65+
66+
[Fact]
67+
public void SocketClientOptions_Ok()
68+
{
69+
var options = new SocketClientOptions
70+
{
71+
ReceiveBufferSize = 1024 * 64,
72+
IsAutoReceive = true,
73+
ConnectTimeout = 1000,
74+
SendTimeout = 500,
75+
ReceiveTimeout = 500,
76+
LocalEndPoint = new IPEndPoint(IPAddress.Loopback, 0)
77+
};
78+
Assert.Equal(1024 * 64, options.ReceiveBufferSize);
79+
Assert.True(options.IsAutoReceive);
80+
Assert.Equal(1000, options.ConnectTimeout);
81+
Assert.Equal(500, options.SendTimeout);
82+
Assert.Equal(500, options.ReceiveTimeout);
83+
Assert.Equal(new IPEndPoint(IPAddress.Loopback, 0), options.LocalEndPoint);
84+
}
85+
86+
private static TcpListener StartTcpServer(int port, Func<TcpClient, Task> handler)
87+
{
88+
var server = new TcpListener(IPAddress.Loopback, port);
89+
server.Start();
90+
Task.Run(() => AcceptClientsAsync(server, handler));
91+
return server;
92+
}
93+
94+
private static async Task AcceptClientsAsync(TcpListener server, Func<TcpClient, Task> handler)
95+
{
96+
while (true)
97+
{
98+
var client = await server.AcceptTcpClientAsync();
99+
_ = Task.Run(() => handler(client));
100+
}
101+
}
102+
103+
private static async Task MockDelimiterPackageAsync(TcpClient client)
104+
{
105+
using var stream = client.GetStream();
106+
while (true)
107+
{
108+
var buffer = new byte[10240];
109+
var len = await stream.ReadAsync(buffer);
110+
if (len == 0)
111+
{
112+
break;
113+
}
114+
115+
// 回写数据到客户端
116+
var block = new ReadOnlyMemory<byte>(buffer, 0, len);
117+
await stream.WriteAsync(block, CancellationToken.None);
118+
119+
await Task.Delay(20);
120+
121+
// 模拟拆包发送第二段数据
122+
await stream.WriteAsync(new byte[] { 0x13, 0x10, 0x5, 0x6, 0x13, 0x10 }, CancellationToken.None);
123+
}
124+
}
125+
126+
private static ITcpSocketClient CreateClient()
127+
{
128+
var sc = new ServiceCollection();
129+
sc.AddLogging(builder =>
130+
{
131+
builder.AddProvider(new MockLoggerProvider());
132+
});
133+
sc.AddBootstrapBlazorTcpSocketFactory();
134+
var provider = sc.BuildServiceProvider();
135+
var factory = provider.GetRequiredService<ITcpSocketFactory>();
136+
var client = factory.GetOrCreate("test", op => op.LocalEndPoint = Utility.ConvertToIpEndPoint("localhost", 0));
137+
return client;
138+
}
139+
140+
class MockLoggerProvider : ILoggerProvider
141+
{
142+
public ILogger CreateLogger(string categoryName)
143+
{
144+
return new MockLogger();
145+
}
146+
147+
public void Dispose()
148+
{
149+
150+
}
151+
}
152+
153+
class MockLogger : ILogger
154+
{
155+
public IDisposable? BeginScope<TState>(TState state) where TState : notnull
156+
{
157+
return null;
158+
}
159+
160+
public bool IsEnabled(LogLevel logLevel)
161+
{
162+
return true;
163+
}
164+
165+
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter)
166+
{
167+
168+
}
169+
}
170+
171+
class MockSendErrorHandler : DataPackageHandlerBase
172+
{
173+
public ITcpSocketClient? Socket { get; set; }
174+
175+
public override ValueTask<ReadOnlyMemory<byte>> SendAsync(ReadOnlyMemory<byte> data, CancellationToken token = default)
176+
{
177+
throw new Exception("Mock send failed");
178+
}
179+
}
180+
181+
class MockSendCancelHandler : DataPackageHandlerBase
182+
{
183+
public ITcpSocketClient? Socket { get; set; }
184+
185+
public override async ValueTask<ReadOnlyMemory<byte>> SendAsync(ReadOnlyMemory<byte> data, CancellationToken token = default)
186+
{
187+
if (Socket != null)
188+
{
189+
await Socket.CloseAsync();
190+
}
191+
await Task.Delay(10, token);
192+
return data;
193+
}
194+
}
195+
196+
class MockReceiveErrorHandler : DataPackageHandlerBase
197+
{
198+
public override ValueTask<ReadOnlyMemory<byte>> SendAsync(ReadOnlyMemory<byte> data, CancellationToken token = default)
199+
{
200+
return ValueTask.FromResult(data);
201+
}
202+
203+
public override async ValueTask ReceiveAsync(ReadOnlyMemory<byte> data, CancellationToken token = default)
204+
{
205+
await base.ReceiveAsync(data, token);
206+
207+
// 模拟接收数据时报错
208+
throw new InvalidOperationException("Test Error");
209+
}
210+
}
211+
212+
class MockSendTimeoutHandler : DataPackageHandlerBase
213+
{
214+
public override async ValueTask<ReadOnlyMemory<byte>> SendAsync(ReadOnlyMemory<byte> data, CancellationToken token = default)
215+
{
216+
// 模拟发送超时
217+
await Task.Delay(200, token);
218+
return data;
219+
}
220+
}
221+
222+
class MockReceiveTimeoutHandler : DataPackageHandlerBase
223+
{
224+
public override async ValueTask ReceiveAsync(ReadOnlyMemory<byte> data, CancellationToken token = default)
225+
{
226+
// 模拟接收超时
227+
await Task.Delay(200, token);
228+
await base.ReceiveAsync(data, token);
229+
}
230+
}
231+
}

test/UnitTest/Services/TcpSocketFactoryTest.cs

Lines changed: 0 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -460,57 +460,6 @@ public async Task DelimiterDataPackageHandler_Ok()
460460
Assert.NotNull(ex);
461461
}
462462

463-
[Fact]
464-
public void Logger_Null()
465-
{
466-
// 测试 Logger 为 null 的情况
467-
var client = CreateClient();
468-
var baseType = client.GetType().BaseType;
469-
Assert.NotNull(baseType);
470-
471-
// 获取 Logger 字段设置为 null 测试 Log 不会抛出异常
472-
var propertyInfo = baseType.GetProperty("Logger", BindingFlags.Public | BindingFlags.Instance);
473-
Assert.NotNull(propertyInfo);
474-
475-
propertyInfo.SetValue(client, null);
476-
477-
var methodInfo = baseType.GetMethod("Log", BindingFlags.NonPublic | BindingFlags.Instance);
478-
Assert.NotNull(methodInfo);
479-
methodInfo.Invoke(client, [LogLevel.Information, null!, "Test log message"]);
480-
}
481-
482-
[Fact]
483-
public async Task DefaultSocketClient_Ok()
484-
{
485-
var port = 8894;
486-
var server = StartTcpServer(port, MockDelimiterPackageAsync);
487-
var client = CreateClient();
488-
489-
// 获得 Client 泛型属性
490-
var baseType = client.GetType().BaseType;
491-
Assert.NotNull(baseType);
492-
493-
// 建立连接
494-
var connect = await client.ConnectAsync("localhost", port);
495-
Assert.True(connect);
496-
497-
var propertyInfo = baseType.GetProperty("Client", BindingFlags.NonPublic | BindingFlags.Instance);
498-
Assert.NotNull(propertyInfo);
499-
var instance = propertyInfo.GetValue(client);
500-
Assert.NotNull(instance);
501-
502-
ISocketClient socketClient = (ISocketClient)instance;
503-
Assert.NotNull(socketClient);
504-
Assert.True(socketClient.IsConnected);
505-
506-
await socketClient.CloseAsync();
507-
Assert.False(socketClient.IsConnected);
508-
509-
var buffer = new byte[10];
510-
var len = await socketClient.ReceiveAsync(buffer);
511-
Assert.Equal(0, len);
512-
}
513-
514463
private static TcpListener StartTcpServer(int port, Func<TcpClient, Task> handler)
515464
{
516465
var server = new TcpListener(IPAddress.Loopback, port);

0 commit comments

Comments
 (0)