Skip to content

Commit 6aa2bd6

Browse files
authored
test(ITcpSocketClient): improve code coverage (#6356)
* test: 重构代码提高覆盖率 * refactor: 更改接口方法名称 * refactor: 增加 SetDataPackageAdapter 扩展方法 * refactor: 精简代码 * feat: 增加 SetDataPackageAdapter 方法 * test: 更新单元测试 * test: 增加单元测试 * doc: 增加移除的路由
1 parent 1afd090 commit 6aa2bd6

File tree

11 files changed

+236
-61
lines changed

11 files changed

+236
-61
lines changed

src/BootstrapBlazor.Server/Components/Pages/Introduction.razor

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
@page "/docs"
22
@page "/introduction"
3+
@page "/components"
34

45
<h3>@Localizer["Title"]</h3>
56

src/BootstrapBlazor.Server/Components/Samples/Sockets/Adapters.razor.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ private async ValueTask OnReceivedAsync(ReadOnlyMemory<byte> data)
9393
if (_useDataAdapter)
9494
{
9595
// 使用数据适配器处理接收的数据
96-
await _dataAdapter.ReceiveAsync(data, _receiveTokenSource.Token);
96+
await _dataAdapter.HandlerAsync(data, _receiveTokenSource.Token);
9797
}
9898
else
9999
{

src/BootstrapBlazor/Extensions/ITcpSocketClientExtensions.cs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,4 +48,68 @@ public static ValueTask<bool> ConnectAsync(this ITcpSocketClient client, string
4848
var endPoint = Utility.ConvertToIpEndPoint(ipString, port);
4949
return client.ConnectAsync(endPoint, token);
5050
}
51+
52+
/// <summary>
53+
/// Configures the specified <see cref="ITcpSocketClient"/> to use the provided <see cref="IDataPackageAdapter"/>
54+
/// for processing received data and sets a callback to handle processed data.
55+
/// </summary>
56+
/// <remarks>This method sets up a two-way data processing pipeline: <list type="bullet"> <item>
57+
/// <description>The <paramref name="client"/> is configured to pass received data to the <paramref name="adapter"/>
58+
/// for processing.</description> </item> <item> <description>The <paramref name="adapter"/> is configured to invoke
59+
/// the provided <paramref name="callback"/> with the processed data.</description> </item> </list> Use this method
60+
/// to integrate a custom data processing adapter with a TCP socket client.</remarks>
61+
/// <param name="client">The <see cref="ITcpSocketClient"/> instance to configure.</param>
62+
/// <param name="adapter">The <see cref="IDataPackageAdapter"/> used to process incoming data.</param>
63+
/// <param name="callback">A callback function invoked with the processed data. The function receives a <see cref="ReadOnlyMemory{T}"/>
64+
/// containing the processed data and returns a <see cref="ValueTask"/>.</param>
65+
public static void SetDataPackageAdapter(this ITcpSocketClient client, IDataPackageAdapter adapter, Func<ReadOnlyMemory<byte>, ValueTask> callback)
66+
{
67+
// 设置 ITcpSocketClient 的回调函数
68+
client.ReceivedCallBack = async buffer =>
69+
{
70+
// 将接收到的数据传递给 DataPackageAdapter 进行数据处理合规数据触发 ReceivedCallBack 回调
71+
await adapter.HandlerAsync(buffer);
72+
};
73+
74+
// 设置 DataPackageAdapter 的回调函数
75+
adapter.ReceivedCallBack = buffer => callback(buffer);
76+
}
77+
78+
/// <summary>
79+
/// Configures the specified <see cref="ITcpSocketClient"/> to use a custom data package adapter and a callback
80+
/// function for processing received data.
81+
/// </summary>
82+
/// <remarks>This method sets up the <paramref name="client"/> to use the provided <paramref
83+
/// name="adapter"/> for handling incoming data. The adapter processes the raw data received by the client and
84+
/// attempts to convert it into an instance of <typeparamref name="TEntity"/>. If the conversion is successful, the
85+
/// <paramref name="callback"/> is invoked with the converted entity; otherwise, it is invoked with <see
86+
/// langword="null"/>.</remarks>
87+
/// <typeparam name="TEntity">The type of the entity that the data package adapter will attempt to convert the received data into.</typeparam>
88+
/// <param name="client">The <see cref="ITcpSocketClient"/> instance to configure.</param>
89+
/// <param name="adapter">The <see cref="IDataPackageAdapter"/> instance responsible for handling and processing incoming data.</param>
90+
/// <param name="callback">A callback function to be invoked with the processed data of type <typeparamref name="TEntity"/>. The callback
91+
/// receives <see langword="null"/> if the data cannot be converted to <typeparamref name="TEntity"/>.</param>
92+
public static void SetDataPackageAdapter<TEntity>(this ITcpSocketClient client, IDataPackageAdapter adapter, Func<TEntity?, Task> callback)
93+
{
94+
// 设置 ITcpSocketClient 的回调函数
95+
client.ReceivedCallBack = async buffer =>
96+
{
97+
// 将接收到的数据传递给 DataPackageAdapter 进行数据处理合规数据触发 ReceivedCallBack 回调
98+
await adapter.HandlerAsync(buffer);
99+
};
100+
101+
// 设置 DataPackageAdapter 的回调函数
102+
adapter.ReceivedCallBack = async buffer =>
103+
{
104+
TEntity? ret = default;
105+
if (adapter.TryConvertTo(buffer, out var t))
106+
{
107+
if (t is TEntity entity)
108+
{
109+
ret = entity;
110+
}
111+
}
112+
await callback(ret);
113+
};
114+
}
51115
}

src/BootstrapBlazor/Services/TcpSocket/DataPackage/DataPackageAdapter.cs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public class DataPackageAdapter : IDataPackageAdapter
3030
/// <param name="data"></param>
3131
/// <param name="token"></param>
3232
/// <returns></returns>
33-
public virtual async ValueTask ReceiveAsync(ReadOnlyMemory<byte> data, CancellationToken token = default)
33+
public virtual async ValueTask HandlerAsync(ReadOnlyMemory<byte> data, CancellationToken token = default)
3434
{
3535
if (DataPackageHandler != null)
3636
{
@@ -40,10 +40,22 @@ public virtual async ValueTask ReceiveAsync(ReadOnlyMemory<byte> data, Cancellat
4040
}
4141

4242
// 如果存在数据处理器则调用其处理方法
43-
await DataPackageHandler.ReceiveAsync(data, token);
43+
await DataPackageHandler.HandlerAsync(data, token);
4444
}
4545
}
4646

47+
/// <summary>
48+
/// <inheritdoc/>
49+
/// </summary>
50+
/// <param name="data"></param>
51+
/// <param name="entity"></param>
52+
/// <returns></returns>
53+
public virtual bool TryConvertTo(ReadOnlyMemory<byte> data, [NotNullWhen(true)] out object? entity)
54+
{
55+
entity = null;
56+
return false;
57+
}
58+
4759
/// <summary>
4860
/// Handles incoming data by invoking a callback method, if one is defined.
4961
/// </summary>

src/BootstrapBlazor/Services/TcpSocket/DataPackage/DataPackageHandlerBase.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public abstract class DataPackageHandlerBase : IDataPackageHandler
2626
/// <param name="data"></param>
2727
/// <param name="token"></param>
2828
/// <returns></returns>
29-
public abstract ValueTask ReceiveAsync(ReadOnlyMemory<byte> data, CancellationToken token = default);
29+
public abstract ValueTask HandlerAsync(ReadOnlyMemory<byte> data, CancellationToken token = default);
3030

3131
/// <summary>
3232
/// Handles the processing of a sticky package by adjusting the provided buffer and length.

src/BootstrapBlazor/Services/TcpSocket/DataPackage/DelimiterDataPackageHandler.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public DelimiterDataPackageHandler(byte[] delimiter)
5252
/// <param name="data"></param>
5353
/// <param name="token"></param>
5454
/// <returns></returns>
55-
public override async ValueTask ReceiveAsync(ReadOnlyMemory<byte> data, CancellationToken token = default)
55+
public override async ValueTask HandlerAsync(ReadOnlyMemory<byte> data, CancellationToken token = default)
5656
{
5757
data = ConcatBuffer(data);
5858

src/BootstrapBlazor/Services/TcpSocket/DataPackage/FixLengthDataPackageHandler.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public class FixLengthDataPackageHandler(int length) : DataPackageHandlerBase
2424
/// <param name="data"></param>
2525
/// <param name="token"></param>
2626
/// <returns></returns>
27-
public override async ValueTask ReceiveAsync(ReadOnlyMemory<byte> data, CancellationToken token = default)
27+
public override async ValueTask HandlerAsync(ReadOnlyMemory<byte> data, CancellationToken token = default)
2828
{
2929
while (data.Length > 0)
3030
{

src/BootstrapBlazor/Services/TcpSocket/DataPackage/IDataPackageAdapter.cs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,5 +38,16 @@ public interface IDataPackageAdapter
3838
/// not provided.</param>
3939
/// <returns>A <see cref="ValueTask"/> representing the asynchronous operation. The task completes when the data has been
4040
/// successfully received and processed.</returns>
41-
ValueTask ReceiveAsync(ReadOnlyMemory<byte> data, CancellationToken token = default);
41+
ValueTask HandlerAsync(ReadOnlyMemory<byte> data, CancellationToken token = default);
42+
43+
/// <summary>
44+
/// Attempts to convert the specified binary data into an object representation.
45+
/// </summary>
46+
/// <remarks>This method does not throw an exception if the conversion fails. Instead, it returns <see
47+
/// langword="false"/> and sets <paramref name="entity"/> to <see langword="null"/>.</remarks>
48+
/// <param name="data">The binary data to be converted. Must not be empty.</param>
49+
/// <param name="entity">When this method returns <see langword="true"/>, contains the converted object. When this method returns <see
50+
/// langword="false"/>, contains <see langword="null"/>.</param>
51+
/// <returns><see langword="true"/> if the conversion was successful; otherwise, <see langword="false"/>.</returns>
52+
bool TryConvertTo(ReadOnlyMemory<byte> data, [NotNullWhen(true)] out object? entity);
4253
}

src/BootstrapBlazor/Services/TcpSocket/DataPackage/IDataPackageHandler.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,5 @@ public interface IDataPackageHandler
2929
/// provided.</param>
3030
/// <returns>A <see cref="ValueTask{TResult}"/> containing <see langword="true"/> if the data was successfully received and
3131
/// processed; otherwise, <see langword="false"/>.</returns>
32-
ValueTask ReceiveAsync(ReadOnlyMemory<byte> data, CancellationToken token = default);
32+
ValueTask HandlerAsync(ReadOnlyMemory<byte> data, CancellationToken token = default);
3333
}

src/BootstrapBlazor/Services/TcpSocket/TcpSocketClientBase.cs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -148,9 +148,14 @@ public virtual async ValueTask<bool> SendAsync(ReadOnlyMemory<byte> data, Cancel
148148
}
149149
catch (OperationCanceledException ex)
150150
{
151-
Log(LogLevel.Warning, ex, token.IsCancellationRequested
152-
? $"TCP Socket send operation was canceled from {_localEndPoint} to {_remoteEndPoint}"
153-
: $"TCP Socket send operation timed out from {_localEndPoint} to {_remoteEndPoint}");
151+
if (token.IsCancellationRequested)
152+
{
153+
Log(LogLevel.Warning, ex, $"TCP Socket send operation was canceled from {_localEndPoint} to {_remoteEndPoint}");
154+
}
155+
else
156+
{
157+
Log(LogLevel.Warning, ex, $"TCP Socket send operation timed out from {_localEndPoint} to {_remoteEndPoint}");
158+
}
154159
}
155160
catch (Exception ex)
156161
{

0 commit comments

Comments
 (0)