From 407d82106c9217dedd435d68716605c46ce431a6 Mon Sep 17 00:00:00 2001 From: walterlv Date: Tue, 16 Jul 2024 10:10:00 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8A=8A=E6=89=80=E6=9C=89=20ContractTestCase?= =?UTF-8?q?=20=E6=94=B9=E4=B8=BA=20TestMethod=EF=BC=8C=E5=9B=A0=E4=B8=BA?= =?UTF-8?q?=E5=89=8D=E8=80=85=E5=B7=B2=E4=B8=8D=E6=94=AF=E6=8C=81=E6=96=B0?= =?UTF-8?q?=E7=9A=84=E6=B5=8B=E8=AF=95=E6=A1=86=E6=9E=B6=E4=BA=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Directory.Packages.props | 7 +- .../dotnetCampus.Ipc.Analyzers.Tests.csproj | 1 - .../dotnetCampus.Ipc.Tests/AckManagerTest.cs | 1 - .../GeneratedProxies/IpcObjectTests.cs | 977 +++++++++--------- ...tGeneratedTestOnlyFakeIpcObjectIpcShape.cs | 8 +- .../IpcClientServiceTests.cs | 94 +- .../IpcMessageConverterTest.cs | 138 ++- .../IpcObjectJsonSerializerTests.cs | 28 +- .../JsonIpcDirectRoutedProviderTest.cs | 871 ++++++++-------- tests/dotnetCampus.Ipc.Tests/NotifyTest.cs | 151 ++- tests/dotnetCampus.Ipc.Tests/PeerProxyTest.cs | 537 +++++----- .../PeerReConnectorTest.cs | 469 ++++----- .../PeerRegisterProviderTests.cs | 149 ++- .../IpcClientPipeConnectorTest.cs | 155 ++- .../ResponseManagerTests.cs | 267 +++-- tests/dotnetCampus.Ipc.Tests/TaskExtension.cs | 5 +- .../Threading/IpcThreadPoolTests.cs | 47 +- .../PeerMessageArgsExtensionTest.cs | 318 +++--- .../Utils/IO/AsyncBinaryReaderTests.cs | 73 +- .../dotnetCampus.Ipc.Tests.csproj | 1 - 20 files changed, 2045 insertions(+), 2252 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index cecc3679..cca186de 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -16,12 +16,11 @@ - + - - - + + diff --git a/tests/dotnetCampus.Ipc.Analyzers.Tests/dotnetCampus.Ipc.Analyzers.Tests.csproj b/tests/dotnetCampus.Ipc.Analyzers.Tests/dotnetCampus.Ipc.Analyzers.Tests.csproj index ceb8701c..547d605a 100644 --- a/tests/dotnetCampus.Ipc.Analyzers.Tests/dotnetCampus.Ipc.Analyzers.Tests.csproj +++ b/tests/dotnetCampus.Ipc.Analyzers.Tests/dotnetCampus.Ipc.Analyzers.Tests.csproj @@ -21,7 +21,6 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - diff --git a/tests/dotnetCampus.Ipc.Tests/AckManagerTest.cs b/tests/dotnetCampus.Ipc.Tests/AckManagerTest.cs index 0c4860f3..fdc82649 100644 --- a/tests/dotnetCampus.Ipc.Tests/AckManagerTest.cs +++ b/tests/dotnetCampus.Ipc.Tests/AckManagerTest.cs @@ -3,7 +3,6 @@ using System.IO; using System.Threading.Tasks; using Microsoft.VisualStudio.TestTools.UnitTesting; -using MSTest.Extensions.Contracts; namespace dotnetCampus.Ipc.PipeCore { diff --git a/tests/dotnetCampus.Ipc.Tests/CompilerServices/GeneratedProxies/IpcObjectTests.cs b/tests/dotnetCampus.Ipc.Tests/CompilerServices/GeneratedProxies/IpcObjectTests.cs index c4e71cc5..8fd0c0b1 100644 --- a/tests/dotnetCampus.Ipc.Tests/CompilerServices/GeneratedProxies/IpcObjectTests.cs +++ b/tests/dotnetCampus.Ipc.Tests/CompilerServices/GeneratedProxies/IpcObjectTests.cs @@ -1,15 +1,7 @@ #nullable enable -using System; using System.Collections; -using System.Collections.Generic; using System.Diagnostics; using System.Reflection; -using System.Runtime.Versioning; -using System.Threading; -using System.Threading.Tasks; -using System.Xml.Linq; - -using dotnetCampus.Ipc.CompilerServices.Attributes; using dotnetCampus.Ipc.CompilerServices.GeneratedProxies; using dotnetCampus.Ipc.Exceptions; using dotnetCampus.Ipc.FakeTests.FakeApis; @@ -19,585 +11,580 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; -using MSTest.Extensions.AssertExtensions; -using MSTest.Extensions.Contracts; +namespace dotnetCampus.Ipc.Tests.CompilerServices.GeneratedProxies; -namespace dotnetCampus.Ipc.Tests.CompilerServices.GeneratedProxies +[TestClass] +public class IpcObjectTests { - [TestClass] - public class IpcObjectTests + [TestMethod("IPC 代理生成:可空字符串属性")] + public async Task IpcPropertyTests1() { - [ContractTestCase] - public void IpcPropertyTests() - { - "IPC 代理生成:可空字符串属性".Test(async () => - { - // 准备。 - var (peer, proxy) = await CreateIpcPairAsync(nameof(FakeIpcObject.NullableStringProperty)); + // 准备。 + var (peer, proxy) = await CreateIpcPairAsync(nameof(FakeIpcObject.NullableStringProperty)); - // 安放。 - var result = proxy.NullableStringProperty; - - // 植物。 - Assert.AreEqual("Title", result); - }); + // 安放。 + var result = proxy.NullableStringProperty; - "IPC 代理生成:非可空字符串属性".Test(async () => - { - // 准备。 - var (peer, proxy) = await CreateIpcPairAsync(nameof(FakeIpcObject.NonNullableStringProperty)); + // 植物。 + Assert.AreEqual("Title", result); + } - // 安放。 - var result = proxy.NonNullableStringProperty; + [TestMethod("IPC 代理生成:非可空字符串属性")] + public async Task IpcPropertyTests2() + { + // 准备。 + var (peer, proxy) = await CreateIpcPairAsync(nameof(FakeIpcObject.NonNullableStringProperty)); - // 植物。 - Assert.AreEqual("Description", result); - }); + // 安放。 + var result = proxy.NonNullableStringProperty; - "IPC 代理生成:枚举属性".Test(async () => - { - // 准备。 - var (peer, proxy) = await CreateIpcPairAsync(nameof(FakeIpcObject.EnumProperty)); - - // 安放。 - var result = proxy.EnumProperty; + // 植物。 + Assert.AreEqual("Description", result); + } - // 植物。 - Assert.AreEqual(BindingFlags.Public, result); - }); + [TestMethod("IPC 代理生成:枚举属性")] + public async Task IpcPropertyTests3() + { + // 准备。 + var (peer, proxy) = await CreateIpcPairAsync(nameof(FakeIpcObject.EnumProperty)); - "IPC 代理生成:IPC 只读属性".Test(async () => - { - // 准备。 - var instance = new FakeIpcObject(); - var (peer, proxy) = await CreateIpcPairAsync(nameof(FakeIpcObject.IpcReadonlyProperty), instance); + // 安放。 + var result = proxy.EnumProperty; - // 安放。 - var result1 = proxy.IpcReadonlyProperty; - instance.SetIpcReadonlyProperty(false); - var result2 = proxy.IpcReadonlyProperty; + // 植物。 + Assert.AreEqual(BindingFlags.Public, result); + } - // 植物。 - Assert.AreEqual(true, result1); - Assert.AreEqual(true, result2); - }); + [TestMethod("IPC 代理生成:IPC 只读属性")] + public async Task IpcPropertyTests4() + { + // 准备。 + var instance = new FakeIpcObject(); + var (peer, proxy) = await CreateIpcPairAsync(nameof(FakeIpcObject.IpcReadonlyProperty), instance); + + // 安放。 + var result1 = proxy.IpcReadonlyProperty; + instance.SetIpcReadonlyProperty(false); + var result2 = proxy.IpcReadonlyProperty; + + // 植物。 + Assert.AreEqual(true, result1); + Assert.AreEqual(true, result2); + } - "IPC 代理生成:没有原生序列化的属性(以指针属性为例)".Test(async () => - { - // 准备。 - var (peer, proxy) = await CreateIpcPairAsync(nameof(FakeIpcObject.IntPtrProperty)); + [TestMethod("IPC 代理生成:没有原生序列化的属性(以指针属性为例)")] + public async Task IpcPropertyTests5() + { + // 准备。 + var (peer, proxy) = await CreateIpcPairAsync(nameof(FakeIpcObject.IntPtrProperty)); - // 安放。 - var result = proxy.IntPtrProperty; + // 安放。 + var result = proxy.IntPtrProperty; - // 植物。 - Assert.AreEqual(new IntPtr(1), result); - }); - } + // 植物。 + Assert.AreEqual(new IntPtr(1), result); + } - [ContractTestCase] - public void IpcMethodsTests() - { - "IPC 代理生成:要等待完成的 void 方法".Test(async () => - { - // 准备。 - var (peer, proxy) = await CreateIpcPairAsync(nameof(FakeIpcObject.WaitsVoidMethod)); + [TestMethod("IPC 代理生成:要等待完成的 void 方法")] + public async Task IpcMethodsTests1() + { + // 准备。 + var (peer, proxy) = await CreateIpcPairAsync(nameof(FakeIpcObject.WaitsVoidMethod)); - // 安放。 - proxy.WaitsVoidMethod(); - var result = proxy.EnumProperty; + // 安放。 + proxy.WaitsVoidMethod(); + var result = proxy.EnumProperty; - // 植物。 - Assert.AreEqual(BindingFlags.Public | BindingFlags.Instance, result); - }); + // 植物。 + Assert.AreEqual(BindingFlags.Public | BindingFlags.Instance, result); + } - "IPC 代理生成:不等待完成的 void 方法".Test(async () => - { - // 准备。 - var (peer, proxy) = await CreateIpcPairAsync(nameof(FakeIpcObject.NonWaitsVoidMethod)); + [TestMethod("IPC 代理生成:不等待完成的 void 方法")] + public async Task IpcMethodsTests2() + { + // 准备。 + var (peer, proxy) = await CreateIpcPairAsync(nameof(FakeIpcObject.NonWaitsVoidMethod)); - // 安放。 - proxy.NonWaitsVoidMethod(); - var result = proxy.EnumProperty; + // 安放。 + proxy.NonWaitsVoidMethod(); + var result = proxy.EnumProperty; - // 植物。 - Assert.AreEqual(BindingFlags.Public, result); - }); + // 植物。 + Assert.AreEqual(BindingFlags.Public, result); + } - "IPC 代理生成:会 IPC 超时的方法".Test(async () => - { - // 准备。 - var (peer, proxy) = await CreateIpcPairAsync(nameof(FakeIpcObject.MethodThatHasTimeout)); + [TestMethod("IPC 代理生成:会 IPC 超时的方法")] + public async Task IpcMethodsTests3() + { + // 准备。 + var (peer, proxy) = await CreateIpcPairAsync(nameof(FakeIpcObject.MethodThatHasTimeout)); - // 安放植物。 - await Assert.ThrowsExceptionAsync(async () => - { - await proxy.MethodThatHasTimeout(); - }); - }); + // 安放植物。 + await Assert.ThrowsExceptionAsync(async () => + { + await proxy.MethodThatHasTimeout(); + }); + } - "IPC 代理生成:返回默认值的方法".Test(async () => - { - // 准备。 - var (peer, proxy) = await CreateIpcPairAsync(nameof(FakeIpcObject.MethodThatHasDefaultReturn)); + [TestMethod("IPC 代理生成:返回默认值的方法")] + public async Task IpcMethodsTests4() + { + // 准备。 + var (peer, proxy) = await CreateIpcPairAsync(nameof(FakeIpcObject.MethodThatHasDefaultReturn)); - // 安放。 - var result = await proxy.MethodThatHasDefaultReturn(); + // 安放。 + var result = await proxy.MethodThatHasDefaultReturn(); - // 植物。 - Assert.AreEqual("default1", result); - }); + // 植物。 + Assert.AreEqual("default1", result); + } - "IPC 代理生成:返回默认表达式默认值的方法".Test(async () => - { - // 准备。 - var (peer, proxy) = await CreateIpcPairAsync(nameof(FakeIpcObject.MethodThatHasObjectWithObjectDefaultReturn)); + [TestMethod("IPC 代理生成:返回默认表达式默认值的方法")] + public async Task IpcMethodsTests5() + { + // 准备。 + var (peer, proxy) = await CreateIpcPairAsync(nameof(FakeIpcObject.MethodThatHasObjectWithObjectDefaultReturn)); - // 安放。 - var result = await proxy.MethodThatHasObjectWithObjectDefaultReturn(); + // 安放。 + var result = await proxy.MethodThatHasObjectWithObjectDefaultReturn(); - // 植物。 - Assert.AreEqual(null, result); - }); + // 植物。 + Assert.AreEqual(null, result); + } - "IPC 代理生成:返回字符串表达式默认值的方法".Test(async () => - { - // 准备。 - var (peer, proxy) = await CreateIpcPairAsync(nameof(FakeIpcObject.MethodThatHasObjectWithStringDefaultReturn)); + [TestMethod("IPC 代理生成:返回字符串表达式默认值的方法")] + public async Task IpcMethodsTests6() + { + // 准备。 + var (peer, proxy) = await CreateIpcPairAsync(nameof(FakeIpcObject.MethodThatHasObjectWithStringDefaultReturn)); - // 安放。 - var result = await proxy.MethodThatHasObjectWithStringDefaultReturn(); + // 安放。 + var result = await proxy.MethodThatHasObjectWithStringDefaultReturn(); - // 植物。 - Assert.AreEqual("default1", result); - }); + // 植物。 + Assert.AreEqual("default1", result); + } - "IPC 代理生成:返回大写字符串表达式默认值的方法".Test(async () => - { - // 准备。 - var (peer, proxy) = await CreateIpcPairAsync(nameof(FakeIpcObject.MethodThatHasStringDefaultReturn)); + [TestMethod("IPC 代理生成:返回大写字符串表达式默认值的方法")] + public async Task IpcMethodsTests7() + { + // 准备。 + var (peer, proxy) = await CreateIpcPairAsync(nameof(FakeIpcObject.MethodThatHasStringDefaultReturn)); - // 安放。 - var result = await proxy.MethodThatHasStringDefaultReturn(); + // 安放。 + var result = await proxy.MethodThatHasStringDefaultReturn(); - // 植物。 - Assert.AreEqual("default1", result); - }); + // 植物。 + Assert.AreEqual("default1", result); + } - "IPC 代理生成:返回自定义表达式默认值的方法".Test(async () => - { - // 准备。 - var (peer, proxy) = await CreateIpcPairAsync(nameof(FakeIpcObject.MethodThatHasCustomDefaultReturn)); + [TestMethod("IPC 代理生成:返回自定义表达式默认值的方法")] + public async Task IpcMethodsTests8() + { + // 准备。 + var (peer, proxy) = await CreateIpcPairAsync(nameof(FakeIpcObject.MethodThatHasCustomDefaultReturn)); - // 安放。 - var result = await proxy.MethodThatHasCustomDefaultReturn(); + // 安放。 + var result = await proxy.MethodThatHasCustomDefaultReturn(); - // 植物。 - Assert.AreEqual(new IntPtr(1), result); - }); - } + // 植物。 + Assert.AreEqual(new IntPtr(1), result); + } - [ContractTestCase] - public void IpcParametersAndReturnsTests() - { - "IPC 代理生成:枚举参数".Test(async () => - { - // 准备。 - var (peer, proxy) = await CreateIpcPairAsync(nameof(FakeIpcObject.MethodWithStructParameters)); + [TestMethod("IPC 代理生成:枚举参数")] + public async Task IpcParametersAndReturnsTests1() + { + // 准备。 + var (peer, proxy) = await CreateIpcPairAsync(nameof(FakeIpcObject.MethodWithStructParameters)); - // 安放植物。 - proxy.MethodWithStructParameters(BindingFlags.Public); - }); + // 安放植物。 + proxy.MethodWithStructParameters(BindingFlags.Public); + } - "IPC 代理生成:布尔返回值".Test(async () => - { - // 准备。 - var (peer, proxy) = await CreateIpcPairAsync(nameof(FakeIpcObject.MethodWithStructReturn)); + [TestMethod("IPC 代理生成:布尔返回值")] + public async Task IpcParametersAndReturnsTests2() + { + // 准备。 + var (peer, proxy) = await CreateIpcPairAsync(nameof(FakeIpcObject.MethodWithStructReturn)); - // 安放。 - var result = proxy.MethodWithStructReturn(); + // 安放。 + var result = proxy.MethodWithStructReturn(); - // 植物。 - Assert.AreEqual(true, result); - }); + // 植物。 + Assert.AreEqual(true, result); + } - "IPC 代理生成:同数量的参数组成的重载方法组。".Test(async () => - { - // 准备。 - var (peer, proxy) = await CreateIpcPairAsync(nameof(FakeIpcObject.MethodWithSameParameterCountOverloading)); + [TestMethod("IPC 代理生成:同数量的参数组成的重载方法组。")] + public async Task IpcParametersAndReturnsTests3() + { + // 准备。 + var (peer, proxy) = await CreateIpcPairAsync(nameof(FakeIpcObject.MethodWithSameParameterCountOverloading)); - // 安放。 - var int32Result = proxy.MethodWithSameParameterCountOverloading(1, 2); - var int64Result = proxy.MethodWithSameParameterCountOverloading(1L, 2L); + // 安放。 + var int32Result = proxy.MethodWithSameParameterCountOverloading(1, 2); + var int64Result = proxy.MethodWithSameParameterCountOverloading(1L, 2L); - // 植物。 - Assert.AreEqual(3, int32Result); - Assert.AreEqual(2L, int64Result); - }); + // 植物。 + Assert.AreEqual(3, int32Result); + Assert.AreEqual(2L, int64Result); + } - "IPC 代理生成:异步返回值".Test(async () => - { - // 准备。 - var (peer, proxy) = await CreateIpcPairAsync(nameof(FakeIpcObject.AsyncMethod)); + [TestMethod("IPC 代理生成:异步返回值")] + public async Task IpcParametersAndReturnsTests4() + { + // 准备。 + var (peer, proxy) = await CreateIpcPairAsync(nameof(FakeIpcObject.AsyncMethod)); - // 安放植物。 - await proxy.AsyncMethod(); - }); + // 安放植物。 + await proxy.AsyncMethod(); + } - "IPC 代理生成:多参数和异步结构体返回值。".Test(async () => - { - // 准备。 - var (peer, proxy) = await CreateIpcPairAsync(nameof(FakeIpcObject.AsyncMethodWithStructParametersAndStructReturn)); + [TestMethod("IPC 代理生成:多参数和异步结构体返回值。")] + public async Task IpcParametersAndReturnsTests5() + { + // 准备。 + var (peer, proxy) = await CreateIpcPairAsync(nameof(FakeIpcObject.AsyncMethodWithStructParametersAndStructReturn)); - // 安放。 - var result = await proxy.AsyncMethodWithStructParametersAndStructReturn(1, 2, 3, 4); + // 安放。 + var result = await proxy.AsyncMethodWithStructParametersAndStructReturn(1, 2, 3, 4); - // 植物。 - Assert.AreEqual(new ValueTuple(1, 2, 3, 4), result); - }); + // 植物。 + Assert.AreEqual(new ValueTuple(1, 2, 3, 4), result); + } - "IPC 代理生成:复杂参数和异步复杂返回值".Test(async () => - { - // 准备。 - var (peer, proxy) = await CreateIpcPairAsync(nameof(FakeIpcObject.AsyncMethodWithComplexParametersAndComplexReturn)); + [TestMethod("IPC 代理生成:复杂参数和异步复杂返回值")] + public async Task IpcParametersAndReturnsTests6() + { + // 准备。 + var (peer, proxy) = await CreateIpcPairAsync(nameof(FakeIpcObject.AsyncMethodWithComplexParametersAndComplexReturn)); - // 安放。 - var result = await proxy.AsyncMethodWithComplexParametersAndComplexReturn(new FakeIpcObjectSubModelA(1, 2, 3, 4)); + // 安放。 + var result = await proxy.AsyncMethodWithComplexParametersAndComplexReturn(new FakeIpcObjectSubModelA(1, 2, 3, 4)); - // 植物。 - Assert.AreEqual((double) 1, result.A); - Assert.AreEqual((uint) 2, result.B); - Assert.AreEqual((int) 3, result.C); - Assert.AreEqual((byte) 4, result.D); - }); + // 植物。 + Assert.AreEqual((double) 1, result.A); + Assert.AreEqual((uint) 2, result.B); + Assert.AreEqual((int) 3, result.C); + Assert.AreEqual((byte) 4, result.D); + } - "IPC 代理生成:字符串参数和异步字符串返回值。".Test(async () => - { - // 准备。 - var (peer, proxy) = await CreateIpcPairAsync(nameof(FakeIpcObject.AsyncMethodWithPrimaryParametersAndPrimaryReturn)); + [TestMethod("IPC 代理生成:字符串参数和异步字符串返回值。")] + public async Task IpcParametersAndReturnsTests7() + { + // 准备。 + var (peer, proxy) = await CreateIpcPairAsync(nameof(FakeIpcObject.AsyncMethodWithPrimaryParametersAndPrimaryReturn)); - // 安放。 - var result = await proxy.AsyncMethodWithPrimaryParametersAndPrimaryReturn("Test"); + // 安放。 + var result = await proxy.AsyncMethodWithPrimaryParametersAndPrimaryReturn("Test"); - // 植物。 - Assert.AreEqual("Test", result); - }); + // 植物。 + Assert.AreEqual("Test", result); + } - "IPC 代理生成:IPC 参数和异步 IPC 返回值".Test(async () => - { - // 准备。 - var proxySideObject = new FakeNestedIpcArgumentOrReturn("test on proxy side"); - var jointSideObject = new FakeNestedIpcArgumentOrReturn("test on joint side"); - var (aProvider, _, peer, proxy) = await CreateIpcPairWithProvidersAsync(nameof(FakeIpcObject.AsyncMethodWithIpcPublicObjectParametersAndIpcPublicObjectReturn), new FakeIpcObject(jointSideObject)); + [TestMethod("IPC 代理生成:IPC 参数和异步 IPC 返回值")] + public async Task IpcParametersAndReturnsTests8() + { + // 准备。 + var proxySideObject = new FakeNestedIpcArgumentOrReturn("test on proxy side"); + var jointSideObject = new FakeNestedIpcArgumentOrReturn("test on joint side"); + var (aProvider, _, peer, proxy) = + await CreateIpcPairWithProvidersAsync(nameof(FakeIpcObject.AsyncMethodWithIpcPublicObjectParametersAndIpcPublicObjectReturn), + new FakeIpcObject(jointSideObject)); + + // 安放。 + var result = await proxy.AsyncMethodWithIpcPublicObjectParametersAndIpcPublicObjectReturn(proxySideObject, "change on joint side"); + + // 植物。 + // 代理端对象的值被对接端修改。 + Assert.AreEqual("change on joint side", proxySideObject.Value); + // 对接端的值保持原样。 + Assert.AreEqual("test on joint side", jointSideObject.Value); + Assert.AreEqual("test on joint side", result.Value); + + // 安放。 + result.Value = "test changed from proxy side"; + + // 植物。 + // 代理端对象的值保持原样。 + Assert.AreEqual("change on joint side", proxySideObject.Value); + // 对接端的值被代理端修改。 + Assert.AreEqual("test changed from proxy side", jointSideObject.Value); + Assert.AreEqual("test changed from proxy side", result.Value); + } - // 安放。 - var result = await proxy.AsyncMethodWithIpcPublicObjectParametersAndIpcPublicObjectReturn(proxySideObject, "change on joint side"); + [TestMethod("IPC 代理生成:不同程序集中的同名 IPC 参数和异步 IPC 返回值")] + public async Task DifferentAssembliesIpcParametersAndReturnsTests() + { + // 准备。 + var remoteExecutablePath = Path.Combine( + Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!, + "..", "..", + @"dotnetCampus.Ipc.FakeTests", + Assembly.GetExecutingAssembly().GetCustomAttribute()!.Configuration.ToLowerInvariant(), + "dotnetCampus.Ipc.FakeTests.dll"); + + if (!File.Exists(remoteExecutablePath)) + { + throw new FileNotFoundException($"在执行真正跨进程 IPC 通信时,目标程序集未找到,请确认代码中编写的路径是否已更新到最新路径。路径为:{remoteExecutablePath}"); + } - // 植物。 - // 代理端对象的值被对接端修改。 - Assert.AreEqual("change on joint side", proxySideObject.Value); - // 对接端的值保持原样。 - Assert.AreEqual("test on joint side", jointSideObject.Value); - Assert.AreEqual("test on joint side", result.Value); + var process = Process.Start(new ProcessStartInfo("dotnet") { UseShellExecute = true, ArgumentList = { remoteExecutablePath, }, })!; + try + { + var ipcPeerName = $"IpcObjectTests.IpcTests.RemoteFakeIpcObject"; + var ipcProvider = new IpcProvider(ipcPeerName + ".Local"); + ipcProvider.StartServer(); + var ipcPeer = await ipcProvider.GetAndConnectToPeerAsync(ipcPeerName); + var remoteObject = ipcProvider.CreateIpcProxy(ipcPeer); + var ipcArgument = new RemoteIpcArgument("argument"); - // 安放。 - result.Value = "test changed from proxy side"; + // 安放。 + var ipcReturn = await remoteObject.MethodWithIpcParameterAsync(ipcArgument, "changed ipc argument"); + try + { // 植物。 - // 代理端对象的值保持原样。 - Assert.AreEqual("change on joint side", proxySideObject.Value); - // 对接端的值被代理端修改。 - Assert.AreEqual("test changed from proxy side", jointSideObject.Value); - Assert.AreEqual("test changed from proxy side", result.Value); - }); + // 本地值被远端修改。 + Assert.AreEqual("changed ipc argument", ipcArgument.Value); + // 远端的值保持默认。 + Assert.AreEqual("private", ipcReturn.Value); + } + finally + { + // 清理。 + await remoteObject.ShutdownAsync(); + } } - - [ContractTestCase] - public void DifferentAssembliesIpcParametersAndReturnsTests() + finally { - "IPC 代理生成:不同程序集中的同名 IPC 参数和异步 IPC 返回值".Test(async () => + try + { + // 清理。 + process.Kill(); + } + catch (Exception) { - // 准备。 - var remoteExecutablePath = Path.Combine( - Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!, - "..", "..", "..", "..", - @"dotnetCampus.Ipc.FakeTests\bin", - Assembly.GetExecutingAssembly().GetCustomAttribute()!.Configuration, - "net6.0", - "dotnetCampus.Ipc.FakeTests.dll"); - - if (!File.Exists(remoteExecutablePath)) - { - throw new FileNotFoundException($"在执行真正跨进程 IPC 通信时,目标程序集未找到,请确认代码中编写的路径是否已更新到最新路径。路径为:{remoteExecutablePath}"); - } - - var process = Process.Start(new ProcessStartInfo("dotnet") - { - UseShellExecute = true, - ArgumentList = - { - remoteExecutablePath, - }, - })!; - try - { - var ipcPeerName = $"IpcObjectTests.IpcTests.RemoteFakeIpcObject"; - var ipcProvider = new IpcProvider(ipcPeerName + ".Local"); - ipcProvider.StartServer(); - var ipcPeer = await ipcProvider.GetAndConnectToPeerAsync(ipcPeerName); - var remoteObject = ipcProvider.CreateIpcProxy(ipcPeer); - var ipcArgument = new RemoteIpcArgument("argument"); - - // 安放。 - var ipcReturn = await remoteObject.MethodWithIpcParameterAsync(ipcArgument, "changed ipc argument"); - - try - { - // 植物。 - // 本地值被远端修改。 - Assert.AreEqual("changed ipc argument", ipcArgument.Value); - // 远端的值保持默认。 - Assert.AreEqual("private", ipcReturn.Value); - } - finally - { - // 清理。 - await remoteObject.ShutdownAsync(); - } - } - finally - { - try - { - // 清理。 - process.Kill(); - } - catch (Exception) - { - // ignored - } - } - }); + // ignored + } } + } - [ContractTestCase] - public void IpcCollectionTests() - { - "IPC 代理生成:集合(列表)属性".Test(async () => - { - // 准备。 - var (peer, proxy) = await CreateIpcPairAsync(nameof(FakeIpcObject.ListProperty)); + [TestMethod("IPC 代理生成:集合(列表)属性")] + public async Task IpcCollectionTests1() + { + // 准备。 + var (peer, proxy) = await CreateIpcPairAsync(nameof(FakeIpcObject.ListProperty)); - // 安放。 - var result = proxy.ListProperty; + // 安放。 + var result = proxy.ListProperty; - // 植物。 - CollectionAssert.AreEqual(new string[] { "List1", "List2" }, result); - }); + // 植物。 + CollectionAssert.AreEqual(new string[] { "List1", "List2" }, result); + } - "IPC 代理生成:集合(接口)属性".Test(async () => - { - // 准备。 - var (peer, proxy) = await CreateIpcPairAsync(nameof(FakeIpcObject.CollectionProperty)); + [TestMethod("IPC 代理生成:集合(接口)属性")] + public async Task IpcCollectionTests2() + { + // 准备。 + var (peer, proxy) = await CreateIpcPairAsync(nameof(FakeIpcObject.CollectionProperty)); - // 安放。 - var result = proxy.CollectionProperty; + // 安放。 + var result = proxy.CollectionProperty; - // 植物。 - CollectionAssert.AreEqual(new string[] { "Collection1", "Collection2" }, (ICollection?) result); - }); + // 植物。 + CollectionAssert.AreEqual(new string[] { "Collection1", "Collection2" }, (ICollection?) result); + } - "IPC 代理生成:集合(数组)属性".Test(async () => - { - // 准备。 - var (peer, proxy) = await CreateIpcPairAsync(nameof(FakeIpcObject.ArrayProperty)); + [TestMethod("IPC 代理生成:集合(数组)属性")] + public async Task IpcCollectionTests3() + { + // 准备。 + var (peer, proxy) = await CreateIpcPairAsync(nameof(FakeIpcObject.ArrayProperty)); - // 安放。 - var result = proxy.ArrayProperty; + // 安放。 + var result = proxy.ArrayProperty; - // 植物。 - CollectionAssert.AreEqual(new string[] { "Array1", "Array2" }, result); - }); + // 植物。 + CollectionAssert.AreEqual(new string[] { "Array1", "Array2" }, result); + } - "IPC 代理生成:集合(列表)异步方法".Test(async () => - { - // 准备。 - var (peer, proxy) = await CreateIpcPairAsync(nameof(FakeIpcObject.MethodWithListParametersAndListReturn)); + [TestMethod("IPC 代理生成:集合(列表)异步方法")] + public async Task IpcCollectionTests4() + { + // 准备。 + var (peer, proxy) = await CreateIpcPairAsync(nameof(FakeIpcObject.MethodWithListParametersAndListReturn)); - // 安放。 - var result = await proxy.MethodWithListParametersAndListReturn( - new List { "a", "b" }, - new List { "c", "d" }); + // 安放。 + var result = await proxy.MethodWithListParametersAndListReturn( + new List { "a", "b" }, + new List { "c", "d" }); - // 植物。 - CollectionAssert.AreEqual(new string[] { "a", "b", "c", "d" }, result); - }); + // 植物。 + CollectionAssert.AreEqual(new string[] { "a", "b", "c", "d" }, result); + } - "IPC 代理生成:集合(接口)异步方法".Test(async () => - { - // 准备。 - var (peer, proxy) = await CreateIpcPairAsync(nameof(FakeIpcObject.MethodWithCollectionParametersAndCollectionReturn)); + [TestMethod("IPC 代理生成:集合(接口)异步方法")] + public async Task IpcCollectionTests5() + { + // 准备。 + var (peer, proxy) = await CreateIpcPairAsync(nameof(FakeIpcObject.MethodWithCollectionParametersAndCollectionReturn)); - // 安放。 - var result = await proxy.MethodWithCollectionParametersAndCollectionReturn( - new List { "a", "b" }, - new List { "c", "d" }); + // 安放。 + var result = await proxy.MethodWithCollectionParametersAndCollectionReturn( + new List { "a", "b" }, + new List { "c", "d" }); - // 植物。 - CollectionAssert.AreEqual(new string[] { "a", "b", "c", "d" }, (ICollection) result); - }); + // 植物。 + CollectionAssert.AreEqual(new string[] { "a", "b", "c", "d" }, (ICollection) result); + } - "IPC 代理生成:集合(数组)异步方法".Test(async () => - { - // 准备。 - var (peer, proxy) = await CreateIpcPairAsync(nameof(FakeIpcObject.MethodWithArrayParametersAndArrayReturn)); + [TestMethod("IPC 代理生成:集合(数组)异步方法")] + public async Task IpcCollectionTests6() + { + // 准备。 + var (peer, proxy) = await CreateIpcPairAsync(nameof(FakeIpcObject.MethodWithArrayParametersAndArrayReturn)); - // 安放。 - var result = await proxy.MethodWithArrayParametersAndArrayReturn( - new string[] { "a", "b" }, - new string[] { "c", "d" }); + // 安放。 + var result = await proxy.MethodWithArrayParametersAndArrayReturn( + new string[] { "a", "b" }, + new string[] { "c", "d" }); - // 植物。 - CollectionAssert.AreEqual(new string[] { "a", "b", "c", "d" }, result); - }); - } + // 植物。 + CollectionAssert.AreEqual(new string[] { "a", "b", "c", "d" }, result); + } - [ContractTestCase] - public void IpcMethodExceptionTests() + [TestMethod("IPC 代理生成:忽略异常的方法")] + public async Task IpcMethodExceptionTests1() + { + // 准备。 + var name = nameof(FakeIpcObject.MethodThatIgnoresIpcException); + var aName = $"IpcObjectTests.IpcTests.{name}.A"; + var bName = $"IpcObjectTests.IpcTests.{name}.B"; + var aProvider = new IpcProvider(aName); + var bProvider = new IpcProvider(bName); + aProvider.StartServer(); + bProvider.StartServer(); + var aJoint = aProvider.CreateIpcJoint(new FakeIpcObject()); + var aPeer = await bProvider.GetAndConnectToPeerAsync(aName); + var bProxy = bProvider.CreateIpcProxy(aPeer); + + // 安放植物。 + // 没有发生异常。 + var task = bProxy.MethodThatIgnoresIpcException(); + await Task.Run(async () => { - "IPC 代理生成:忽略异常的方法".Test(async () => - { - // 准备。 - var name = nameof(FakeIpcObject.MethodThatIgnoresIpcException); - var aName = $"IpcObjectTests.IpcTests.{name}.A"; - var bName = $"IpcObjectTests.IpcTests.{name}.B"; - var aProvider = new IpcProvider(aName); - var bProvider = new IpcProvider(bName); - aProvider.StartServer(); - bProvider.StartServer(); - var aJoint = aProvider.CreateIpcJoint(new FakeIpcObject()); - var aPeer = await bProvider.GetAndConnectToPeerAsync(aName); - var bProxy = bProvider.CreateIpcProxy(aPeer); - - // 安放植物。 - // 没有发生异常。 - var task = bProxy.MethodThatIgnoresIpcException(); - await Task.Run(async () => - { - await Task.Delay(20); - aProvider.Dispose(); - }); - await task; - }); - - "IPC 代理生成:没有忽略异常的方法".Test(async () => - { - // 准备。 - var name = nameof(FakeIpcObject.MethodThatThrowsIpcException); - var aName = $"IpcObjectTests.IpcTests.{name}.A"; - var bName = $"IpcObjectTests.IpcTests.{name}.B"; - var aProvider = new IpcProvider(aName); - var bProvider = new IpcProvider(bName); - aProvider.StartServer(); - bProvider.StartServer(); - var aJoint = aProvider.CreateIpcJoint(new FakeIpcObject()); - var aPeer = await bProvider.GetAndConnectToPeerAsync(aName); - var bProxy = bProvider.CreateIpcProxy(aPeer); - - // 安放。 - var task = bProxy.MethodThatThrowsIpcException(); - await Task.Run(async () => - { - await Task.Delay(20); - aProvider.Dispose(); - }); + await Task.Delay(20); + aProvider.Dispose(); + }); + await task; + } - // 植物。 - try - { - await task; - } - catch (IpcRemoteException e) - { - if (e.InnerException is IpcPeerConnectionBrokenException) - { - // 期望的异常是外层是 IpcRemoteException 异常 - // 里层是 IpcPeerConnectionBrokenException 异常 - // 外层的异常将包括发送的消息的调试使用的 Tag 信息 - return; - } - } - - Assert.Fail($"期望的异常没有被抛出"); - }); - - "IPC 代理生成:成员上没有标记忽略异常,但是类型上标记了,也要忽略异常".Test(async () => - { - // 准备。 - var name = $"{nameof(FakeIpcObjectWithTypeAttributes)}.{nameof(FakeIpcObject.MethodThatThrowsIpcException)}"; - var aName = $"IpcObjectTests.IpcTests.{name}.A"; - var bName = $"IpcObjectTests.IpcTests.{name}.B"; - var aProvider = new IpcProvider(aName); - var bProvider = new IpcProvider(bName); - aProvider.StartServer(); - bProvider.StartServer(); - var aJoint = aProvider.CreateIpcJoint(new FakeIpcObjectWithTypeAttributes()); - var aPeer = await bProvider.GetAndConnectToPeerAsync(aName); - var bProxy = bProvider.CreateIpcProxy(aPeer, new IpcProxyConfigs - { - IgnoresIpcException = true, - }); - - // 安放植物。 - // 没有发生异常。 - var task = bProxy.MethodThatThrowsIpcException(); - await Task.Run(async () => - { - await Task.Delay(20); - aProvider.Dispose(); - }); - await task; - }); - } + [TestMethod("IPC 代理生成:没有忽略异常的方法")] + public async Task IpcMethodExceptionTests2() + { + // 准备。 + var name = nameof(FakeIpcObject.MethodThatThrowsIpcException); + var aName = $"IpcObjectTests.IpcTests.{name}.A"; + var bName = $"IpcObjectTests.IpcTests.{name}.B"; + var aProvider = new IpcProvider(aName); + var bProvider = new IpcProvider(bName); + aProvider.StartServer(); + bProvider.StartServer(); + var aJoint = aProvider.CreateIpcJoint(new FakeIpcObject()); + var aPeer = await bProvider.GetAndConnectToPeerAsync(aName); + var bProxy = bProvider.CreateIpcProxy(aPeer); + + // 安放。 + var task = bProxy.MethodThatThrowsIpcException(); + await Task.Run(async () => + { + await Task.Delay(20); + aProvider.Dispose(); + }); - private async Task<(IPeerProxy peer, IFakeIpcObject proxy)> CreateIpcPairAsync(string name, FakeIpcObject? instance = null) + // 植物。 + try { - var aName = $"IpcObjectTests.IpcTests.{name}.A"; - var bName = $"IpcObjectTests.IpcTests.{name}.B"; - var aProvider = new IpcProvider(aName); - var bProvider = new IpcProvider(bName); - aProvider.StartServer(); - bProvider.StartServer(); - var aJoint = aProvider.CreateIpcJoint(instance ?? new FakeIpcObject()); - var aPeer = await bProvider.GetAndConnectToPeerAsync(aName); - var bProxy = bProvider.CreateIpcProxy(aPeer); - // 这里的延迟是为了暂时缓解死锁 bug @lindexi - // 这个问题其实是因为 IpcObject 这一套可能存在异步转同步等待的问题 - // 问题原因如下: - // 从 GetAndConnectToPeerAsync 返回的时,是消息接受端 DispatchMessage 所在线程调用过来的 - // 如果此线程卡住了,那就意味着不再能够接收到消息 - // 那为什么存在锁的问题?因为如果在接下来一句话是走 IpcObject 框架获取远程对象的属性值类似的代码 - // 将会在获取属性时,进入异步转同步等待,需要等待到什么时候才会继续执行?需要等待消息接受端 DispatchMessage 接收到远程对象返回的消息 - // 然而消息接受端 DispatchMessage 所在线程已经进入异步转同步等待,导致无法接收到消息,进而导致 DispatchMessage 所在线程无法释放 - // 那为什么设计上要让 GetAndConnectToPeerAsync 返回的线程是消息接受端 DispatchMessage 所在线程?原因是在主动发起对 Peer 连接时,也许需要进行一些事件加等处理等,如果在另一个线程,那可能出现在获取到 Peer 的同时也接收到 Peer 发送过来的消息。这会存在由于事件加等处理在另一个线程,没有及时执行,导致丢失消息 - await Task.Delay(100); - return (aPeer, bProxy); + await task; } - - private async Task<(IIpcProvider aProvider, IIpcProvider bProvider, IPeerProxy peer, IFakeIpcObject proxy)> CreateIpcPairWithProvidersAsync(string name, FakeIpcObject? instance = null) + catch (IpcRemoteException e) { - var aName = $"IpcObjectTests.IpcTests.{name}.A"; - var bName = $"IpcObjectTests.IpcTests.{name}.B"; - var aProvider = new IpcProvider(aName); - var bProvider = new IpcProvider(bName); - aProvider.StartServer(); - bProvider.StartServer(); - var aJoint = aProvider.CreateIpcJoint(instance ?? new FakeIpcObject()); - var aPeer = await bProvider.GetAndConnectToPeerAsync(aName); - var bProxy = bProvider.CreateIpcProxy(aPeer); - // 这里的延迟是为了暂时缓解死锁 bug @lindexi - await Task.Delay(100); - return (aProvider, bProvider, aPeer, bProxy); + if (e.InnerException is IpcPeerConnectionBrokenException) + { + // 期望的异常是外层是 IpcRemoteException 异常 + // 里层是 IpcPeerConnectionBrokenException 异常 + // 外层的异常将包括发送的消息的调试使用的 Tag 信息 + return; + } } + + Assert.Fail($"期望的异常没有被抛出"); + } + + [TestMethod("IPC 代理生成:成员上没有标记忽略异常,但是类型上标记了,也要忽略异常")] + public async Task IpcMethodExceptionTests3() + { + // 准备。 + var name = $"{nameof(FakeIpcObjectWithTypeAttributes)}.{nameof(FakeIpcObject.MethodThatThrowsIpcException)}"; + var aName = $"IpcObjectTests.IpcTests.{name}.A"; + var bName = $"IpcObjectTests.IpcTests.{name}.B"; + var aProvider = new IpcProvider(aName); + var bProvider = new IpcProvider(bName); + aProvider.StartServer(); + bProvider.StartServer(); + var aJoint = aProvider.CreateIpcJoint(new FakeIpcObjectWithTypeAttributes()); + var aPeer = await bProvider.GetAndConnectToPeerAsync(aName); + var bProxy = bProvider.CreateIpcProxy(aPeer, new IpcProxyConfigs { IgnoresIpcException = true, }); + + // 安放植物。 + // 没有发生异常。 + var task = bProxy.MethodThatThrowsIpcException(); + await Task.Run(async () => + { + await Task.Delay(20); + aProvider.Dispose(); + }); + await task; + } + + private async Task<(IPeerProxy peer, IFakeIpcObject proxy)> CreateIpcPairAsync(string name, FakeIpcObject? instance = null) + { + var aName = $"IpcObjectTests.IpcTests.{name}.A"; + var bName = $"IpcObjectTests.IpcTests.{name}.B"; + var aProvider = new IpcProvider(aName); + var bProvider = new IpcProvider(bName); + aProvider.StartServer(); + bProvider.StartServer(); + var aJoint = aProvider.CreateIpcJoint(instance ?? new FakeIpcObject()); + var aPeer = await bProvider.GetAndConnectToPeerAsync(aName); + var bProxy = bProvider.CreateIpcProxy(aPeer); + // 这里的延迟是为了暂时缓解死锁 bug @lindexi + // 这个问题其实是因为 IpcObject 这一套可能存在异步转同步等待的问题 + // 问题原因如下: + // 从 GetAndConnectToPeerAsync 返回的时,是消息接受端 DispatchMessage 所在线程调用过来的 + // 如果此线程卡住了,那就意味着不再能够接收到消息 + // 那为什么存在锁的问题?因为如果在接下来一句话是走 IpcObject 框架获取远程对象的属性值类似的代码 + // 将会在获取属性时,进入异步转同步等待,需要等待到什么时候才会继续执行?需要等待消息接受端 DispatchMessage 接收到远程对象返回的消息 + // 然而消息接受端 DispatchMessage 所在线程已经进入异步转同步等待,导致无法接收到消息,进而导致 DispatchMessage 所在线程无法释放 + // 那为什么设计上要让 GetAndConnectToPeerAsync 返回的线程是消息接受端 DispatchMessage 所在线程?原因是在主动发起对 Peer 连接时,也许需要进行一些事件加等处理等,如果在另一个线程,那可能出现在获取到 Peer 的同时也接收到 Peer 发送过来的消息。这会存在由于事件加等处理在另一个线程,没有及时执行,导致丢失消息 + await Task.Delay(100); + return (aPeer, bProxy); + } + + private async Task<(IIpcProvider aProvider, IIpcProvider bProvider, IPeerProxy peer, IFakeIpcObject proxy)> CreateIpcPairWithProvidersAsync(string name, + FakeIpcObject? instance = null) + { + var aName = $"IpcObjectTests.IpcTests.{name}.A"; + var bName = $"IpcObjectTests.IpcTests.{name}.B"; + var aProvider = new IpcProvider(aName); + var bProvider = new IpcProvider(bName); + aProvider.StartServer(); + bProvider.StartServer(); + var aJoint = aProvider.CreateIpcJoint(instance ?? new FakeIpcObject()); + var aPeer = await bProvider.GetAndConnectToPeerAsync(aName); + var bProxy = bProvider.CreateIpcProxy(aPeer); + // 这里的延迟是为了暂时缓解死锁 bug @lindexi + await Task.Delay(100); + return (aProvider, bProvider, aPeer, bProxy); } } diff --git a/tests/dotnetCampus.Ipc.Tests/CompilerServices/GeneratedProxies/NotGeneratedTestOnlyFakeIpcObjectIpcShape.cs b/tests/dotnetCampus.Ipc.Tests/CompilerServices/GeneratedProxies/NotGeneratedTestOnlyFakeIpcObjectIpcShape.cs index ae568282..dfd69119 100644 --- a/tests/dotnetCampus.Ipc.Tests/CompilerServices/GeneratedProxies/NotGeneratedTestOnlyFakeIpcObjectIpcShape.cs +++ b/tests/dotnetCampus.Ipc.Tests/CompilerServices/GeneratedProxies/NotGeneratedTestOnlyFakeIpcObjectIpcShape.cs @@ -1,11 +1,5 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Threading.Tasks; +using System.Reflection; using dotnetCampus.Ipc.CompilerServices.Attributes; -using dotnetCampus.Ipc.CompilerServices.GeneratedProxies; -using dotnetCampus.Ipc.Tests.CompilerServices; using dotnetCampus.Ipc.Tests.CompilerServices.Fake; namespace dotnetCampus.Ipc.Tests.CompilerServices.GeneratedProxies diff --git a/tests/dotnetCampus.Ipc.Tests/IpcClientServiceTests.cs b/tests/dotnetCampus.Ipc.Tests/IpcClientServiceTests.cs index 62ff42ab..53a51c7d 100644 --- a/tests/dotnetCampus.Ipc.Tests/IpcClientServiceTests.cs +++ b/tests/dotnetCampus.Ipc.Tests/IpcClientServiceTests.cs @@ -1,73 +1,65 @@ -using System; -using System.IO; -using System.Threading; -using System.Threading.Tasks; -using dotnetCampus.Ipc.Messages; +using dotnetCampus.Ipc.Messages; using dotnetCampus.Ipc.Pipes; using dotnetCampus.Threading; using Microsoft.VisualStudio.TestTools.UnitTesting; -using MSTest.Extensions.Contracts; namespace dotnetCampus.Ipc.Tests { [TestClass] public class IpcClientServiceTests { - [ContractTestCase] - public void SendWhenDisposed() + [TestMethod("连接断开之后持续发送消息,将会收到 ObjectDisposedException 异常")] + public async Task SendWhenDisposed() { - "连接断开之后持续发送消息,将会收到 ObjectDisposedException 异常".Test(async () => - { - var ipcProviderA = new IpcProvider(); - var ipcProviderB = new IpcProvider(); + var ipcProviderA = new IpcProvider(); + var ipcProviderB = new IpcProvider(); - ipcProviderA.StartServer(); - ipcProviderB.StartServer(); + ipcProviderA.StartServer(); + ipcProviderB.StartServer(); - var peer = await ipcProviderA.GetAndConnectToPeerAsync(ipcProviderB.IpcContext.PipeName); - var n = 100; - var buffer = new byte[1024]; - var autoResetEvent = new AsyncAutoResetEvent(false); - var sendTask = Task.Run(async () => + var peer = await ipcProviderA.GetAndConnectToPeerAsync(ipcProviderB.IpcContext.PipeName); + var n = 100; + var buffer = new byte[1024]; + var autoResetEvent = new AsyncAutoResetEvent(false); + var sendTask = Task.Run(async () => + { + for (int i = 0; i < n; i++) { - for (int i = 0; i < n; i++) - { - await peer.IpcMessageWriter.WriteMessageAsync(new IpcMessage("Test", buffer)); - - if (i == n / 2) - { - // 让另一个线程去释放 ipcProviderB 对象 - autoResetEvent.Set(); - } + await peer.IpcMessageWriter.WriteMessageAsync(new IpcMessage("Test", buffer)); - await Task.Yield(); + if (i == n / 2) + { + // 让另一个线程去释放 ipcProviderB 对象 + autoResetEvent.Set(); } - }); - - var disposeTask = Task.Run(async () => - { - await autoResetEvent.WaitOneAsync(); - ipcProviderB.Dispose(); - }); - try - { - // 等待发送和释放任务完成 - // 预期是一定会在发送任务抛出异常,异常是 ObjectDisposedException 或 IOException 这两个 - await Task.WhenAll(sendTask, disposeTask); - } - catch (Exception e) - { - // 期望抛出异常 - // 在调用一次 WriteMessageAsync 之前,被释放,那么抛出 ObjectDisposedException 异常 - // 在写入过程,被释放,那么写入 PipeStream.WriteCore 抛出 IO 异常 - Assert.AreEqual(true, e is ObjectDisposedException or IOException); - return; + await Task.Yield(); } + }); - // 如果没有抛出异常,那么进入此分支 - Assert.Fail("预期抛出的是 ObjectDisposedException 或 IOException 异常"); + var disposeTask = Task.Run(async () => + { + await autoResetEvent.WaitOneAsync(); + ipcProviderB.Dispose(); }); + + try + { + // 等待发送和释放任务完成 + // 预期是一定会在发送任务抛出异常,异常是 ObjectDisposedException 或 IOException 这两个 + await Task.WhenAll(sendTask, disposeTask); + } + catch (Exception e) + { + // 期望抛出异常 + // 在调用一次 WriteMessageAsync 之前,被释放,那么抛出 ObjectDisposedException 异常 + // 在写入过程,被释放,那么写入 PipeStream.WriteCore 抛出 IO 异常 + Assert.AreEqual(true, e is ObjectDisposedException or IOException); + return; + } + + // 如果没有抛出异常,那么进入此分支 + Assert.Fail("预期抛出的是 ObjectDisposedException 或 IOException 异常"); } } } diff --git a/tests/dotnetCampus.Ipc.Tests/IpcMessageConverterTest.cs b/tests/dotnetCampus.Ipc.Tests/IpcMessageConverterTest.cs index c0a14d67..05f86e8e 100644 --- a/tests/dotnetCampus.Ipc.Tests/IpcMessageConverterTest.cs +++ b/tests/dotnetCampus.Ipc.Tests/IpcMessageConverterTest.cs @@ -1,86 +1,82 @@ -using System.IO; - -using dotnetCampus.Ipc.Context; +using dotnetCampus.Ipc.Context; using dotnetCampus.Ipc.Internals; using dotnetCampus.Ipc.Messages; using dotnetCampus.Ipc.Utils.Buffers; using Microsoft.VisualStudio.TestTools.UnitTesting; -using MSTest.Extensions.Contracts; - namespace dotnetCampus.Ipc.Tests { [TestClass] public class IpcMessageConverterTest { - [ContractTestCase] - public void IpcMessageConverterWriteAsync() + [TestMethod("读取消息头不对的数据,可以返回读取失败")] + public async Task IpcMessageConverterWriteAsync1() + { + using var memoryStream = new MemoryStream(); + + ulong ack = 10; + var buffer = new byte[] { 0x12, 0x12, 0x00 }; + var messageHeader = new byte[] { 0x00, 0x00 }; + var breakMessageHeader = new byte[] { 0x00, 0x01 }; + + var ipcBufferMessageContext = new IpcBufferMessageContext("test", IpcMessageCommandType.Unknown, new IpcMessageBody(buffer)); + + await IpcMessageConverter.WriteAsync(memoryStream, messageHeader, ack, ipcBufferMessageContext, new SharedArrayPool()); + + memoryStream.Position = 0; + var ipcMessageResult = (await IpcMessageConverter.ReadAsync(memoryStream, + breakMessageHeader, new SharedArrayPool())).Result; + var success = ipcMessageResult.Success; + var ipcMessageCommandType = ipcMessageResult.IpcMessageCommandType; + + Assert.AreEqual(false, success); + Assert.AreEqual(IpcMessageCommandType.Unknown, ipcMessageCommandType); + } + + [TestMethod("读取消息头长度不对的数据,可以返回读取失败")] + public async Task IpcMessageConverterWriteAsync2() + { + using var memoryStream = new MemoryStream(); + + var ipcConfiguration = new IpcConfiguration(); + ulong ack = 10; + var buffer = new byte[] { 0x12, 0x12, 0x00 }; + var messageHeader = new byte[] { 0x00, 0x00 }; + + var ipcBufferMessageContext = new IpcBufferMessageContext("test", IpcMessageCommandType.Unknown, new IpcMessageBody(buffer)); + + await IpcMessageConverter.WriteAsync(memoryStream, messageHeader, ack, ipcBufferMessageContext, new SharedArrayPool()); + + memoryStream.Position = 0; + var ipcMessageResult = (await IpcMessageConverter.ReadAsync(memoryStream, + ipcConfiguration.MessageHeader, new SharedArrayPool())).Result; + var success = ipcMessageResult.Success; + var ipcMessageCommandType = ipcMessageResult.IpcMessageCommandType; + + Assert.AreEqual(false, success); + Assert.AreEqual(IpcMessageCommandType.Unknown, ipcMessageCommandType); + } + + [TestMethod("写入的数据和读取的相同,可以读取到写入的数据")] + public async Task IpcMessageConverterWriteAsync3() { - "读取消息头不对的数据,可以返回读取失败".Test(async () => - { - using var memoryStream = new MemoryStream(); - - ulong ack = 10; - var buffer = new byte[] { 0x12, 0x12, 0x00 }; - var messageHeader = new byte[] { 0x00, 0x00 }; - var breakMessageHeader = new byte[] { 0x00, 0x01 }; - - var ipcBufferMessageContext = new IpcBufferMessageContext("test", IpcMessageCommandType.Unknown, new IpcMessageBody(buffer)); - - await IpcMessageConverter.WriteAsync(memoryStream, messageHeader, ack, ipcBufferMessageContext, new SharedArrayPool()); - - memoryStream.Position = 0; - var ipcMessageResult = (await IpcMessageConverter.ReadAsync(memoryStream, - breakMessageHeader, new SharedArrayPool())).Result; - var success = ipcMessageResult.Success; - var ipcMessageCommandType = ipcMessageResult.IpcMessageCommandType; - - Assert.AreEqual(false, success); - Assert.AreEqual(IpcMessageCommandType.Unknown, ipcMessageCommandType); - }); - - "读取消息头长度不对的数据,可以返回读取失败".Test(async () => - { - using var memoryStream = new MemoryStream(); - - var ipcConfiguration = new IpcConfiguration(); - ulong ack = 10; - var buffer = new byte[] { 0x12, 0x12, 0x00 }; - var messageHeader = new byte[] { 0x00, 0x00 }; - - var ipcBufferMessageContext = new IpcBufferMessageContext("test", IpcMessageCommandType.Unknown, new IpcMessageBody(buffer)); - - await IpcMessageConverter.WriteAsync(memoryStream, messageHeader, ack, ipcBufferMessageContext, new SharedArrayPool()); - - memoryStream.Position = 0; - var ipcMessageResult = (await IpcMessageConverter.ReadAsync(memoryStream, - ipcConfiguration.MessageHeader, new SharedArrayPool())).Result; - var success = ipcMessageResult.Success; - var ipcMessageCommandType = ipcMessageResult.IpcMessageCommandType; - - Assert.AreEqual(false, success); - Assert.AreEqual(IpcMessageCommandType.Unknown, ipcMessageCommandType); - }); - - "写入的数据和读取的相同,可以读取到写入的数据".Test(async () => - { - // 写入的数据和读取的相同 - using var memoryStream = new MemoryStream(); - - var ipcConfiguration = new IpcConfiguration(); - ulong ack = 10; - var buffer = new byte[] { 0x12, 0x12, 0x00 }; - var ipcBufferMessageContext = new IpcBufferMessageContext("test", IpcMessageCommandType.Unknown, new IpcMessageBody(buffer)); - await IpcMessageConverter.WriteAsync(memoryStream, ipcConfiguration.MessageHeader, ack, ipcBufferMessageContext, new SharedArrayPool()); - - memoryStream.Position = 0; - var (success, ipcMessageContext) = (await IpcMessageConverter.ReadAsync(memoryStream, - ipcConfiguration.MessageHeader, new SharedArrayPool())).Result; - - Assert.AreEqual(true, success); - Assert.AreEqual(ack, ipcMessageContext.Ack.Value); - }); + + // 写入的数据和读取的相同 + using var memoryStream = new MemoryStream(); + + var ipcConfiguration = new IpcConfiguration(); + ulong ack = 10; + var buffer = new byte[] { 0x12, 0x12, 0x00 }; + var ipcBufferMessageContext = new IpcBufferMessageContext("test", IpcMessageCommandType.Unknown, new IpcMessageBody(buffer)); + await IpcMessageConverter.WriteAsync(memoryStream, ipcConfiguration.MessageHeader, ack, ipcBufferMessageContext, new SharedArrayPool()); + + memoryStream.Position = 0; + var (success, ipcMessageContext) = (await IpcMessageConverter.ReadAsync(memoryStream, + ipcConfiguration.MessageHeader, new SharedArrayPool())).Result; + + Assert.AreEqual(true, success); + Assert.AreEqual(ack, ipcMessageContext.Ack.Value); } } } diff --git a/tests/dotnetCampus.Ipc.Tests/IpcObjectJsonSerializerTests.cs b/tests/dotnetCampus.Ipc.Tests/IpcObjectJsonSerializerTests.cs index 1591b541..0f79c9fa 100644 --- a/tests/dotnetCampus.Ipc.Tests/IpcObjectJsonSerializerTests.cs +++ b/tests/dotnetCampus.Ipc.Tests/IpcObjectJsonSerializerTests.cs @@ -1,34 +1,24 @@ using dotnetCampus.Ipc.Serialization; -using dotnetCampus.Ipc.Utils; - using Microsoft.VisualStudio.TestTools.UnitTesting; -using MSTest.Extensions.Contracts; - namespace dotnetCampus.Ipc.Tests { [TestClass] public class IpcObjectJsonSerializerTests { - [ContractTestCase] + [TestMethod("序列化对象之后,能通过二进制反序列化回对象")] public void Serialize() { - "序列化对象之后,能通过二进制反序列化回对象".Test(() => - { - // Arrange - IIpcObjectSerializer ipcObjectSerializer = new IpcObjectJsonSerializer(); - var foo = new Foo() - { - Name = "林德熙是逗比" - }; + // Arrange + IIpcObjectSerializer ipcObjectSerializer = new IpcObjectJsonSerializer(); + var foo = new Foo() { Name = "林德熙是逗比" }; - // Action - var byteList = ipcObjectSerializer.Serialize(foo); - var deserializeFoo = ipcObjectSerializer.Deserialize(byteList); + // Action + var byteList = ipcObjectSerializer.Serialize(foo); + var deserializeFoo = ipcObjectSerializer.Deserialize(byteList); - // Assert - Assert.AreEqual(foo.Name, deserializeFoo.Name); - }); + // Assert + Assert.AreEqual(foo.Name, deserializeFoo.Name); } public class Foo diff --git a/tests/dotnetCampus.Ipc.Tests/IpcRouteds/DirectRouteds/JsonIpcDirectRoutedProviderTest.cs b/tests/dotnetCampus.Ipc.Tests/IpcRouteds/DirectRouteds/JsonIpcDirectRoutedProviderTest.cs index eb0dac50..60186b0b 100644 --- a/tests/dotnetCampus.Ipc.Tests/IpcRouteds/DirectRouteds/JsonIpcDirectRoutedProviderTest.cs +++ b/tests/dotnetCampus.Ipc.Tests/IpcRouteds/DirectRouteds/JsonIpcDirectRoutedProviderTest.cs @@ -1,11 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -using dotnetCampus.Ipc.CompilerServices.GeneratedProxies; +using dotnetCampus.Ipc.CompilerServices.GeneratedProxies; using dotnetCampus.Ipc.Context; using dotnetCampus.Ipc.IpcRouteds.DirectRouteds; using dotnetCampus.Ipc.Pipes; @@ -14,593 +7,563 @@ using dotnetCampus.Ipc.Utils.Logging; using Microsoft.VisualStudio.TestTools.UnitTesting; -using MSTest.Extensions.Contracts; - namespace dotnetCampus.Ipc.Tests.IpcRouteds.DirectRouteds; [TestClass] public class JsonIpcDirectRoutedProviderTest { - [ContractTestCase] - public void TestShared() + [TestMethod("多个通讯框架共用相同的 IpcProvider 对象,相互之间不受影响")] + public async Task TestShared() { - "多个通讯框架共用相同的 IpcProvider 对象,相互之间不受影响".Test(async () => - { - var name = "JsonIpcDirectRoutedProviderTest_1"; - var aName = $"IpcObjectTests.IpcTests.{name}.A"; - var bName = $"IpcObjectTests.IpcTests.{name}.B"; - var aProvider = new IpcProvider(aName); - var bProvider = new IpcProvider(bName); + var name = "JsonIpcDirectRoutedProviderTest_1"; + var aName = $"IpcObjectTests.IpcTests.{name}.A"; + var bName = $"IpcObjectTests.IpcTests.{name}.B"; + var aProvider = new IpcProvider(aName); + var bProvider = new IpcProvider(bName); - var serverProvider = new JsonIpcDirectRoutedProvider(aProvider); - var clientProvider = new JsonIpcDirectRoutedProvider(bProvider); + var serverProvider = new JsonIpcDirectRoutedProvider(aProvider); + var clientProvider = new JsonIpcDirectRoutedProvider(bProvider); - const string routedPath = "Foo1"; - serverProvider.AddRequestHandler(routedPath, (FakeArgument argument) => - { - return new FakeResult("Ok"); - }); + const string routedPath = "Foo1"; + serverProvider.AddRequestHandler(routedPath, (FakeArgument argument) => + { + return new FakeResult("Ok"); + }); - serverProvider.StartServer(); - clientProvider.StartServer(); + serverProvider.StartServer(); + clientProvider.StartServer(); - // 有上面的 StartServer 其实就可以不需要有下面的启动 - aProvider.StartServer(); - bProvider.StartServer(); + // 有上面的 StartServer 其实就可以不需要有下面的启动 + aProvider.StartServer(); + bProvider.StartServer(); - var aJoint = aProvider.CreateIpcJoint(new FakeIpcObject()); - var aPeer = await bProvider.GetAndConnectToPeerAsync(aName); - var bProxy = bProvider.CreateIpcProxy(aPeer); + var aJoint = aProvider.CreateIpcJoint(new FakeIpcObject()); + var aPeer = await bProvider.GetAndConnectToPeerAsync(aName); + var bProxy = bProvider.CreateIpcProxy(aPeer); - // 防止获取属性异步转同步卡住 - await Task.Yield(); + // 防止获取属性异步转同步卡住 + await Task.Yield(); - // 两个框架发送的内容,都经过相同的一个管道,但是相互不影响 - var result = bProxy.NullableStringProperty; - Assert.IsNotNull(result); + // 两个框架发送的内容,都经过相同的一个管道,但是相互不影响 + var result = bProxy.NullableStringProperty; + Assert.IsNotNull(result); - // 发送直接路由的请求 - var clientProxy = await clientProvider.GetAndConnectClientAsync(aName); - var fakeResult = await clientProxy.GetResponseAsync(routedPath, new FakeArgument("Name", 1)); - Assert.AreEqual("Ok", fakeResult.Name); - }); + // 发送直接路由的请求 + var clientProxy = await clientProvider.GetAndConnectClientAsync(aName); + var fakeResult = await clientProxy.GetResponseAsync(routedPath, new FakeArgument("Name", 1)); + Assert.AreEqual("Ok", fakeResult.Name); } - [ContractTestCase] - public void TestRequest() + [TestMethod("客户端请求服务端,可以在服务端收到客户端请求的内容")] + public async Task TestRequest1() { - "客户端请求服务端,可以在服务端收到客户端请求的内容".Test(async () => - { - // 初始化服务端 - var serverName = "JsonIpcDirectRoutedProviderTest_Request_1"; - var serverProvider = new JsonIpcDirectRoutedProvider(serverName, new IpcConfiguration() - { - IpcLoggerProvider = name => new IpcLogger(name) - { - MinLogLevel = LogLevel.Debug, - } - }); - var argument = new FakeArgument("TestName", 1); + // 初始化服务端 + var serverName = "JsonIpcDirectRoutedProviderTest_Request_1"; + var serverProvider = new JsonIpcDirectRoutedProvider(serverName, + new IpcConfiguration() { IpcLoggerProvider = name => new IpcLogger(name) { MinLogLevel = LogLevel.Debug, } }); + var argument = new FakeArgument("TestName", 1); - var responseText = $"OK_{Guid.NewGuid().ToString()}"; + var responseText = $"OK_{Guid.NewGuid().ToString()}"; - int enterCount = 0; - serverProvider.AddRequestHandler("Foo1", (FakeArgument arg) => - { - // 没有任何逻辑请求,不能处理 - enterCount++; - Assert.AreEqual(argument.Name, arg.Name); - Assert.AreEqual(argument.Count, arg.Count); + int enterCount = 0; + serverProvider.AddRequestHandler("Foo1", (FakeArgument arg) => + { + // 没有任何逻辑请求,不能处理 + enterCount++; + Assert.AreEqual(argument.Name, arg.Name); + Assert.AreEqual(argument.Count, arg.Count); - return new FakeResult(responseText); - }); + return new FakeResult(responseText); + }); - serverProvider.AddRequestHandler("Foo2", (FakeArgument arg, JsonIpcDirectRoutedContext context) => - { - // 没有任何逻辑请求,不能处理 - Assert.Fail(); - return new FakeResult("Ok"); - }); + serverProvider.AddRequestHandler("Foo2", (FakeArgument arg, JsonIpcDirectRoutedContext context) => + { + // 没有任何逻辑请求,不能处理 + Assert.Fail(); + return new FakeResult("Ok"); + }); - serverProvider.StartServer(); + serverProvider.StartServer(); - // 创建客户端 - // 允许管道名无参数,如果只是做客户端使用的话 - JsonIpcDirectRoutedProvider clientProvider = new(ipcConfiguration: new IpcConfiguration() - { - IpcLoggerProvider = name => new IpcLogger(name) - { - MinLogLevel = LogLevel.Debug, - } - }); - // 对于 clientProvider 来说,可选调用 StartServer 方法 - var clientProxy = await clientProvider.GetAndConnectClientAsync(serverName); + // 创建客户端 + // 允许管道名无参数,如果只是做客户端使用的话 + JsonIpcDirectRoutedProvider clientProvider = new(ipcConfiguration: new IpcConfiguration() + { + IpcLoggerProvider = name => new IpcLogger(name) { MinLogLevel = LogLevel.Debug, } + }); + // 对于 clientProvider 来说,可选调用 StartServer 方法 + var clientProxy = await clientProvider.GetAndConnectClientAsync(serverName); - var result = await clientProxy.GetResponseAsync("Foo1", argument); + var result = await clientProxy.GetResponseAsync("Foo1", argument); - // 可以获取到响应内容 - Assert.AreEqual(responseText, result!.Name); + // 可以获取到响应内容 + Assert.AreEqual(responseText, result!.Name); - // 要求只进入一次 - Assert.AreEqual(1, enterCount); - }); + // 要求只进入一次 + Assert.AreEqual(1, enterCount); + } - "客户端到服务端的请求,可以获取到服务端的响应".Test(async () => - { - // 初始化服务端 - var serverName = "JsonIpcDirectRoutedProviderTest_Request_2"; - var clientName = "JsonIpcDirectRoutedProviderTest_Request_Client_1"; - var serverProvider = new JsonIpcDirectRoutedProvider(serverName); - var argument = new FakeArgument("TestName", 1); + [TestMethod("客户端到服务端的请求,可以获取到服务端的响应")] + public async Task TestRequest2() + { + // 初始化服务端 + var serverName = "JsonIpcDirectRoutedProviderTest_Request_2"; + var clientName = "JsonIpcDirectRoutedProviderTest_Request_Client_1"; + var serverProvider = new JsonIpcDirectRoutedProvider(serverName); + var argument = new FakeArgument("TestName", 1); - var responseText = Guid.NewGuid().ToString(); + var responseText = Guid.NewGuid().ToString(); - int enterCount = 0; - serverProvider.AddRequestHandler("Foo1", (FakeArgument arg) => - { - // 没有任何逻辑请求,不能处理 - Assert.Fail(); - return new FakeResult("Ok"); - }); + int enterCount = 0; + serverProvider.AddRequestHandler("Foo1", (FakeArgument arg) => + { + // 没有任何逻辑请求,不能处理 + Assert.Fail(); + return new FakeResult("Ok"); + }); - serverProvider.AddRequestHandler("Foo2", (FakeArgument arg, JsonIpcDirectRoutedContext context) => - { - // 可以获取到客户端名 - Assert.AreEqual(clientName, context.PeerName); + serverProvider.AddRequestHandler("Foo2", (FakeArgument arg, JsonIpcDirectRoutedContext context) => + { + // 可以获取到客户端名 + Assert.AreEqual(clientName, context.PeerName); - enterCount++; + enterCount++; - return new FakeResult(responseText); - }); + return new FakeResult(responseText); + }); - serverProvider.StartServer(); + serverProvider.StartServer(); - // 创建客户端 - // 允许无参数,如果只是做客户端使用的话 - JsonIpcDirectRoutedProvider clientProvider = new(clientName); - // 对于 clientProvider 来说,可选调用 StartServer 方法 - var clientProxy = await clientProvider.GetAndConnectClientAsync(serverName); + // 创建客户端 + // 允许无参数,如果只是做客户端使用的话 + JsonIpcDirectRoutedProvider clientProvider = new(clientName); + // 对于 clientProvider 来说,可选调用 StartServer 方法 + var clientProxy = await clientProvider.GetAndConnectClientAsync(serverName); - var result = await clientProxy.GetResponseAsync("Foo2", argument); + var result = await clientProxy.GetResponseAsync("Foo2", argument); - // 可以获取到响应内容 - Assert.AreEqual(responseText, result.Name); + // 可以获取到响应内容 + Assert.AreEqual(responseText, result.Name); - // 要求只进入一次 - Assert.AreEqual(1, enterCount); - }); + // 要求只进入一次 + Assert.AreEqual(1, enterCount); + } - "允许创建多个服务端实例共用相同的 IpcProvider 对象,但是如果多个服务端对相同的路由进行处理,只有先添加的才能收到消息".Test(async () => + [TestMethod("允许创建多个服务端实例共用相同的 IpcProvider 对象,但是如果多个服务端对相同的路由进行处理,只有先添加的才能收到消息")] + public async Task TestRequest3() + { + // 初始化服务端 + var serverName = "JsonIpcDirectRoutedProviderTest_Request_3"; + // 这样的创建方式也是对 IPC 连接最高定制的方式 + IpcProvider ipcProvider = new(serverName); + var serverProvider1 = new JsonIpcDirectRoutedProvider(ipcProvider); + var argument = new FakeArgument("TestName", 1); + int enterCount = 0; + const string routedPath = "Foo1"; + var responseText = Guid.NewGuid().ToString(); + TaskCompletionSource taskCompletionSource = new(); + + serverProvider1.AddRequestHandler(routedPath, (FakeArgument arg) => { - // 初始化服务端 - var serverName = "JsonIpcDirectRoutedProviderTest_Request_3"; - // 这样的创建方式也是对 IPC 连接最高定制的方式 - IpcProvider ipcProvider = new(serverName); - var serverProvider1 = new JsonIpcDirectRoutedProvider(ipcProvider); - var argument = new FakeArgument("TestName", 1); - int enterCount = 0; - const string routedPath = "Foo1"; - var responseText = Guid.NewGuid().ToString(); - TaskCompletionSource taskCompletionSource = new(); - - serverProvider1.AddRequestHandler(routedPath, (FakeArgument arg) => - { - enterCount++; - return new FakeResult(responseText); - }); + enterCount++; + return new FakeResult(responseText); + }); - // 再次开启一个服务,共用相同的 IpcProvider 对象 - var serverProvider2 = new JsonIpcDirectRoutedProvider(ipcProvider); + // 再次开启一个服务,共用相同的 IpcProvider 对象 + var serverProvider2 = new JsonIpcDirectRoutedProvider(ipcProvider); - serverProvider2.AddRequestHandler(routedPath, (FakeArgument arg) => - { - // 第二个服务收不到消息 - Assert.Fail(); + serverProvider2.AddRequestHandler(routedPath, (FakeArgument arg) => + { + // 第二个服务收不到消息 + Assert.Fail(); - return new FakeResult(responseText); - }); + return new FakeResult(responseText); + }); - // 多服务使用相同的 IpcProvider 对象存在一个问题,那就是如果是原先 IpcProvider 就启动过的,那这里添加处理一定会抛出异常 - // 意味着需要所有的 JsonIpcDirectRoutedProvider 都创建和添加处理,才能一起调用 StartServer 开始 - serverProvider1.StartServer(); - serverProvider2.StartServer(); + // 多服务使用相同的 IpcProvider 对象存在一个问题,那就是如果是原先 IpcProvider 就启动过的,那这里添加处理一定会抛出异常 + // 意味着需要所有的 JsonIpcDirectRoutedProvider 都创建和添加处理,才能一起调用 StartServer 开始 + serverProvider1.StartServer(); + serverProvider2.StartServer(); - // 创建客户端 - // 允许无参数,如果只是做客户端使用的话 - JsonIpcDirectRoutedProvider clientProvider = new(); - var clientProxy = await clientProvider.GetAndConnectClientAsync(serverName); + // 创建客户端 + // 允许无参数,如果只是做客户端使用的话 + JsonIpcDirectRoutedProvider clientProvider = new(); + var clientProxy = await clientProvider.GetAndConnectClientAsync(serverName); - var result = await clientProxy.GetResponseAsync("Foo1", argument); + var result = await clientProxy.GetResponseAsync("Foo1", argument); - // 可以获取到响应内容 - Assert.AreEqual(responseText, result.Name); + // 可以获取到响应内容 + Assert.AreEqual(responseText, result.Name); - // 要求只进入一次 - Assert.AreEqual(1, enterCount); - }); + // 要求只进入一次 + Assert.AreEqual(1, enterCount); } - //[ContractTestCase] // 这一条调试下行为可能不同,于是先注释掉 - public void TestException() + // [TestMethod("如果请求的对象出现了异常,可以正确收到请求响应结束,而不会进入无限等待")] // 这一条调试下行为可能不同,于是先注释掉 + public async Task TestException() { - "如果请求的对象出现了异常,可以正确收到请求响应结束,而不会进入无限等待".Test(async () => + // 初始化服务端 + var serverName = "JsonIpcDirectRoutedProviderTest_TestException_1"; + var jsonIpcDirectRoutedProvider = new JsonIpcDirectRoutedProvider(serverName); + var path = "Foo"; + jsonIpcDirectRoutedProvider.AddRequestHandler(path, (FakeArgument fakeArgument) => { - // 初始化服务端 - var serverName = "JsonIpcDirectRoutedProviderTest_TestException_1"; - var jsonIpcDirectRoutedProvider = new JsonIpcDirectRoutedProvider(serverName); - var path = "Foo"; - jsonIpcDirectRoutedProvider.AddRequestHandler(path, (FakeArgument fakeArgument) => + if (!string.IsNullOrEmpty(fakeArgument.Name)) { - if (!string.IsNullOrEmpty(fakeArgument.Name)) - { - throw new Exception("Foo"); - } - - return new FakeResult("xx"); - }); - jsonIpcDirectRoutedProvider.StartServer(); + throw new Exception("Foo"); + } - var t = new JsonIpcDirectRoutedProvider(); - var client = await t.GetAndConnectClientAsync(serverName); - var response = await client.GetResponseAsync(path, new FakeArgument("xx", 1)); - // 能够等到响应结束就是成功 - GC.KeepAlive(response); // 这句话只是方便打断点 + return new FakeResult("xx"); }); + jsonIpcDirectRoutedProvider.StartServer(); + + var t = new JsonIpcDirectRoutedProvider(); + var client = await t.GetAndConnectClientAsync(serverName); + var response = await client.GetResponseAsync(path, new FakeArgument("xx", 1)); + // 能够等到响应结束就是成功 + GC.KeepAlive(response); // 这句话只是方便打断点 } - [ContractTestCase] + [TestMethod("重复调用 JsonIpcDirectRoutedProvider 添加通知处理相同的消息,将会抛出异常")] public void AddNotifyHandler() { - "重复调用 JsonIpcDirectRoutedProvider 添加通知处理相同的消息,将会抛出异常".Test(() => - { - JsonIpcDirectRoutedProvider provider = new(); + JsonIpcDirectRoutedProvider provider = new(); - var routedPath = "FooPath"; + var routedPath = "FooPath"; - provider.AddNotifyHandler(routedPath, (FakeArgument arg) => - { - }); + provider.AddNotifyHandler(routedPath, (FakeArgument arg) => + { + }); - Assert.ThrowsException(() => + Assert.ThrowsException(() => + { + provider.AddNotifyHandler(routedPath, (FakeArgument arg) => { - provider.AddNotifyHandler(routedPath, (FakeArgument arg) => - { - }); }); }); } - [ContractTestCase] + [TestMethod("重复调用 AddRequestHandler 添加请求处理相同的消息,将会抛出异常")] public void AddRequestHandler() { - "重复调用 AddRequestHandler 添加请求处理相同的消息,将会抛出异常".Test(() => - { - JsonIpcDirectRoutedProvider provider = new(); + JsonIpcDirectRoutedProvider provider = new(); - var routedPath = "FooPath"; + var routedPath = "FooPath"; + provider.AddRequestHandler(routedPath, (FakeArgument argument) => + { + return "Ok"; + }); + + Assert.ThrowsException(() => + { provider.AddRequestHandler(routedPath, (FakeArgument argument) => { return "Ok"; }); - - Assert.ThrowsException(() => - { - provider.AddRequestHandler(routedPath, (FakeArgument argument) => - { - return "Ok"; - }); - }); }); } - [ContractTestCase] - public void TestNotify() + [TestMethod("允许创建多个服务端实例共用相同的 IpcProvider 对象,从而每个服务端接收不同的通知")] + public async Task TestNotify1() { - "允许创建多个服务端实例共用相同的 IpcProvider 对象,从而每个服务端接收不同的通知".Test(async () => + // 初始化服务端 + var serverName = "JsonIpcDirectRoutedProviderTest_Notify_3"; + // 这样的创建方式也是对 IPC 连接最高定制的方式 + IpcProvider ipcProvider = new(serverName); + var serverProvider1 = new JsonIpcDirectRoutedProvider(ipcProvider); + var argument = new FakeArgument("TestName", 1); + int enterCount = 0; + TaskCompletionSource taskCompletionSource = new(); + + serverProvider1.AddNotifyHandler("Foo1", (FakeArgument arg) => { - // 初始化服务端 - var serverName = "JsonIpcDirectRoutedProviderTest_Notify_3"; - // 这样的创建方式也是对 IPC 连接最高定制的方式 - IpcProvider ipcProvider = new(serverName); - var serverProvider1 = new JsonIpcDirectRoutedProvider(ipcProvider); - var argument = new FakeArgument("TestName", 1); - int enterCount = 0; - TaskCompletionSource taskCompletionSource = new(); - - serverProvider1.AddNotifyHandler("Foo1", (FakeArgument arg) => + Interlocked.Increment(ref enterCount); + Assert.AreEqual(argument.Name, arg.Name); + Assert.AreEqual(argument.Count, arg.Count); + + if (enterCount == 2) { - Interlocked.Increment(ref enterCount); - Assert.AreEqual(argument.Name, arg.Name); - Assert.AreEqual(argument.Count, arg.Count); - - if (enterCount == 2) - { - taskCompletionSource.TrySetResult(); - } - }); + taskCompletionSource.TrySetResult(); + } + }); - // 再次开启一个服务,共用相同的 IpcProvider 对象 - var serverProvider2 = new JsonIpcDirectRoutedProvider(ipcProvider); + // 再次开启一个服务,共用相同的 IpcProvider 对象 + var serverProvider2 = new JsonIpcDirectRoutedProvider(ipcProvider); - serverProvider2.AddNotifyHandler("Foo2", (FakeArgument arg) => + serverProvider2.AddNotifyHandler("Foo2", (FakeArgument arg) => + { + Interlocked.Increment(ref enterCount); + Assert.AreEqual(argument.Name, arg.Name); + Assert.AreEqual(argument.Count, arg.Count); + + if (enterCount == 2) { - Interlocked.Increment(ref enterCount); - Assert.AreEqual(argument.Name, arg.Name); - Assert.AreEqual(argument.Count, arg.Count); - - if (enterCount == 2) - { - taskCompletionSource.TrySetResult(); - } - }); - serverProvider1.StartServer(); - serverProvider2.StartServer(); - - // 创建客户端 - // 允许无参数,如果只是做客户端使用的话 - JsonIpcDirectRoutedProvider clientProvider = new(); - var clientProxy = await clientProvider.GetAndConnectClientAsync(serverName); - await clientProxy.NotifyAsync("Foo1", argument); - // 预期这条消息是在第二个服务处理的 - await clientProxy.NotifyAsync("Foo2", argument); - - // 等待接收完成,以上的 await 返回仅仅只是发送出去,不代表对方已接收到 - await taskCompletionSource.Task.WaitTimeout(TimeSpan.FromSeconds(5)); - // 两个服务都进入 - Assert.AreEqual(2, enterCount); + taskCompletionSource.TrySetResult(); + } }); + serverProvider1.StartServer(); + serverProvider2.StartServer(); + + // 创建客户端 + // 允许无参数,如果只是做客户端使用的话 + JsonIpcDirectRoutedProvider clientProvider = new(); + var clientProxy = await clientProvider.GetAndConnectClientAsync(serverName); + await clientProxy.NotifyAsync("Foo1", argument); + // 预期这条消息是在第二个服务处理的 + await clientProxy.NotifyAsync("Foo2", argument); + + // 等待接收完成,以上的 await 返回仅仅只是发送出去,不代表对方已接收到 + await taskCompletionSource.Task.WaitTimeout(TimeSpan.FromSeconds(5)); + // 两个服务都进入 + Assert.AreEqual(2, enterCount); + } - "从客户端通知到服务端,可以在服务端获取到通知的客户端名".Test(async () => + [TestMethod("从客户端通知到服务端,可以在服务端获取到通知的客户端名")] + public async Task TestNotify2() + { + // 初始化服务端 + var serverName = "JsonIpcDirectRoutedProviderTest_Notify_2"; + var clientName = "JsonIpcDirectRoutedProviderTest_Notify_Client_1"; + var serverProvider = new JsonIpcDirectRoutedProvider(serverName); + var argument = new FakeArgument("TestName", 1); + + int enterCount = 0; + TaskCompletionSource taskCompletionSource = new(); + serverProvider.AddNotifyHandler("Foo1", (FakeArgument arg) => { - // 初始化服务端 - var serverName = "JsonIpcDirectRoutedProviderTest_Notify_2"; - var clientName = "JsonIpcDirectRoutedProviderTest_Notify_Client_1"; - var serverProvider = new JsonIpcDirectRoutedProvider(serverName); - var argument = new FakeArgument("TestName", 1); - - int enterCount = 0; - TaskCompletionSource taskCompletionSource = new(); - serverProvider.AddNotifyHandler("Foo1", (FakeArgument arg) => - { - // 没有任何逻辑请求,不能处理 - Assert.Fail(); - }); + // 没有任何逻辑请求,不能处理 + Assert.Fail(); + }); - serverProvider.AddNotifyHandler("Foo2", (arg, context) => - { - // 可以获取到客户端名 - Assert.AreEqual(clientName, context.PeerName); + serverProvider.AddNotifyHandler("Foo2", (arg, context) => + { + // 可以获取到客户端名 + Assert.AreEqual(clientName, context.PeerName); - enterCount++; + enterCount++; - taskCompletionSource.TrySetResult(); - }); + taskCompletionSource.TrySetResult(); + }); - serverProvider.StartServer(); + serverProvider.StartServer(); - // 创建客户端 - // 允许无参数,如果只是做客户端使用的话 - JsonIpcDirectRoutedProvider clientProvider = new(clientName); - // 对于 clientProvider 来说,可选调用 StartServer 方法 - var clientProxy = await clientProvider.GetAndConnectClientAsync(serverName); + // 创建客户端 + // 允许无参数,如果只是做客户端使用的话 + JsonIpcDirectRoutedProvider clientProvider = new(clientName); + // 对于 clientProvider 来说,可选调用 StartServer 方法 + var clientProxy = await clientProvider.GetAndConnectClientAsync(serverName); - await clientProxy.NotifyAsync("Foo2", argument); + await clientProxy.NotifyAsync("Foo2", argument); - // 等待接收完成,以上的 await 返回仅仅只是发送出去,不代表对方已接收到 - await taskCompletionSource.Task.WaitTimeout(TimeSpan.FromSeconds(5)); - // 要求只进入一次 - Assert.AreEqual(1, enterCount); - }); + // 等待接收完成,以上的 await 返回仅仅只是发送出去,不代表对方已接收到 + await taskCompletionSource.Task.WaitTimeout(TimeSpan.FromSeconds(5)); + // 要求只进入一次 + Assert.AreEqual(1, enterCount); + } - "客户端的通知可以成功发送到服务端".Test(async () => + [TestMethod("客户端的通知可以成功发送到服务端")] + public async Task TestNotify3() + { + // 初始化服务端 + var serverName = "JsonIpcDirectRoutedProviderTest_Notify_1"; + var serverProvider = new JsonIpcDirectRoutedProvider(serverName); + var routedPath = "Foo1"; + var argument = new FakeArgument("TestName", 1); + + int enterCount = 0; + TaskCompletionSource taskCompletionSource = new(); + serverProvider.AddNotifyHandler(routedPath, (FakeArgument arg) => { - // 初始化服务端 - var serverName = "JsonIpcDirectRoutedProviderTest_Notify_1"; - var serverProvider = new JsonIpcDirectRoutedProvider(serverName); - var routedPath = "Foo1"; - var argument = new FakeArgument("TestName", 1); - - int enterCount = 0; - TaskCompletionSource taskCompletionSource = new(); - serverProvider.AddNotifyHandler(routedPath, (FakeArgument arg) => - { - enterCount++; - Assert.AreEqual(argument.Name, arg.Name); - Assert.AreEqual(argument.Count, arg.Count); + enterCount++; + Assert.AreEqual(argument.Name, arg.Name); + Assert.AreEqual(argument.Count, arg.Count); - taskCompletionSource.TrySetResult(); - }); + taskCompletionSource.TrySetResult(); + }); - serverProvider.AddNotifyHandler("Foo2", (arg, context) => - { - // 没有任何逻辑请求,不能处理 - Assert.Fail(); - }); + serverProvider.AddNotifyHandler("Foo2", (arg, context) => + { + // 没有任何逻辑请求,不能处理 + Assert.Fail(); + }); - serverProvider.StartServer(); + serverProvider.StartServer(); - // 创建客户端 - // 允许无参数,如果只是做客户端使用的话 - JsonIpcDirectRoutedProvider clientProvider = new(); - clientProvider.StartServer(); - var clientProxy = await clientProvider.GetAndConnectClientAsync(serverName); + // 创建客户端 + // 允许无参数,如果只是做客户端使用的话 + JsonIpcDirectRoutedProvider clientProvider = new(); + clientProvider.StartServer(); + var clientProxy = await clientProvider.GetAndConnectClientAsync(serverName); - await clientProxy.NotifyAsync(routedPath, argument); + await clientProxy.NotifyAsync(routedPath, argument); - // 等待接收完成,以上的 await 返回仅仅只是发送出去,不代表对方已接收到 - await taskCompletionSource.Task.WaitTimeout(TimeSpan.FromSeconds(5)); - // 要求只进入一次 - Assert.AreEqual(1, enterCount); - }); + // 等待接收完成,以上的 await 返回仅仅只是发送出去,不代表对方已接收到 + await taskCompletionSource.Task.WaitTimeout(TimeSpan.FromSeconds(5)); + // 要求只进入一次 + Assert.AreEqual(1, enterCount); } - [ContractTestCase] - public void TestNotifyLocalOneByOne() + [TestMethod("配置 LocalOneByOne 即可让服务端收到的通知消息是一条条按照顺序接收的")] + public async Task TestNotifyLocalOneByOne() { - "配置 LocalOneByOne 即可让服务端收到的通知消息是一条条按照顺序接收的".Test(async () => + // 初始化服务端 + var serverName = "JsonIpcDirectRoutedProviderTest_Test_NotifyLocalOneByOne_1"; + var serverProvider = new JsonIpcDirectRoutedProvider(serverName, new IpcConfiguration() { IpcTaskScheduling = IpcTaskScheduling.LocalOneByOne, }); + + var count = 0; + for (int i = 0; i < 10; i++) { - // 初始化服务端 - var serverName = "JsonIpcDirectRoutedProviderTest_Test_NotifyLocalOneByOne_1"; - var serverProvider = new JsonIpcDirectRoutedProvider(serverName, new IpcConfiguration() + var n = i; + serverProvider.AddNotifyHandler($"Foo{n}", async () => { - IpcTaskScheduling = IpcTaskScheduling.LocalOneByOne, + // 如果是按照顺序进来的,那就是按照数字顺序 + Assert.AreEqual(n, count); + count++; + // 模拟异步处理 + await Task.Delay(100); }); + } - var count = 0; - for (int i = 0; i < 10; i++) - { - var n = i; - serverProvider.AddNotifyHandler($"Foo{n}", async () => - { - // 如果是按照顺序进来的,那就是按照数字顺序 - Assert.AreEqual(n, count); - count++; - // 模拟异步处理 - await Task.Delay(100); - }); - } - - serverProvider.StartServer(); + serverProvider.StartServer(); - // 创建客户端 - JsonIpcDirectRoutedProvider clientProvider = new(); - clientProvider.StartServer(); - var clientProxy = await clientProvider.GetAndConnectClientAsync(serverName); + // 创建客户端 + JsonIpcDirectRoutedProvider clientProvider = new(); + clientProvider.StartServer(); + var clientProxy = await clientProvider.GetAndConnectClientAsync(serverName); - // 发送 10 条通知 - for (int i = 0; i < 10; i++) - { - await clientProxy.NotifyAsync($"Foo{i}"); - } + // 发送 10 条通知 + for (int i = 0; i < 10; i++) + { + await clientProxy.NotifyAsync($"Foo{i}"); + } - // 等待接收完成,以上的 await 返回仅仅只是发送出去,不代表对方已接收到 - for (int i = 0; i < 1000 && count != 10; i++) - { - await Task.Delay(100); - } - }); + // 等待接收完成,以上的 await 返回仅仅只是发送出去,不代表对方已接收到 + for (int i = 0; i < 1000 && count != 10; i++) + { + await Task.Delay(100); + } } /// /// 测试无参版本 /// - [ContractTestCase] - public void TestParameterless() + [TestMethod("发送无参请求,可以让服务端收到请求")] + public async Task TestParameterless() { - "发送无参请求,可以让服务端收到请求".Test(async () => + // 初始化服务端 + var serverName = "JsonIpcDirectRoutedProviderTest_Test_Parameterless_1"; + var serverProvider = new JsonIpcDirectRoutedProvider(serverName); + var routedPath = "Foo1"; + + // 注册无参数请求处理 + serverProvider.AddRequestHandler(routedPath, () => { - // 初始化服务端 - var serverName = "JsonIpcDirectRoutedProviderTest_Test_Parameterless_1"; - var serverProvider = new JsonIpcDirectRoutedProvider(serverName); - var routedPath = "Foo1"; + return new FakeResult(nameof(TestParameterless)); + }); - // 注册无参数请求处理 - serverProvider.AddRequestHandler(routedPath, () => - { - return new FakeResult(nameof(TestParameterless)); - }); + serverProvider.StartServer(); - serverProvider.StartServer(); + // 创建客户端 + JsonIpcDirectRoutedProvider clientProvider = new(); + clientProvider.StartServer(); + var clientProxy = await clientProvider.GetAndConnectClientAsync(serverName); - // 创建客户端 - JsonIpcDirectRoutedProvider clientProvider = new(); - clientProvider.StartServer(); - var clientProxy = await clientProvider.GetAndConnectClientAsync(serverName); + // 请求无参数 + var result = await clientProxy.GetResponseAsync(routedPath); - // 请求无参数 - var result = await clientProxy.GetResponseAsync(routedPath); + // 如果能收到服务端返回值,证明请求成功 + Assert.IsNotNull(result); + Assert.AreEqual(nameof(TestParameterless), result.Name); + } - // 如果能收到服务端返回值,证明请求成功 - Assert.IsNotNull(result); - Assert.AreEqual(nameof(TestParameterless), result.Name); - }); + [TestMethod("发送无参通知,可以让服务端收到通知")] + public async Task TestParameterless2() + { + // 初始化服务端 + var serverName = "JsonIpcDirectRoutedProviderTest_Test_Parameterless_2"; + var serverProvider = new JsonIpcDirectRoutedProvider(serverName); + var routedPath = "Foo1"; - "发送无参通知,可以让服务端收到通知".Test(async () => + var taskCompletionSource = new TaskCompletionSource(); + serverProvider.AddNotifyHandler(routedPath, () => { - // 初始化服务端 - var serverName = "JsonIpcDirectRoutedProviderTest_Test_Parameterless_2"; - var serverProvider = new JsonIpcDirectRoutedProvider(serverName); - var routedPath = "Foo1"; - - var taskCompletionSource = new TaskCompletionSource(); - serverProvider.AddNotifyHandler(routedPath, () => - { - taskCompletionSource.SetResult(); - }); + taskCompletionSource.SetResult(); + }); - serverProvider.StartServer(); + serverProvider.StartServer(); - // 创建客户端 - JsonIpcDirectRoutedProvider clientProvider = new(); - clientProvider.StartServer(); - var clientProxy = await clientProvider.GetAndConnectClientAsync(serverName); - await clientProxy.NotifyAsync(routedPath); + // 创建客户端 + JsonIpcDirectRoutedProvider clientProvider = new(); + clientProvider.StartServer(); + var clientProxy = await clientProvider.GetAndConnectClientAsync(serverName); + await clientProxy.NotifyAsync(routedPath); - // 再等待一下,让服务端处理完成 - await taskCompletionSource.Task.WaitTimeout(TimeSpan.FromSeconds(1)); - // 预期是服务端能够执行完成 - Assert.AreEqual(true, taskCompletionSource.Task.IsCompleted); - }); + // 再等待一下,让服务端处理完成 + await taskCompletionSource.Task.WaitTimeout(TimeSpan.FromSeconds(1)); + // 预期是服务端能够执行完成 + Assert.AreEqual(true, taskCompletionSource.Task.IsCompleted); + } - "发送无参请求,服务端订阅有参,依然可以让服务端收到请求".Test(async () => + [TestMethod("发送无参请求,服务端订阅有参,依然可以让服务端收到请求")] + public async Task TestParameterless3() + { + // 可能是版本兼容,一个客户端版本软件是旧版本发送时不带参数,后续的服务端新版本写了带参数处理 + // 期望这样的情况服务端依然能够收到请求,达成兼容 + // 初始化服务端 + var serverName = "JsonIpcDirectRoutedProviderTest_Test_Parameterless_3"; + var serverProvider = new JsonIpcDirectRoutedProvider(serverName); + var routedPath = "Foo1"; + + // 服务端订阅有参 + serverProvider.AddRequestHandler(routedPath, (FakeArgument arg) => { - // 可能是版本兼容,一个客户端版本软件是旧版本发送时不带参数,后续的服务端新版本写了带参数处理 - // 期望这样的情况服务端依然能够收到请求,达成兼容 - // 初始化服务端 - var serverName = "JsonIpcDirectRoutedProviderTest_Test_Parameterless_3"; - var serverProvider = new JsonIpcDirectRoutedProvider(serverName); - var routedPath = "Foo1"; - - // 服务端订阅有参 - serverProvider.AddRequestHandler(routedPath, (FakeArgument arg) => - { - Assert.IsNotNull(arg); + Assert.IsNotNull(arg); - return new FakeResult(nameof(TestParameterless)); - }); + return new FakeResult(nameof(TestParameterless)); + }); - serverProvider.StartServer(); + serverProvider.StartServer(); - // 创建客户端 - JsonIpcDirectRoutedProvider clientProvider = new(); - clientProvider.StartServer(); - var clientProxy = await clientProvider.GetAndConnectClientAsync(serverName); + // 创建客户端 + JsonIpcDirectRoutedProvider clientProvider = new(); + clientProvider.StartServer(); + var clientProxy = await clientProvider.GetAndConnectClientAsync(serverName); - // 请求无参数 - var result = await clientProxy.GetResponseAsync(routedPath); + // 请求无参数 + var result = await clientProxy.GetResponseAsync(routedPath); - // 如果能收到服务端返回值,证明请求成功 - Assert.IsNotNull(result); - Assert.AreEqual(nameof(TestParameterless), result.Name); - }); + // 如果能收到服务端返回值,证明请求成功 + Assert.IsNotNull(result); + Assert.AreEqual(nameof(TestParameterless), result.Name); + } - "客户端发送有参请求,服务端订阅无参,依然可以让服务端收到请求".Test(async () => - { - var serverName = "JsonIpcDirectRoutedProviderTest_Test_Parameterless_4"; - var serverProvider = new JsonIpcDirectRoutedProvider(serverName); - var routedPath = "Foo1"; + [TestMethod("客户端发送有参请求,服务端订阅无参,依然可以让服务端收到请求")] + public async Task TestParameterless4() + { + var serverName = "JsonIpcDirectRoutedProviderTest_Test_Parameterless_4"; + var serverProvider = new JsonIpcDirectRoutedProvider(serverName); + var routedPath = "Foo1"; - // 服务端订阅无参 - serverProvider.AddRequestHandler(routedPath, () => - { - return new FakeResult(nameof(TestParameterless)); - }); + // 服务端订阅无参 + serverProvider.AddRequestHandler(routedPath, () => + { + return new FakeResult(nameof(TestParameterless)); + }); - serverProvider.StartServer(); + serverProvider.StartServer(); - // 创建客户端 - JsonIpcDirectRoutedProvider clientProvider = new(); - clientProvider.StartServer(); - var clientProxy = await clientProvider.GetAndConnectClientAsync(serverName); + // 创建客户端 + JsonIpcDirectRoutedProvider clientProvider = new(); + clientProvider.StartServer(); + var clientProxy = await clientProvider.GetAndConnectClientAsync(serverName); - // 发送有参请求 - var result = await clientProxy.GetResponseAsync(routedPath, new FakeArgument("foo", 2)); + // 发送有参请求 + var result = await clientProxy.GetResponseAsync(routedPath, new FakeArgument("foo", 2)); - // 如果能收到服务端返回值,证明请求成功 - Assert.IsNotNull(result); - Assert.AreEqual(nameof(TestParameterless), result.Name); - }); + // 如果能收到服务端返回值,证明请求成功 + Assert.IsNotNull(result); + Assert.AreEqual(nameof(TestParameterless), result.Name); } record class FakeArgument(string Name, int Count) diff --git a/tests/dotnetCampus.Ipc.Tests/NotifyTest.cs b/tests/dotnetCampus.Ipc.Tests/NotifyTest.cs index ff0d511e..77461f57 100644 --- a/tests/dotnetCampus.Ipc.Tests/NotifyTest.cs +++ b/tests/dotnetCampus.Ipc.Tests/NotifyTest.cs @@ -1,113 +1,104 @@ -using System; -using System.Threading; -using System.Threading.Tasks; - -using dotnetCampus.Ipc.Context; +using dotnetCampus.Ipc.Context; using dotnetCampus.Ipc.Messages; using dotnetCampus.Ipc.Pipes; using dotnetCampus.Ipc.Threading; using Microsoft.VisualStudio.TestTools.UnitTesting; -using MSTest.Extensions.Contracts; - namespace dotnetCampus.Ipc.Tests; [TestClass] public class NotifyTest { - [ContractTestCase] - public void Notify() + [TestMethod("使用 LocalOneByOne 的线程调度,按照顺序调用 NotifyAsync 方法,但是不等待 NotifyAsync 方法执行完成,可以按照顺序接收")] + public async Task Notify1() { - "使用 LocalOneByOne 的线程调度,按照顺序调用 NotifyAsync 方法,但是不等待 NotifyAsync 方法执行完成,可以按照顺序接收".Test(async () => - { - var name = "B_PeerNotifyTest_01"; + var name = "B_PeerNotifyTest_01"; - // 让 a 发送给 b 接收 - var a = new IpcProvider("A_PeerNotifyTest_01"); - var b = new IpcProvider(name, new IpcConfiguration() - { - // 使用 LocalOneByOne 的线程调度 - IpcTaskScheduling = IpcTaskScheduling.LocalOneByOne - }); + // 让 a 发送给 b 接收 + var a = new IpcProvider("A_PeerNotifyTest_01"); + var b = new IpcProvider(name, new IpcConfiguration() + { + // 使用 LocalOneByOne 的线程调度 + IpcTaskScheduling = IpcTaskScheduling.LocalOneByOne + }); - a.StartServer(); - b.StartServer(); + a.StartServer(); + b.StartServer(); - int currentCount = 0; - var taskCompletionSource = new TaskCompletionSource(); - const int count = byte.MaxValue - 10; + int currentCount = 0; + var taskCompletionSource = new TaskCompletionSource(); + const int count = byte.MaxValue - 10; - b.PeerConnected += (sender, args) => + b.PeerConnected += (sender, args) => + { + var aPeer = args.Peer; + aPeer.MessageReceived += (_, e) => { - var aPeer = args.Peer; - aPeer.MessageReceived += (_, e) => + // 按照顺序调用 Notify 方法,可以按照顺序接收 + // 发送的顺序就是首个不断加一,于是判断收到是否连续即可 + Assert.AreEqual(currentCount, e.Message.Body.Buffer[0]); + Interlocked.Increment(ref currentCount); + + if (currentCount == count) { - // 按照顺序调用 Notify 方法,可以按照顺序接收 - // 发送的顺序就是首个不断加一,于是判断收到是否连续即可 - Assert.AreEqual(currentCount, e.Message.Body.Buffer[0]); - Interlocked.Increment(ref currentCount); - - if (currentCount == count) - { - // 全部执行完成 - taskCompletionSource.SetResult(true); - } - }; + // 全部执行完成 + taskCompletionSource.SetResult(true); + } }; + }; - var peer = await a.GetAndConnectToPeerAsync(name); + var peer = await a.GetAndConnectToPeerAsync(name); - // 按照顺序调用 NotifyAsync 方法,但是不等待 NotifyAsync 方法执行完成 - for (int i = 0; i < count; i++) - { - _ = peer.NotifyAsync(new IpcMessage("测试使用 LocalOneByOne 的线程调度,按照顺序调用 Notify 方法,可以按照顺序接收", - new byte[] { (byte) i, 0xF1, 0xF2 })); - } + // 按照顺序调用 NotifyAsync 方法,但是不等待 NotifyAsync 方法执行完成 + for (int i = 0; i < count; i++) + { + _ = peer.NotifyAsync(new IpcMessage("测试使用 LocalOneByOne 的线程调度,按照顺序调用 Notify 方法,可以按照顺序接收", + new byte[] { (byte) i, 0xF1, 0xF2 })); + } - // 等待全部执行完成 - await Task.WhenAny(taskCompletionSource.Task, Task.Delay(TimeSpan.FromMinutes(5))); - Assert.AreEqual(true, taskCompletionSource.Task.IsCompleted); - }); + // 等待全部执行完成 + await Task.WhenAny(taskCompletionSource.Task, Task.Delay(TimeSpan.FromMinutes(5))); + Assert.AreEqual(true, taskCompletionSource.Task.IsCompleted); + } - "使用 LocalOneByOne 的线程调度,按照顺序调用 Notify 方法,可以按照顺序接收".Test(async () => - { - var name = "B_PeerNotifyTest"; + [TestMethod("使用 LocalOneByOne 的线程调度,按照顺序调用 Notify 方法,可以按照顺序接收")] + public async Task Notify2() + { + var name = "B_PeerNotifyTest"; - // 让 a 发送给 b 接收 - var a = new IpcProvider("A_PeerNotifyTest"); - var b = new IpcProvider(name, new IpcConfiguration() - { - // 使用 LocalOneByOne 的线程调度 - IpcTaskScheduling = IpcTaskScheduling.LocalOneByOne - }); + // 让 a 发送给 b 接收 + var a = new IpcProvider("A_PeerNotifyTest"); + var b = new IpcProvider(name, new IpcConfiguration() + { + // 使用 LocalOneByOne 的线程调度 + IpcTaskScheduling = IpcTaskScheduling.LocalOneByOne + }); - a.StartServer(); - b.StartServer(); + a.StartServer(); + b.StartServer(); - int currentCount = 0; + int currentCount = 0; - b.PeerConnected += (sender, args) => + b.PeerConnected += (sender, args) => + { + var aPeer = args.Peer; + aPeer.MessageReceived += (_, e) => { - var aPeer = args.Peer; - aPeer.MessageReceived += (_, e) => - { - // 按照顺序调用 Notify 方法,可以按照顺序接收 - // 发送的顺序就是首个不断加一,于是判断收到是否连续即可 - Assert.AreEqual(currentCount, e.Message.Body.Buffer[0]); - Interlocked.Increment(ref currentCount); - }; + // 按照顺序调用 Notify 方法,可以按照顺序接收 + // 发送的顺序就是首个不断加一,于是判断收到是否连续即可 + Assert.AreEqual(currentCount, e.Message.Body.Buffer[0]); + Interlocked.Increment(ref currentCount); }; + }; - var peer = await a.GetAndConnectToPeerAsync(name); - - // 按照顺序调用 Notify 方法 - for (int i = 0; i < byte.MaxValue - 10; i++) - { - await peer.NotifyAsync(new IpcMessage("测试使用 LocalOneByOne 的线程调度,按照顺序调用 Notify 方法,可以按照顺序接收", - new byte[] { (byte) i, 0xF1, 0xF2 })); - } + var peer = await a.GetAndConnectToPeerAsync(name); - }); + // 按照顺序调用 Notify 方法 + for (int i = 0; i < byte.MaxValue - 10; i++) + { + await peer.NotifyAsync(new IpcMessage("测试使用 LocalOneByOne 的线程调度,按照顺序调用 Notify 方法,可以按照顺序接收", + new byte[] { (byte) i, 0xF1, 0xF2 })); + } } } diff --git a/tests/dotnetCampus.Ipc.Tests/PeerProxyTest.cs b/tests/dotnetCampus.Ipc.Tests/PeerProxyTest.cs index 4ccc69fd..a93efe0e 100644 --- a/tests/dotnetCampus.Ipc.Tests/PeerProxyTest.cs +++ b/tests/dotnetCampus.Ipc.Tests/PeerProxyTest.cs @@ -1,393 +1,358 @@ -using System; -using System.Collections.Generic; -using System.Threading.Tasks; - -using dotnetCampus.Ipc.Context; -using dotnetCampus.Ipc.Exceptions; +using dotnetCampus.Ipc.Context; using dotnetCampus.Ipc.Internals; using dotnetCampus.Ipc.Messages; using dotnetCampus.Ipc.Pipes; -using dotnetCampus.Ipc.Utils.Extensions; using dotnetCampus.Threading; using Microsoft.VisualStudio.TestTools.UnitTesting; -using MSTest.Extensions.Contracts; - namespace dotnetCampus.Ipc.Tests { [TestClass] public class PeerProxyTest { - [ContractTestCase] - public void SendWithReconnect() + [TestMethod("断开连接过程中,所有请求响应,都可以在重连之后请求成功")] + public async Task SendWithReconnect1() { - "断开连接过程中,所有请求响应,都可以在重连之后请求成功".Test(async () => - { - var name = "B_PeerReconnected"; - var aRequest = new byte[] { 0xF1 }; - var cResponse = new byte[] { 0xF1, 0xF2 }; + var name = "B_PeerReconnected"; + var aRequest = new byte[] { 0xF1 }; + var cResponse = new byte[] { 0xF1, 0xF2 }; - var a = new IpcProvider("A_PeerReconnected", new IpcConfiguration() - { - AutoReconnectPeers = true, - }); - // 毕竟一会就要挂了,啥都不需要配置 - var b = new IpcProvider(name); + var a = new IpcProvider("A_PeerReconnected", new IpcConfiguration() { AutoReconnectPeers = true, }); + // 毕竟一会就要挂了,啥都不需要配置 + var b = new IpcProvider(name); - a.StartServer(); - b.StartServer(); + a.StartServer(); + b.StartServer(); - var peer = await a.GetAndConnectToPeerAsync(name); + var peer = await a.GetAndConnectToPeerAsync(name); - // 连接成功了,那么就让 b 凉凉 - b.Dispose(); + // 连接成功了,那么就让 b 凉凉 + b.Dispose(); - // 等待后台所有断开成功 - await Task.Delay(TimeSpan.FromSeconds(2)); + // 等待后台所有断开成功 + await Task.Delay(TimeSpan.FromSeconds(2)); - // 预期状态是 Peer 是断开的,等待重新连接 - Assert.AreEqual(true, peer.IsBroken); - Assert.AreEqual(false, peer.WaitForFinishedTaskCompletionSource.Task.IsCompleted); + // 预期状态是 Peer 是断开的,等待重新连接 + Assert.AreEqual(true, peer.IsBroken); + Assert.AreEqual(false, peer.WaitForFinishedTaskCompletionSource.Task.IsCompleted); - // 开始请求响应,预期进入等待,没有任何响应 - var requestTask = peer.GetResponseAsync(new IpcMessage("A发送", aRequest)); + // 开始请求响应,预期进入等待,没有任何响应 + var requestTask = peer.GetResponseAsync(new IpcMessage("A发送", aRequest)); - // 重新启动 b 服务,用法是再新建一个 c 用了 b 的 name 从而假装是 b 重启 - var c = new IpcProvider(name, new IpcConfiguration() - { - DefaultIpcRequestHandler = new DelegateIpcRequestHandler(context => - new IpcHandleRequestMessageResult(new IpcMessage("C回复", cResponse))) - }); - c.StartServer(); - - // 预期可以收到 - await requestTask.WaitTimeout(TimeSpan.FromSeconds(3)); - var ipcMessage = await requestTask; - Assert.AreEqual(true, ipcMessage.Body.AsSpan().SequenceEqual(cResponse)); + // 重新启动 b 服务,用法是再新建一个 c 用了 b 的 name 从而假装是 b 重启 + var c = new IpcProvider(name, new IpcConfiguration() + { + DefaultIpcRequestHandler = new DelegateIpcRequestHandler(context => + new IpcHandleRequestMessageResult(new IpcMessage("C回复", cResponse))) }); + c.StartServer(); - "断开连接过程中,发送的所有消息,都可以在重连之后发送".Test(async () => - { - var name = "B_PeerReconnected_F2"; - var aRequest = new byte[] { 0xF1 }; + // 预期可以收到 + await requestTask.WaitTimeout(TimeSpan.FromSeconds(3)); + var ipcMessage = await requestTask; + Assert.AreEqual(true, ipcMessage.Body.AsSpan().SequenceEqual(cResponse)); + } - var a = new IpcProvider("A_PeerReconnected_F2", new IpcConfiguration() - { - AutoReconnectPeers = true, - }); - // 毕竟一会就要挂了,啥都不需要配置 - var b = new IpcProvider(name); + [TestMethod("断开连接过程中,发送的所有消息,都可以在重连之后发送")] + public async Task SendWithReconnect2() + { + var name = "B_PeerReconnected_F2"; + var aRequest = new byte[] { 0xF1 }; + + var a = new IpcProvider("A_PeerReconnected_F2", new IpcConfiguration() { AutoReconnectPeers = true, }); + // 毕竟一会就要挂了,啥都不需要配置 + var b = new IpcProvider(name); - a.StartServer(); - b.StartServer(); + a.StartServer(); + b.StartServer(); - var peer = await a.GetAndConnectToPeerAsync(name); + var peer = await a.GetAndConnectToPeerAsync(name); - // 连接成功了,那么就让 b 凉凉 - b.Dispose(); + // 连接成功了,那么就让 b 凉凉 + b.Dispose(); - // 等待后台所有断开成功 - await Task.Delay(TimeSpan.FromSeconds(2)); + // 等待后台所有断开成功 + await Task.Delay(TimeSpan.FromSeconds(2)); - // 预期状态是 Peer 是断开的,等待重新连接 - Assert.AreEqual(true, peer.IsBroken); - Assert.AreEqual(false, peer.WaitForFinishedTaskCompletionSource.Task.IsCompleted); + // 预期状态是 Peer 是断开的,等待重新连接 + Assert.AreEqual(true, peer.IsBroken); + Assert.AreEqual(false, peer.WaitForFinishedTaskCompletionSource.Task.IsCompleted); - // 开始发送消息,此时发送消息的任务都在进入等待 - var notifyTask = peer.NotifyAsync(new IpcMessage("A发送", aRequest)); + // 开始发送消息,此时发送消息的任务都在进入等待 + var notifyTask = peer.NotifyAsync(new IpcMessage("A发送", aRequest)); - // 稍微等一下,此时预期还是没有发送完成 - await Task.WhenAny(notifyTask, Task.Delay(TimeSpan.FromMilliseconds(100))); - Assert.AreEqual(false, notifyTask.IsCompleted); + // 稍微等一下,此时预期还是没有发送完成 + await Task.WhenAny(notifyTask, Task.Delay(TimeSpan.FromMilliseconds(100))); + Assert.AreEqual(false, notifyTask.IsCompleted); - // 重新启动 b 服务,用法是再新建一个 c 用了 b 的 name 从而假装是 b 重启 - var c = new IpcProvider(name); + // 重新启动 b 服务,用法是再新建一个 c 用了 b 的 name 从而假装是 b 重启 + var c = new IpcProvider(name); - // 是否可以收到重新发送消息 - var receiveANotifyTask = new TaskCompletionSource(); - c.PeerConnected += (s, e) => + // 是否可以收到重新发送消息 + var receiveANotifyTask = new TaskCompletionSource(); + c.PeerConnected += (s, e) => + { + // 预期这里是 A 连接过来 + e.Peer.MessageReceived += (sender, args) => { - // 预期这里是 A 连接过来 - e.Peer.MessageReceived += (sender, args) => + if (args.Message.Body.AsSpan().SequenceEqual(aRequest)) { - if (args.Message.Body.AsSpan().SequenceEqual(aRequest)) - { - receiveANotifyTask.SetResult(true); - } - }; + receiveANotifyTask.SetResult(true); + } }; + }; - c.StartServer(); + c.StartServer(); - var receiveAFromGlobalMessageReceived = new TaskCompletionSource(); - c.IpcServerService.MessageReceived += (s, e) => + var receiveAFromGlobalMessageReceived = new TaskCompletionSource(); + c.IpcServerService.MessageReceived += (s, e) => + { + if (e.Message.Body.AsSpan().SequenceEqual(aRequest)) { - if (e.Message.Body.AsSpan().SequenceEqual(aRequest)) - { - receiveAFromGlobalMessageReceived.SetResult(true); - } - }; + receiveAFromGlobalMessageReceived.SetResult(true); + } + }; - await receiveANotifyTask.Task.WaitTimeout(TimeSpan.FromSeconds(5)); - await notifyTask.WaitTimeout(TimeSpan.FromSeconds(5)); + await receiveANotifyTask.Task.WaitTimeout(TimeSpan.FromSeconds(5)); + await notifyTask.WaitTimeout(TimeSpan.FromSeconds(5)); - // 发送成功 - Assert.AreEqual(true, notifyTask.IsCompleted); - if (receiveANotifyTask.Task.IsCompleted) + // 发送成功 + Assert.AreEqual(true, notifyTask.IsCompleted); + if (receiveANotifyTask.Task.IsCompleted) + { + // 和平,能收到重新连接发过来的消息 + } + else + { + if (receiveAFromGlobalMessageReceived.Task.IsCompleted) { - // 和平,能收到重新连接发过来的消息 + // 如果被全局收了,那也是预期的,因为连接过来之后,立刻收到消息,此时的 e.Peer.MessageReceived+=xx 的代码还没跑 } else { - if (receiveAFromGlobalMessageReceived.Task.IsCompleted) - { - // 如果被全局收了,那也是预期的,因为连接过来之后,立刻收到消息,此时的 e.Peer.MessageReceived+=xx 的代码还没跑 - } - else - { - Assert.Fail("没有收到重连的消息"); - } + Assert.Fail("没有收到重连的消息"); } - }); + } } - [ContractTestCase] - public void GetResponseAsync() + [TestMethod("向对方请求响应,可以拿到对方的回复")] + public async Task GetResponseAsync() { - "向对方请求响应,可以拿到对方的回复".Test(async () => - { - var name = "B_PeerReconnected_GetResponseAsync"; - var aRequest = new byte[] { 0xF1 }; - var bResponse = new byte[] { 0xF1, 0xF2 }; + var name = "B_PeerReconnected_GetResponseAsync"; + var aRequest = new byte[] { 0xF1 }; + var bResponse = new byte[] { 0xF1, 0xF2 }; - var a = new IpcProvider("A_PeerReconnected_GetResponseAsync"); - var b = new IpcProvider(name, new IpcConfiguration() - { - DefaultIpcRequestHandler = new DelegateIpcRequestHandler(context => - new IpcHandleRequestMessageResult(new IpcMessage("B回复", bResponse))) - }); + var a = new IpcProvider("A_PeerReconnected_GetResponseAsync"); + var b = new IpcProvider(name, new IpcConfiguration() + { + DefaultIpcRequestHandler = new DelegateIpcRequestHandler(context => + new IpcHandleRequestMessageResult(new IpcMessage("B回复", bResponse))) + }); - a.StartServer(); - b.StartServer(); + a.StartServer(); + b.StartServer(); - var peer = await a.GetAndConnectToPeerAsync(name); - var request1 = await peer.GetResponseAsync(new IpcMessage("A发送", aRequest)); - Assert.AreEqual(true, bResponse.AsSpan().SequenceEqual(request1.Body.AsSpan())); + var peer = await a.GetAndConnectToPeerAsync(name); + var request1 = await peer.GetResponseAsync(new IpcMessage("A发送", aRequest)); + Assert.AreEqual(true, bResponse.AsSpan().SequenceEqual(request1.Body.AsSpan())); - // 多次发送消息测试一下 - var request2 = await peer.GetResponseAsync(new IpcMessage("A发送", aRequest)); - Assert.AreEqual(true, bResponse.AsSpan().SequenceEqual(request2.Body.AsSpan())); - }); + // 多次发送消息测试一下 + var request2 = await peer.GetResponseAsync(new IpcMessage("A发送", aRequest)); + Assert.AreEqual(true, bResponse.AsSpan().SequenceEqual(request2.Body.AsSpan())); } - [ContractTestCase] - public void PeerReconnected() + [TestMethod("连接过程中,对方断掉重连,可以收到重连事件")] + public async Task PeerReconnected() { - "连接过程中,对方断掉重连,可以收到重连事件".Test(async () => - { - var name = "B_PeerReconnected_Main"; - var a = new IpcProvider("A_PeerReconnected_Main", new IpcConfiguration() - { - AutoReconnectPeers = true - }); - var b = new IpcProvider(name); + var name = "B_PeerReconnected_Main"; + var a = new IpcProvider("A_PeerReconnected_Main", new IpcConfiguration() { AutoReconnectPeers = true }); + var b = new IpcProvider(name); - a.StartServer(); - b.StartServer(); + a.StartServer(); + b.StartServer(); - var peer = await a.GetAndConnectToPeerAsync(name); - var peerReconnectedTask = new TaskCompletionSource(); - peer.PeerReconnected += delegate - { - peerReconnectedTask.SetResult(true); - }; + var peer = await a.GetAndConnectToPeerAsync(name); + var peerReconnectedTask = new TaskCompletionSource(); + peer.PeerReconnected += delegate + { + peerReconnectedTask.SetResult(true); + }; - // 断开 b 此时只会收到断开消息,不会收到重连消息 - b.Dispose(); + // 断开 b 此时只会收到断开消息,不会收到重连消息 + b.Dispose(); - // 等待2秒,预计此时是不会收到重新连接消息,也就是 peerReconnectedTask 任务还没完成 - await Task.Delay(TimeSpan.FromSeconds(2)); - // 判断此时是否收到重连消息 - Assert.AreEqual(false, peerReconnectedTask.Task.IsCompleted, "还没有重启 b 服务,但是已收到重连消息"); + // 等待2秒,预计此时是不会收到重新连接消息,也就是 peerReconnectedTask 任务还没完成 + await Task.Delay(TimeSpan.FromSeconds(2)); + // 判断此时是否收到重连消息 + Assert.AreEqual(false, peerReconnectedTask.Task.IsCompleted, "还没有重启 b 服务,但是已收到重连消息"); - // 重新启动 b 服务,用法是再新建一个 c 用了 b 的 name 从而假装是 b 重启 - var c = new IpcProvider(name); - c.StartServer(); + // 重新启动 b 服务,用法是再新建一个 c 用了 b 的 name 从而假装是 b 重启 + var c = new IpcProvider(name); + c.StartServer(); - // 多线程,需要等待一下,等待连接 - await peerReconnectedTask.Task.WaitTimeout(TimeSpan.FromSeconds(3)); + // 多线程,需要等待一下,等待连接 + await peerReconnectedTask.Task.WaitTimeout(TimeSpan.FromSeconds(3)); - Assert.AreEqual(true, peerReconnectedTask.Task.IsCompleted); - Assert.AreEqual(true, peerReconnectedTask.Task.Result); + Assert.AreEqual(true, peerReconnectedTask.Task.IsCompleted); + Assert.AreEqual(true, peerReconnectedTask.Task.Result); - Assert.AreEqual(true, peer.IsConnectedFinished); - Assert.AreEqual(false, peer.IsBroken); - }); + Assert.AreEqual(true, peer.IsConnectedFinished); + Assert.AreEqual(false, peer.IsBroken); } - [ContractTestCase] - public void PeerConnectionBroken() + [TestMethod("发送请求响应,对方断掉,请求将会抛出异常")] + public async Task PeerConnectionBroken1() { - "发送请求响应,对方断掉,请求将会抛出异常".Test(async () => - { - var name = "B_BreakAllRequestTaskByIpcBroken"; - var aRequest = new byte[] { 0xF2 }; - var asyncManualResetEvent = new AsyncManualResetEvent(false); - var a = new IpcProvider("A_BreakAllRequestTaskByIpcBroken"); - var b = new IpcProvider(name, - new IpcConfiguration() - { - DefaultIpcRequestHandler = new DelegateIpcRequestHandler(context => - Task.Run(async () => - { - await asyncManualResetEvent.WaitOneAsync(); - return (IIpcResponseMessage) null; - })) - }); - - a.StartServer(); - b.StartServer(); - - var peer = await a.GetAndConnectToPeerAsync(name); - - // 发送请求,预期这些请求都没有收到回复 - var taskList = new List>(); - for (int i = 0; i < 10; i++) + var name = "B_BreakAllRequestTaskByIpcBroken"; + var aRequest = new byte[] { 0xF2 }; + var asyncManualResetEvent = new AsyncManualResetEvent(false); + var a = new IpcProvider("A_BreakAllRequestTaskByIpcBroken"); + var b = new IpcProvider(name, + new IpcConfiguration() { - Task responseTask = peer.GetResponseAsync(new IpcMessage("A发送", aRequest)); - taskList.Add(responseTask); - } + DefaultIpcRequestHandler = new DelegateIpcRequestHandler(context => + Task.Run(async () => + { + await asyncManualResetEvent.WaitOneAsync(); + return (IIpcResponseMessage) null; + })) + }); - await Task.Yield(); + a.StartServer(); + b.StartServer(); - foreach (var task in taskList) - { - Assert.AreEqual(false, task.IsCompleted); - } + var peer = await a.GetAndConnectToPeerAsync(name); - // 让消息写入一下 - await Task.Delay(TimeSpan.FromSeconds(2)); + // 发送请求,预期这些请求都没有收到回复 + var taskList = new List>(); + for (int i = 0; i < 10; i++) + { + Task responseTask = peer.GetResponseAsync(new IpcMessage("A发送", aRequest)); + taskList.Add(responseTask); + } - b.Dispose(); + await Task.Yield(); - // 等待断开 - await Task.Delay(TimeSpan.FromSeconds(5)); - foreach (var task in taskList) - { - Assert.AreEqual(true, task.IsCompleted); + foreach (var task in taskList) + { + Assert.AreEqual(false, task.IsCompleted); + } - // 这里的异常也许是 连接断开异常, 也许是写入过程中,对方已断开异常 - Assert.IsNotNull(task.Exception?.InnerExceptions[0] as Exception); - } + // 让消息写入一下 + await Task.Delay(TimeSpan.FromSeconds(2)); - // 所有请求都炸掉 - Assert.AreEqual(0, peer.IpcMessageRequestManager.WaitingResponseCount); - }); + b.Dispose(); - "连接过程中,对方断掉,可以收到对方断掉的消息".Test(async () => + // 等待断开 + await Task.Delay(TimeSpan.FromSeconds(5)); + foreach (var task in taskList) { - // 让 a 去连接 b 然后聊聊天 - // 接着将 b 结束,此时 a 的 peer 将会断开连接 - var name = "B_PeerConnectionBroken_PeerConnectionBroken"; - var aRequest = new byte[] { 0xF1 }; - var bResponse = new byte[] { 0xF1, 0xF2 }; - - var a = new IpcProvider("A_PeerConnectionBroken_PeerConnectionBroken"); - var b = new IpcProvider(name, - new IpcConfiguration() - { - DefaultIpcRequestHandler = new DelegateIpcRequestHandler(context => - new IpcHandleRequestMessageResult(new IpcMessage("B回复", bResponse))) - }); + Assert.AreEqual(true, task.IsCompleted); + + // 这里的异常也许是 连接断开异常, 也许是写入过程中,对方已断开异常 + Assert.IsNotNull(task.Exception?.InnerExceptions[0] as Exception); + } + + // 所有请求都炸掉 + Assert.AreEqual(0, peer.IpcMessageRequestManager.WaitingResponseCount); + } + + [TestMethod("连接过程中,对方断掉,可以收到对方断掉的消息")] + public async Task PeerConnectionBroken2() + { + // 让 a 去连接 b 然后聊聊天 + // 接着将 b 结束,此时 a 的 peer 将会断开连接 + var name = "B_PeerConnectionBroken_PeerConnectionBroken"; + var aRequest = new byte[] { 0xF1 }; + var bResponse = new byte[] { 0xF1, 0xF2 }; + + var a = new IpcProvider("A_PeerConnectionBroken_PeerConnectionBroken"); + var b = new IpcProvider(name, + new IpcConfiguration() + { + DefaultIpcRequestHandler = new DelegateIpcRequestHandler(context => + new IpcHandleRequestMessageResult(new IpcMessage("B回复", bResponse))) + }); - a.StartServer(); - b.StartServer(); + a.StartServer(); + b.StartServer(); - var peer = await a.GetAndConnectToPeerAsync(name); - var request1 = await peer.GetResponseAsync(new IpcMessage("A发送", aRequest)); - Assert.AreEqual(true, bResponse.AsSpan().SequenceEqual(request1.Body.AsSpan())); - await Task.Yield(); + var peer = await a.GetAndConnectToPeerAsync(name); + var request1 = await peer.GetResponseAsync(new IpcMessage("A发送", aRequest)); + Assert.AreEqual(true, bResponse.AsSpan().SequenceEqual(request1.Body.AsSpan())); + await Task.Yield(); - var peerBrokenTask = new TaskCompletionSource(); - peer.PeerConnectionBroken += delegate { peerBrokenTask.TrySetResult(true); }; + var peerBrokenTask = new TaskCompletionSource(); + peer.PeerConnectionBroken += delegate { peerBrokenTask.TrySetResult(true); }; - b.Dispose(); + b.Dispose(); - // 预期 b 结束时,能收到 PeerConnectionBroken 事件 - await Task.WhenAny(peerBrokenTask.Task, Task.Delay(TimeSpan.FromSeconds(2))); + // 预期 b 结束时,能收到 PeerConnectionBroken 事件 + await Task.WhenAny(peerBrokenTask.Task, Task.Delay(TimeSpan.FromSeconds(2))); - if (!peerBrokenTask.Task.IsCompleted) - { + if (!peerBrokenTask.Task.IsCompleted) + { #if DEBUG - // 进入断点,也许上面的时间太短 - await Task.WhenAny(peerBrokenTask.Task, Task.Delay(TimeSpan.FromMinutes(5))); + // 进入断点,也许上面的时间太短 + await Task.WhenAny(peerBrokenTask.Task, Task.Delay(TimeSpan.FromMinutes(5))); #endif - } + } - // 判断是否能收到对方断开的消息 - Assert.AreEqual(true, peerBrokenTask.Task.IsCompleted); - Assert.AreEqual(true, peerBrokenTask.Task.Result); + // 判断是否能收到对方断开的消息 + Assert.AreEqual(true, peerBrokenTask.Task.IsCompleted); + Assert.AreEqual(true, peerBrokenTask.Task.Result); - Assert.AreEqual(true, peer.IsBroken); - }); + Assert.AreEqual(true, peer.IsBroken); } - [ContractTestCase] - public void Dispose() + [TestMethod("使用释放的服务发送消息,将会提示对象释放")] + public async Task Dispose1() { - "使用释放的服务发送消息,将会提示对象释放".Test(async () => - { - var name = "B_PeerConnectionBroken_Dispose"; + var name = "B_PeerConnectionBroken_Dispose"; - var aRequest = new byte[] { 0xF1 }; - var a = new IpcProvider("A_PeerConnectionBroken_Dispose", new IpcConfiguration() - { - AutoReconnectPeers = true - }); - var b = new IpcProvider(name); + var aRequest = new byte[] { 0xF1 }; + var a = new IpcProvider("A_PeerConnectionBroken_Dispose", new IpcConfiguration() { AutoReconnectPeers = true }); + var b = new IpcProvider(name); - a.StartServer(); - b.StartServer(); + a.StartServer(); + b.StartServer(); - var peer = await a.GetAndConnectToPeerAsync(name); + var peer = await a.GetAndConnectToPeerAsync(name); - // 设置为自动重连的服务,释放 - a.Dispose(); + // 设置为自动重连的服务,释放 + a.Dispose(); - // 等待资源的释放 - await Task.Delay(TimeSpan.FromSeconds(2)); + // 等待资源的释放 + await Task.Delay(TimeSpan.FromSeconds(2)); - await Assert.ThrowsExceptionAsync(async () => - { - await peer.NotifyAsync(new IpcMessage("A发送", aRequest)); - }); + await Assert.ThrowsExceptionAsync(async () => + { + await peer.NotifyAsync(new IpcMessage("A发送", aRequest)); }); + } - "设置为自动重连的服务,释放之后,不会有任何资源进入等待".Test(async () => - { - var name = "B_PeerConnectionBroken_Dispose2"; + [TestMethod("设置为自动重连的服务,释放之后,不会有任何资源进入等待")] + public async Task Dispose() + { + var name = "B_PeerConnectionBroken_Dispose2"; - var a = new IpcProvider("A_PeerConnectionBroken_Dispose2", new IpcConfiguration() - { - AutoReconnectPeers = true - }); - var b = new IpcProvider(name); + var a = new IpcProvider("A_PeerConnectionBroken_Dispose2", new IpcConfiguration() { AutoReconnectPeers = true }); + var b = new IpcProvider(name); - a.StartServer(); - b.StartServer(); + a.StartServer(); + b.StartServer(); - var peer = await a.GetAndConnectToPeerAsync(name); + var peer = await a.GetAndConnectToPeerAsync(name); - // 设置为自动重连的服务,释放 - a.Dispose(); + // 设置为自动重连的服务,释放 + a.Dispose(); - // 等待资源的释放 - await Task.WhenAny(peer.WaitForFinishedTaskCompletionSource.Task, Task.Delay(TimeSpan.FromSeconds(10))); + // 等待资源的释放 + await Task.WhenAny(peer.WaitForFinishedTaskCompletionSource.Task, Task.Delay(TimeSpan.FromSeconds(10))); - Assert.AreEqual(true, peer.IsBroken); - Assert.AreEqual(true, peer.WaitForFinishedTaskCompletionSource.Task.IsCompleted); - }); + Assert.AreEqual(true, peer.IsBroken); + Assert.AreEqual(true, peer.WaitForFinishedTaskCompletionSource.Task.IsCompleted); } } } diff --git a/tests/dotnetCampus.Ipc.Tests/PeerReConnectorTest.cs b/tests/dotnetCampus.Ipc.Tests/PeerReConnectorTest.cs index 0dc7cc10..6cfed540 100644 --- a/tests/dotnetCampus.Ipc.Tests/PeerReConnectorTest.cs +++ b/tests/dotnetCampus.Ipc.Tests/PeerReConnectorTest.cs @@ -1,6 +1,4 @@ -using System; -using System.Threading.Tasks; -using dotnetCampus.Ipc.Context; +using dotnetCampus.Ipc.Context; using dotnetCampus.Ipc.Internals; using dotnetCampus.Ipc.Messages; using dotnetCampus.Ipc.Pipes; @@ -8,306 +6,289 @@ using dotnetCampus.Ipc.Threading; using Microsoft.VisualStudio.TestTools.UnitTesting; -using MSTest.Extensions.Contracts; - namespace dotnetCampus.Ipc.Tests { [TestClass] public class PeerReConnectorTest { - [ContractTestCase] - public void IpcClientPipeConnectorTest() + [TestMethod("设置自动重新连接,但是重新连接器里面永远返回不继续连接。在对方结束之后,重新再开始,可以被重复连接")] + public async Task IpcClientPipeConnectorTest() { - "设置自动重新连接,但是重新连接器里面永远返回不继续连接。在对方结束之后,重新再开始,可以被重复连接".Test(async () => + // 先启动 a 和 b 两个 + // 让 b 主动连接 a 然后聊聊天 + // 接着将 b 结束,此时 a 的 peer 将会断开连接 + // 然后启动 c 让 c 用原本 b 的 name 从而假装是 b 重新再开始 + // 让 c 主动连接 a 然后聊聊天 + // 预期可以让 a 获取到 c 的连接事件 + + var aName = "A_PeerConnectorTest_02"; + var bName = "B_PeerConnectorTest_02"; + var aResponse = new byte[] { 0xF1, 0xF3 }; + var bRequest = new byte[] { 0xF1, 0xF2, 0xF3 }; + var cRequest = new byte[] { 0x01, 0x05, 0xF3 }; + + var a = new IpcProvider(aName, new IpcConfiguration() { - // 先启动 a 和 b 两个 - // 让 b 主动连接 a 然后聊聊天 - // 接着将 b 结束,此时 a 的 peer 将会断开连接 - // 然后启动 c 让 c 用原本 b 的 name 从而假装是 b 重新再开始 - // 让 c 主动连接 a 然后聊聊天 - // 预期可以让 a 获取到 c 的连接事件 - - var aName = "A_PeerConnectorTest_02"; - var bName = "B_PeerConnectorTest_02"; - var aResponse = new byte[] { 0xF1, 0xF3 }; - var bRequest = new byte[] { 0xF1, 0xF2, 0xF3 }; - var cRequest = new byte[] { 0x01, 0x05, 0xF3 }; - - var a = new IpcProvider(aName, new IpcConfiguration() - { - AutoReconnectPeers = true, // 设置自动重新连接 - // 但是重新连接器里面永远返回不继续连接 - IpcClientPipeConnector = - new IpcClientPipeConnector(context => false, - // 设置每一步都是快速超时 - stepTimeout: TimeSpan.FromMilliseconds(100)), - - DefaultIpcRequestHandler = new DelegateIpcRequestHandler(context => + AutoReconnectPeers = true, // 设置自动重新连接 + // 但是重新连接器里面永远返回不继续连接 + IpcClientPipeConnector = + new IpcClientPipeConnector(context => false, + // 设置每一步都是快速超时 + stepTimeout: TimeSpan.FromMilliseconds(100)), + DefaultIpcRequestHandler = new DelegateIpcRequestHandler(context => new IpcHandleRequestMessageResult(new IpcMessage("B回复", aResponse))), - IpcTaskScheduling = IpcTaskScheduling.LocalOneByOne, - }); - - var connectCount = 0; - var peerBrokenTask = new TaskCompletionSource(); - a.PeerConnected += (sender, args) => - { - connectCount++; + IpcTaskScheduling = IpcTaskScheduling.LocalOneByOne, + }); - args.Peer.PeerConnectionBroken += (o, brokenArgs) => - { - peerBrokenTask.TrySetResult(true); - }; - }; + var connectCount = 0; + var peerBrokenTask = new TaskCompletionSource(); + a.PeerConnected += (sender, args) => + { + connectCount++; - var b = new IpcProvider(bName, new IpcConfiguration() + args.Peer.PeerConnectionBroken += (o, brokenArgs) => { - AutoReconnectPeers = true, // 设置自动重新连接 - // 但是重新连接器里面永远返回不继续连接 - IpcClientPipeConnector = new IpcClientPipeConnector(context => false), + peerBrokenTask.TrySetResult(true); + }; + }; - IpcTaskScheduling = IpcTaskScheduling.LocalOneByOne, - }); + var b = new IpcProvider(bName, new IpcConfiguration() + { + AutoReconnectPeers = true, // 设置自动重新连接 + // 但是重新连接器里面永远返回不继续连接 + IpcClientPipeConnector = new IpcClientPipeConnector(context => false), + IpcTaskScheduling = IpcTaskScheduling.LocalOneByOne, + }); - a.StartServer(); - b.StartServer(); + a.StartServer(); + b.StartServer(); - // 让 b 主动连接 a 然后聊聊天 - var peer1 = await b.GetOrCreatePeerProxyAsync(aName); - var request1 = await peer1.GetResponseAsync(new IpcMessage("Test", bRequest)); - Assert.AreEqual(true, aResponse.AsSpan().SequenceEqual(request1.Body.AsSpan())); - await Task.Yield(); + // 让 b 主动连接 a 然后聊聊天 + var peer1 = await b.GetOrCreatePeerProxyAsync(aName); + var request1 = await peer1.GetResponseAsync(new IpcMessage("Test", bRequest)); + Assert.AreEqual(true, aResponse.AsSpan().SequenceEqual(request1.Body.AsSpan())); + await Task.Yield(); - // 能收到一次连接。这是预期的 - Assert.AreEqual(1, connectCount); + // 能收到一次连接。这是预期的 + Assert.AreEqual(1, connectCount); - var peerReconnectedCount = 0; - peer1.PeerReconnected += (sender, args) => - { - peerReconnectedCount++; - }; + var peerReconnectedCount = 0; + peer1.PeerReconnected += (sender, args) => + { + peerReconnectedCount++; + }; - // 将 b 结束,此时 a 的 peer 将会断开连接 - b.Dispose(); + // 将 b 结束,此时 a 的 peer 将会断开连接 + b.Dispose(); - // 预期 b 结束时,能收到 PeerConnectionBroken 事件 - await Task.WhenAny(peerBrokenTask.Task, Task.Delay(TimeSpan.FromSeconds(2))); - if (!peerBrokenTask.Task.IsCompleted) - { + // 预期 b 结束时,能收到 PeerConnectionBroken 事件 + await Task.WhenAny(peerBrokenTask.Task, Task.Delay(TimeSpan.FromSeconds(2))); + if (!peerBrokenTask.Task.IsCompleted) + { #if DEBUG - // 进入断点,也许上面的时间太短 - await Task.WhenAny(peerBrokenTask.Task, Task.Delay(TimeSpan.FromMinutes(5))); + // 进入断点,也许上面的时间太短 + await Task.WhenAny(peerBrokenTask.Task, Task.Delay(TimeSpan.FromMinutes(5))); #endif - } - // 判断是否能收到对方断开的消息 - Assert.AreEqual(true, peerBrokenTask.Task.IsCompleted); - Assert.AreEqual(true, peerBrokenTask.Task.Result); - - // 等待重新连接失败 - await Task.Delay(TimeSpan.FromSeconds(5)); + } + // 判断是否能收到对方断开的消息 + Assert.AreEqual(true, peerBrokenTask.Task.IsCompleted); + Assert.AreEqual(true, peerBrokenTask.Task.Result); - // 确定 b 断开,再启动 c 去主动连接 - var c = new IpcProvider(bName, new IpcConfiguration() - { - AutoReconnectPeers = true, // 设置自动重新连接 - // 但是重新连接器里面永远返回不继续连接 - IpcClientPipeConnector = new IpcClientPipeConnector(context => false), + // 等待重新连接失败 + await Task.Delay(TimeSpan.FromSeconds(5)); - IpcTaskScheduling = IpcTaskScheduling.LocalOneByOne, - }); - c.StartServer(); - - // 启动 c 去主动连接 - var peer2 = await c.GetOrCreatePeerProxyAsync(aName); - // 发送一条请求获取响应,可以证明连接到符合预期的。同时也等待对方完成连接 - var request2 = await peer2.GetResponseAsync(new IpcMessage("Test", cRequest)); - Assert.AreEqual(true, aResponse.AsSpan().SequenceEqual(request2.Body.AsSpan())); - - // 可以被重复连接 - // 也就是会被连接两次 - // 不存在被重复连接 - Assert.AreEqual(2, connectCount); - Assert.AreEqual(0, peerReconnectedCount); + // 确定 b 断开,再启动 c 去主动连接 + var c = new IpcProvider(bName, new IpcConfiguration() + { + AutoReconnectPeers = true, // 设置自动重新连接 + // 但是重新连接器里面永远返回不继续连接 + IpcClientPipeConnector = new IpcClientPipeConnector(context => false), + IpcTaskScheduling = IpcTaskScheduling.LocalOneByOne, }); + c.StartServer(); + + // 启动 c 去主动连接 + var peer2 = await c.GetOrCreatePeerProxyAsync(aName); + // 发送一条请求获取响应,可以证明连接到符合预期的。同时也等待对方完成连接 + var request2 = await peer2.GetResponseAsync(new IpcMessage("Test", cRequest)); + Assert.AreEqual(true, aResponse.AsSpan().SequenceEqual(request2.Body.AsSpan())); + + // 可以被重复连接 + // 也就是会被连接两次 + // 不存在被重复连接 + Assert.AreEqual(2, connectCount); + Assert.AreEqual(0, peerReconnectedCount); } - [ContractTestCase] - public void Connect() + [TestMethod("不自动重新连接,对方结束之后,重新再开始,可以被重复连接")] + public async Task Connect() { - "不自动重新连接,对方结束之后,重新再开始,可以被重复连接".Test(async () => + // 先启动 a 和 b 两个 + // 让 b 主动连接 a 然后聊聊天 + // 接着将 b 结束,此时 a 的 peer 将会断开连接 + // 然后启动 c 让 c 用原本 b 的 name 从而假装是 b 重新再开始 + // 让 c 主动连接 a 然后聊聊天 + // 预期可以让 a 获取到 c 的连接事件 + + var aName = "A_PeerConnectorTest_01"; + var bName = "B_PeerConnectorTest_01"; + var aResponse = new byte[] { 0xF1, 0xF3 }; + var bRequest = new byte[] { 0xF1, 0xF2, 0xF3 }; + var cRequest = new byte[] { 0x01, 0x05, 0xF3 }; + + var a = new IpcProvider(aName, new IpcConfiguration() { - // 先启动 a 和 b 两个 - // 让 b 主动连接 a 然后聊聊天 - // 接着将 b 结束,此时 a 的 peer 将会断开连接 - // 然后启动 c 让 c 用原本 b 的 name 从而假装是 b 重新再开始 - // 让 c 主动连接 a 然后聊聊天 - // 预期可以让 a 获取到 c 的连接事件 - - var aName = "A_PeerConnectorTest_01"; - var bName = "B_PeerConnectorTest_01"; - var aResponse = new byte[] { 0xF1, 0xF3 }; - var bRequest = new byte[] { 0xF1, 0xF2, 0xF3 }; - var cRequest = new byte[] { 0x01, 0x05, 0xF3 }; - - var a = new IpcProvider(aName, new IpcConfiguration() - { - AutoReconnectPeers = false, // 不自动重新连接 - DefaultIpcRequestHandler = new DelegateIpcRequestHandler(context => + AutoReconnectPeers = false, // 不自动重新连接 + DefaultIpcRequestHandler = new DelegateIpcRequestHandler(context => new IpcHandleRequestMessageResult(new IpcMessage("B回复", aResponse))), - IpcTaskScheduling = IpcTaskScheduling.LocalOneByOne, - }); + IpcTaskScheduling = IpcTaskScheduling.LocalOneByOne, + }); - var connectCount = 0; - var peerBrokenTask = new TaskCompletionSource(); - a.PeerConnected += (sender, args) => - { - connectCount++; + var connectCount = 0; + var peerBrokenTask = new TaskCompletionSource(); + a.PeerConnected += (sender, args) => + { + connectCount++; - args.Peer.PeerConnectionBroken += (o, brokenArgs) => - { - peerBrokenTask.TrySetResult(true); - }; + args.Peer.PeerConnectionBroken += (o, brokenArgs) => + { + peerBrokenTask.TrySetResult(true); }; + }; - var b = new IpcProvider(bName, new IpcConfiguration() - { - AutoReconnectPeers = false, // 不自动重新连接 - IpcTaskScheduling = IpcTaskScheduling.LocalOneByOne, - }); + var b = new IpcProvider(bName, new IpcConfiguration() + { + AutoReconnectPeers = false, // 不自动重新连接 + IpcTaskScheduling = IpcTaskScheduling.LocalOneByOne, + }); - a.StartServer(); - b.StartServer(); + a.StartServer(); + b.StartServer(); - // 让 b 主动连接 a 然后聊聊天 - var peer1 = await b.GetOrCreatePeerProxyAsync(aName); - var request1 = await peer1.GetResponseAsync(new IpcMessage("Test", bRequest)); - Assert.AreEqual(true, aResponse.AsSpan().SequenceEqual(request1.Body.AsSpan())); - await Task.Yield(); + // 让 b 主动连接 a 然后聊聊天 + var peer1 = await b.GetOrCreatePeerProxyAsync(aName); + var request1 = await peer1.GetResponseAsync(new IpcMessage("Test", bRequest)); + Assert.AreEqual(true, aResponse.AsSpan().SequenceEqual(request1.Body.AsSpan())); + await Task.Yield(); - // 能收到一次连接。这是预期的 - Assert.AreEqual(1, connectCount); + // 能收到一次连接。这是预期的 + Assert.AreEqual(1, connectCount); - var peerReconnectedCount = 0; - peer1.PeerReconnected += (sender, args) => - { - peerReconnectedCount++; - }; + var peerReconnectedCount = 0; + peer1.PeerReconnected += (sender, args) => + { + peerReconnectedCount++; + }; - // 将 b 结束,此时 a 的 peer 将会断开连接 - b.Dispose(); + // 将 b 结束,此时 a 的 peer 将会断开连接 + b.Dispose(); - // 预期 b 结束时,能收到 PeerConnectionBroken 事件 - await Task.WhenAny(peerBrokenTask.Task, Task.Delay(TimeSpan.FromSeconds(2))); - if (!peerBrokenTask.Task.IsCompleted) - { + // 预期 b 结束时,能收到 PeerConnectionBroken 事件 + await Task.WhenAny(peerBrokenTask.Task, Task.Delay(TimeSpan.FromSeconds(2))); + if (!peerBrokenTask.Task.IsCompleted) + { #if DEBUG - // 进入断点,也许上面的时间太短 - await Task.WhenAny(peerBrokenTask.Task, Task.Delay(TimeSpan.FromMinutes(5))); + // 进入断点,也许上面的时间太短 + await Task.WhenAny(peerBrokenTask.Task, Task.Delay(TimeSpan.FromMinutes(5))); #endif - } - // 判断是否能收到对方断开的消息 - Assert.AreEqual(true, peerBrokenTask.Task.IsCompleted); - Assert.AreEqual(true, peerBrokenTask.Task.Result); + } + // 判断是否能收到对方断开的消息 + Assert.AreEqual(true, peerBrokenTask.Task.IsCompleted); + Assert.AreEqual(true, peerBrokenTask.Task.Result); - // 确定 b 断开,再启动 c 去主动连接 - var c = new IpcProvider(bName, new IpcConfiguration() - { - AutoReconnectPeers = false, // 不自动重新连接 - IpcTaskScheduling = IpcTaskScheduling.LocalOneByOne, - }); - c.StartServer(); - - // 启动 c 去主动连接 - var peer2 = await c.GetOrCreatePeerProxyAsync(aName); - // 发送一条请求获取响应,可以证明连接到符合预期的。同时也等待对方完成连接 - var request2 = await peer2.GetResponseAsync(new IpcMessage("Test", cRequest)); - Assert.AreEqual(true, aResponse.AsSpan().SequenceEqual(request2.Body.AsSpan())); - - // 可以被重复连接 - // 也就是会被连接两次 - // 不存在被重复连接 - Assert.AreEqual(2, connectCount); - Assert.AreEqual(0, peerReconnectedCount); + // 确定 b 断开,再启动 c 去主动连接 + var c = new IpcProvider(bName, new IpcConfiguration() + { + AutoReconnectPeers = false, // 不自动重新连接 + IpcTaskScheduling = IpcTaskScheduling.LocalOneByOne, }); + c.StartServer(); + + // 启动 c 去主动连接 + var peer2 = await c.GetOrCreatePeerProxyAsync(aName); + // 发送一条请求获取响应,可以证明连接到符合预期的。同时也等待对方完成连接 + var request2 = await peer2.GetResponseAsync(new IpcMessage("Test", cRequest)); + Assert.AreEqual(true, aResponse.AsSpan().SequenceEqual(request2.Body.AsSpan())); + + // 可以被重复连接 + // 也就是会被连接两次 + // 不存在被重复连接 + Assert.AreEqual(2, connectCount); + Assert.AreEqual(0, peerReconnectedCount); } - [ContractTestCase] - public void Reconnect() + [TestMethod("连接过程中,对方断掉,可以自动重新连接对方")] + public async Task Reconnect() { - "连接过程中,对方断掉,可以自动重新连接对方".Test(async () => - { - // 让 a 去连接 b 然后聊聊天 - // 接着将 b 结束,此时 a 的 peer 将会断开连接 - // 然后启动 c 让 c 用原本 b 的 name 从而假装是 b 重启 - // 预期是 a 会重新连接到 "b" 继续聊天 - var name = "B_PeerReConnectorTest"; - var aRequest = new byte[] { 0xF1 }; - var bResponse = new byte[] { 0xF1, 0xF2 }; - var cResponse = new byte[] { 0x01, 0x05 }; - - var a = new IpcProvider("A_PeerReConnectorTest", new IpcConfiguration() + // 让 a 去连接 b 然后聊聊天 + // 接着将 b 结束,此时 a 的 peer 将会断开连接 + // 然后启动 c 让 c 用原本 b 的 name 从而假装是 b 重启 + // 预期是 a 会重新连接到 "b" 继续聊天 + var name = "B_PeerReConnectorTest"; + var aRequest = new byte[] { 0xF1 }; + var bResponse = new byte[] { 0xF1, 0xF2 }; + var cResponse = new byte[] { 0x01, 0x05 }; + + var a = new IpcProvider("A_PeerReConnectorTest", new IpcConfiguration() { AutoReconnectPeers = true }); + var b = new IpcProvider(name, + new IpcConfiguration() { - AutoReconnectPeers = true + DefaultIpcRequestHandler = new DelegateIpcRequestHandler(context => + new IpcHandleRequestMessageResult(new IpcMessage("B回复", bResponse))) }); - var b = new IpcProvider(name, - new IpcConfiguration() - { - DefaultIpcRequestHandler = new DelegateIpcRequestHandler(context => - new IpcHandleRequestMessageResult(new IpcMessage("B回复", bResponse))) - }); - a.StartServer(); - b.StartServer(); + a.StartServer(); + b.StartServer(); - var peer = await a.GetAndConnectToPeerAsync(name); - var request1 = await peer.GetResponseAsync(new IpcMessage("A发送", aRequest)); - Assert.AreEqual(true, bResponse.AsSpan().SequenceEqual(request1.Body.AsSpan())); - await Task.Yield(); + var peer = await a.GetAndConnectToPeerAsync(name); + var request1 = await peer.GetResponseAsync(new IpcMessage("A发送", aRequest)); + Assert.AreEqual(true, bResponse.AsSpan().SequenceEqual(request1.Body.AsSpan())); + await Task.Yield(); - var peerBrokenTask = new TaskCompletionSource(); - peer.PeerConnectionBroken += delegate { peerBrokenTask.TrySetResult(true); }; + var peerBrokenTask = new TaskCompletionSource(); + peer.PeerConnectionBroken += delegate { peerBrokenTask.TrySetResult(true); }; - b.Dispose(); + b.Dispose(); - // 预期 b 结束时,能收到 PeerConnectionBroken 事件 - await Task.WhenAny(peerBrokenTask.Task, Task.Delay(TimeSpan.FromSeconds(2))); + // 预期 b 结束时,能收到 PeerConnectionBroken 事件 + await Task.WhenAny(peerBrokenTask.Task, Task.Delay(TimeSpan.FromSeconds(2))); - if (!peerBrokenTask.Task.IsCompleted) - { + if (!peerBrokenTask.Task.IsCompleted) + { #if DEBUG - // 进入断点,也许上面的时间太短 - await Task.WhenAny(peerBrokenTask.Task, Task.Delay(TimeSpan.FromMinutes(5))); + // 进入断点,也许上面的时间太短 + await Task.WhenAny(peerBrokenTask.Task, Task.Delay(TimeSpan.FromMinutes(5))); #endif - } - - // 判断是否能收到对方断开的消息 - Assert.AreEqual(true, peerBrokenTask.Task.IsCompleted); - Assert.AreEqual(true, peerBrokenTask.Task.Result); - - Assert.AreEqual(true, peer.IsBroken); - Assert.AreEqual(false, peer.WaitForFinishedTaskCompletionSource.Task.IsCompleted); - - // 启动 c 用来假装 b 重启,能让 a 自动用原先的 Peer 连接 - var c = new IpcProvider(name, - new IpcConfiguration() - { - DefaultIpcRequestHandler = new DelegateIpcRequestHandler(context => - new IpcHandleRequestMessageResult(new IpcMessage("C回复", cResponse))) - }); - c.StartServer(); - - // 等待 a 重新连接 - await Task.WhenAny(peer.WaitForFinishedTaskCompletionSource.Task, Task.Delay(TimeSpan.FromSeconds(2))); - if (!peer.WaitForFinishedTaskCompletionSource.Task.IsCompleted) + } + + // 判断是否能收到对方断开的消息 + Assert.AreEqual(true, peerBrokenTask.Task.IsCompleted); + Assert.AreEqual(true, peerBrokenTask.Task.Result); + + Assert.AreEqual(true, peer.IsBroken); + Assert.AreEqual(false, peer.WaitForFinishedTaskCompletionSource.Task.IsCompleted); + + // 启动 c 用来假装 b 重启,能让 a 自动用原先的 Peer 连接 + var c = new IpcProvider(name, + new IpcConfiguration() { + DefaultIpcRequestHandler = new DelegateIpcRequestHandler(context => + new IpcHandleRequestMessageResult(new IpcMessage("C回复", cResponse))) + }); + c.StartServer(); + + // 等待 a 重新连接 + await Task.WhenAny(peer.WaitForFinishedTaskCompletionSource.Task, Task.Delay(TimeSpan.FromSeconds(2))); + if (!peer.WaitForFinishedTaskCompletionSource.Task.IsCompleted) + { #if DEBUG - // 进入断点,也许上面的时间太短 - await Task.WhenAny(peer.WaitForFinishedTaskCompletionSource.Task, Task.Delay(TimeSpan.FromMinutes(2))); + // 进入断点,也许上面的时间太短 + await Task.WhenAny(peer.WaitForFinishedTaskCompletionSource.Task, Task.Delay(TimeSpan.FromMinutes(2))); #endif - } + } - var request2 = await peer.GetResponseAsync(new IpcMessage("A发送", aRequest)); - Assert.AreEqual(true, cResponse.AsSpan().SequenceEqual(request2.Body.AsSpan())); - }); + var request2 = await peer.GetResponseAsync(new IpcMessage("A发送", aRequest)); + Assert.AreEqual(true, cResponse.AsSpan().SequenceEqual(request2.Body.AsSpan())); } } } diff --git a/tests/dotnetCampus.Ipc.Tests/PeerRegisterProviderTests.cs b/tests/dotnetCampus.Ipc.Tests/PeerRegisterProviderTests.cs index b757b3da..1f67b910 100644 --- a/tests/dotnetCampus.Ipc.Tests/PeerRegisterProviderTests.cs +++ b/tests/dotnetCampus.Ipc.Tests/PeerRegisterProviderTests.cs @@ -1,110 +1,105 @@ -using System.IO; - -using dotnetCampus.Ipc.Context; +using dotnetCampus.Ipc.Context; using dotnetCampus.Ipc.Internals; -using dotnetCampus.Ipc.PipeCore; using dotnetCampus.Ipc.Utils.Buffers; using dotnetCampus.Ipc.Utils.IO; using Microsoft.VisualStudio.TestTools.UnitTesting; -using MSTest.Extensions.Contracts; - namespace dotnetCampus.Ipc.Tests { [TestClass] public class PeerRegisterProviderTests { - [ContractTestCase] - public void BuildPeerRegisterMessage() + [TestMethod("如果注册消息的内容添加了其他内容,不会读取到不属于注册消息的内容")] + public void BuildPeerRegisterMessage1() { - "如果注册消息的内容添加了其他内容,不会读取到不属于注册消息的内容".Test(() => - { - // 创建的内容可以序列化 - var peerRegisterProvider = new PeerRegisterProvider(); - var pipeName = "123"; - var bufferMessageContext = peerRegisterProvider.BuildPeerRegisterMessage(pipeName); - var memoryStream = new MemoryStream(bufferMessageContext.Length); + // 创建的内容可以序列化 + var peerRegisterProvider = new PeerRegisterProvider(); + var pipeName = "123"; + var bufferMessageContext = peerRegisterProvider.BuildPeerRegisterMessage(pipeName); + var memoryStream = new MemoryStream(bufferMessageContext.Length); - foreach (var ipcBufferMessage in bufferMessageContext.IpcBufferMessageList) - { - memoryStream.Write(ipcBufferMessage.Buffer, ipcBufferMessage.Start, ipcBufferMessage.Length); - } + foreach (var ipcBufferMessage in bufferMessageContext.IpcBufferMessageList) + { + memoryStream.Write(ipcBufferMessage.Buffer, ipcBufferMessage.Start, ipcBufferMessage.Length); + } - // 写入其他内容 - var streamWriter = new StreamWriter(memoryStream); - streamWriter.Write("林德熙是逗比"); - streamWriter.Flush(); + // 写入其他内容 + var streamWriter = new StreamWriter(memoryStream); + streamWriter.Write("林德熙是逗比"); + streamWriter.Flush(); - memoryStream.Position = 0; + memoryStream.Position = 0; - var success = peerRegisterProvider.TryParsePeerRegisterMessage(memoryStream, out var peerName); + var success = peerRegisterProvider.TryParsePeerRegisterMessage(memoryStream, out var peerName); - Assert.AreEqual(true, success); - Assert.AreEqual(pipeName, peerName); - }); + Assert.AreEqual(true, success); + Assert.AreEqual(pipeName, peerName); + } - "如果消息不是对方的注册消息,那么将不修改Stream的起始".Test(() => - { - var peerRegisterProvider = new PeerRegisterProvider(); - var memoryStream = new MemoryStream(); - for (int i = 0; i < 1000; i++) - { - memoryStream.WriteByte(0x00); - } - - const int position = 10; - memoryStream.Position = position; - var isPeerRegisterMessage = peerRegisterProvider.TryParsePeerRegisterMessage(memoryStream, out _); - Assert.AreEqual(false, isPeerRegisterMessage); - Assert.AreEqual(position, memoryStream.Position); - }); - - "使用发送端之后,能序列化之前的字符串".Test(async () => + [TestMethod("如果消息不是对方的注册消息,那么将不修改Stream的起始")] + public void BuildPeerRegisterMessage2() + { + var peerRegisterProvider = new PeerRegisterProvider(); + var memoryStream = new MemoryStream(); + for (int i = 0; i < 1000; i++) { - var peerRegisterProvider = new PeerRegisterProvider(); - var pipeName = "123"; - var bufferMessageContext = peerRegisterProvider.BuildPeerRegisterMessage(pipeName); - var memoryStream = new MemoryStream(bufferMessageContext.Length); - var ipcConfiguration = new IpcConfiguration(); + memoryStream.WriteByte(0x00); + } + + const int position = 10; + memoryStream.Position = position; + var isPeerRegisterMessage = peerRegisterProvider.TryParsePeerRegisterMessage(memoryStream, out _); + Assert.AreEqual(false, isPeerRegisterMessage); + Assert.AreEqual(position, memoryStream.Position); + } - await IpcMessageConverter.WriteAsync(memoryStream, ipcConfiguration.MessageHeader, ack: 10, - bufferMessageContext, new SharedArrayPool()); + [TestMethod("使用发送端之后,能序列化之前的字符串")] + public async Task BuildPeerRegisterMessage3() + { + var peerRegisterProvider = new PeerRegisterProvider(); + var pipeName = "123"; + var bufferMessageContext = peerRegisterProvider.BuildPeerRegisterMessage(pipeName); + var memoryStream = new MemoryStream(bufferMessageContext.Length); + var ipcConfiguration = new IpcConfiguration(); - memoryStream.Position = 0; - var (success, ipcMessageContext) = (await IpcMessageConverter.ReadAsync(memoryStream, - ipcConfiguration.MessageHeader, new SharedArrayPool())).Result; + await IpcMessageConverter.WriteAsync(memoryStream, ipcConfiguration.MessageHeader, ack: 10, + bufferMessageContext, new SharedArrayPool()); - Assert.AreEqual(true, success); + memoryStream.Position = 0; + var (success, ipcMessageContext) = (await IpcMessageConverter.ReadAsync(memoryStream, + ipcConfiguration.MessageHeader, new SharedArrayPool())).Result; - var stream = new ByteListMessageStream(ipcMessageContext); - success = peerRegisterProvider.TryParsePeerRegisterMessage(stream, out var peerName); + Assert.AreEqual(true, success); - Assert.AreEqual(true, success); + var stream = new ByteListMessageStream(ipcMessageContext); + success = peerRegisterProvider.TryParsePeerRegisterMessage(stream, out var peerName); - Assert.AreEqual(pipeName, peerName); - }); + Assert.AreEqual(true, success); - "创建的注册服务器名内容可以序列化,序列化之后可以反序列化出服务器名".Test(() => - { - // 创建的内容可以序列化 - var peerRegisterProvider = new PeerRegisterProvider(); - var pipeName = "123"; - var bufferMessageContext = peerRegisterProvider.BuildPeerRegisterMessage(pipeName); - var memoryStream = new MemoryStream(bufferMessageContext.Length); + Assert.AreEqual(pipeName, peerName); + } - foreach (var ipcBufferMessage in bufferMessageContext.IpcBufferMessageList) - { - memoryStream.Write(ipcBufferMessage.Buffer, ipcBufferMessage.Start, ipcBufferMessage.Length); - } + [TestMethod("创建的注册服务器名内容可以序列化,序列化之后可以反序列化出服务器名")] + public void BuildPeerRegisterMessage4() + { + // 创建的内容可以序列化 + var peerRegisterProvider = new PeerRegisterProvider(); + var pipeName = "123"; + var bufferMessageContext = peerRegisterProvider.BuildPeerRegisterMessage(pipeName); + var memoryStream = new MemoryStream(bufferMessageContext.Length); + + foreach (var ipcBufferMessage in bufferMessageContext.IpcBufferMessageList) + { + memoryStream.Write(ipcBufferMessage.Buffer, ipcBufferMessage.Start, ipcBufferMessage.Length); + } - memoryStream.Position = 0; + memoryStream.Position = 0; - var success = peerRegisterProvider.TryParsePeerRegisterMessage(memoryStream, out var peerName); + var success = peerRegisterProvider.TryParsePeerRegisterMessage(memoryStream, out var peerName); - Assert.AreEqual(true, success); - Assert.AreEqual(pipeName, peerName); - }); + Assert.AreEqual(true, success); + Assert.AreEqual(pipeName, peerName); } } } diff --git a/tests/dotnetCampus.Ipc.Tests/Pipes/PipeConnectors/IpcClientPipeConnectorTest.cs b/tests/dotnetCampus.Ipc.Tests/Pipes/PipeConnectors/IpcClientPipeConnectorTest.cs index e6ed3089..60b6ba49 100644 --- a/tests/dotnetCampus.Ipc.Tests/Pipes/PipeConnectors/IpcClientPipeConnectorTest.cs +++ b/tests/dotnetCampus.Ipc.Tests/Pipes/PipeConnectors/IpcClientPipeConnectorTest.cs @@ -1,111 +1,100 @@ -using System; -using System.Threading.Tasks; - -using dotnetCampus.Ipc.Context; +using dotnetCampus.Ipc.Context; using dotnetCampus.Ipc.Exceptions; using dotnetCampus.Ipc.Pipes; using dotnetCampus.Ipc.Pipes.PipeConnectors; using dotnetCampus.Threading; using Microsoft.VisualStudio.TestTools.UnitTesting; -using MSTest.Extensions.Contracts; +namespace dotnetCampus.Ipc.Tests.Pipes.PipeConnectors; -namespace dotnetCampus.Ipc.Tests.Pipes.PipeConnectors +[TestClass] +public class IpcClientPipeConnectorTest { - [TestClass] - public class IpcClientPipeConnectorTest + [TestMethod("重连接时,调用 CanContinue 方法返回不支持再次重新连接,则不再次重新连接")] + public async Task ReConnectBreak() { - [ContractTestCase] - public void ReConnectBreak() + int callCanContinueCount = 0; + var asyncAutoResetEvent = new AsyncAutoResetEvent(false); + var ipcConfiguration = new IpcConfiguration() { - "重连接时,调用 CanContinue 方法返回不支持再次重新连接,则不再次重新连接".Test(async () => + AutoReconnectPeers = true, + IpcClientPipeConnector = new IpcClientPipeConnector(c => { - int callCanContinueCount = 0; - var asyncAutoResetEvent = new AsyncAutoResetEvent(false); - var ipcConfiguration = new IpcConfiguration() - { - AutoReconnectPeers = true, - IpcClientPipeConnector = new IpcClientPipeConnector(c => - { - // 调用 CanContinue 方法返回不支持 - callCanContinueCount++; - asyncAutoResetEvent.Set(); - return false; - }, stepTimeout: TimeSpan.FromMilliseconds(100)), - }; + // 调用 CanContinue 方法返回不支持 + callCanContinueCount++; + asyncAutoResetEvent.Set(); + return false; + }, stepTimeout: TimeSpan.FromMilliseconds(100)), + }; - var ipcProviderA = new IpcProvider(Guid.NewGuid().ToString("N"), ipcConfiguration); - var ipcProviderB = new IpcProvider(); - ipcProviderA.StartServer(); - ipcProviderB.StartServer(); + var ipcProviderA = new IpcProvider(Guid.NewGuid().ToString("N"), ipcConfiguration); + var ipcProviderB = new IpcProvider(); + ipcProviderA.StartServer(); + ipcProviderB.StartServer(); - var peer = await ipcProviderA.GetAndConnectToPeerAsync(ipcProviderB.IpcContext.PipeName); - Assert.AreEqual(0, callCanContinueCount); - Assert.IsNotNull(peer); + var peer = await ipcProviderA.GetAndConnectToPeerAsync(ipcProviderB.IpcContext.PipeName); + Assert.AreEqual(0, callCanContinueCount); + Assert.IsNotNull(peer); - // 断开,预期此时将会重新连接 - ipcProviderB.Dispose(); + // 断开,预期此时将会重新连接 + ipcProviderB.Dispose(); - await asyncAutoResetEvent.WaitOneAsync(); - await Task.Delay(TimeSpan.FromSeconds(1)); - Assert.AreEqual(true, peer.IsBroken); - Assert.AreEqual(1, callCanContinueCount); - }); - } + await asyncAutoResetEvent.WaitOneAsync(); + await Task.Delay(TimeSpan.FromSeconds(1)); + Assert.AreEqual(true, peer.IsBroken); + Assert.AreEqual(1, callCanContinueCount); + } - [ContractTestCase] - public void ConnectNamedPipeAsync() + [TestMethod("连接一个不存在的服务,会调用到 CanContinue 方法判断是否可以再次重新连接。如 CanContinue 返回不能继续连接,将抛出连接失败异常")] + public async Task ConnectNamedPipeAsync1() + { + int callCanContinueCount = 0; + var ipcConfiguration = new IpcConfiguration() { - "连接一个不存在的服务,会调用到 CanContinue 方法判断是否可以再次重新连接。如 CanContinue 返回不能继续连接,将抛出连接失败异常".Test(async () => + IpcClientPipeConnector = new IpcClientPipeConnector(c => { - int callCanContinueCount = 0; - var ipcConfiguration = new IpcConfiguration() - { - IpcClientPipeConnector = new IpcClientPipeConnector(c => - { - callCanContinueCount++; - // 第一次返回可以继续连接,预期进来第二次 - return callCanContinueCount == 1; - }, stepTimeout: TimeSpan.FromMilliseconds(100)), - }; + callCanContinueCount++; + // 第一次返回可以继续连接,预期进来第二次 + return callCanContinueCount == 1; + }, stepTimeout: TimeSpan.FromMilliseconds(100)), + }; - var ipcProviderA = new IpcProvider(Guid.NewGuid().ToString("N"), ipcConfiguration); - ipcProviderA.StartServer(); + var ipcProviderA = new IpcProvider(Guid.NewGuid().ToString("N"), ipcConfiguration); + ipcProviderA.StartServer(); - await Assert.ThrowsExceptionAsync(async () => - { - // 连接一个不存在的服务 - var peer = await ipcProviderA.GetAndConnectToPeerAsync("NotExists_" + Guid.NewGuid().ToString("N")); - Assert.IsNull(peer); - }); + await Assert.ThrowsExceptionAsync(async () => + { + // 连接一个不存在的服务 + var peer = await ipcProviderA.GetAndConnectToPeerAsync("NotExists_" + Guid.NewGuid().ToString("N")); + Assert.IsNull(peer); + }); - // 调用两次,第一次返回可以继续连接 - Assert.AreEqual(2, callCanContinueCount); - }); + // 调用两次,第一次返回可以继续连接 + Assert.AreEqual(2, callCanContinueCount); + } - "连接能立刻连上的服务,不会调用到 CanContinue 方法判断是否可以再次重新连接".Test(async () => + [TestMethod("连接能立刻连上的服务,不会调用到 CanContinue 方法判断是否可以再次重新连接")] + public async Task ConnectNamedPipeAsync2() + { + int callCanContinueCount = 0; + var ipcConfiguration = new IpcConfiguration() + { + IpcClientPipeConnector = new IpcClientPipeConnector(c => { - int callCanContinueCount = 0; - var ipcConfiguration = new IpcConfiguration() - { - IpcClientPipeConnector = new IpcClientPipeConnector(c => - { - callCanContinueCount++; - return true; - }), - }; + callCanContinueCount++; + return true; + }), + }; - var ipcProviderA = new IpcProvider(Guid.NewGuid().ToString("N"), ipcConfiguration); - var ipcProviderB = new IpcProvider(); - ipcProviderA.StartServer(); - ipcProviderB.StartServer(); + var ipcProviderA = new IpcProvider(Guid.NewGuid().ToString("N"), ipcConfiguration); + var ipcProviderB = new IpcProvider(); + ipcProviderA.StartServer(); + ipcProviderB.StartServer(); - var peer = await ipcProviderA.GetAndConnectToPeerAsync(ipcProviderB.IpcContext.PipeName); + var peer = await ipcProviderA.GetAndConnectToPeerAsync(ipcProviderB.IpcContext.PipeName); - // 不会调用到 CanContinue 方法判断是否可以再次重新连接 - Assert.AreEqual(0, callCanContinueCount); - Assert.IsNotNull(peer); - }); - } + // 不会调用到 CanContinue 方法判断是否可以再次重新连接 + Assert.AreEqual(0, callCanContinueCount); + Assert.IsNotNull(peer); } } diff --git a/tests/dotnetCampus.Ipc.Tests/ResponseManagerTests.cs b/tests/dotnetCampus.Ipc.Tests/ResponseManagerTests.cs index 05535887..304311c7 100644 --- a/tests/dotnetCampus.Ipc.Tests/ResponseManagerTests.cs +++ b/tests/dotnetCampus.Ipc.Tests/ResponseManagerTests.cs @@ -1,178 +1,159 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Threading.Tasks; - -using dotnetCampus.Ipc.Context; +using dotnetCampus.Ipc.Context; using dotnetCampus.Ipc.Internals; using dotnetCampus.Ipc.Messages; -using dotnetCampus.Ipc.PipeCore; using dotnetCampus.Ipc.Pipes; -using dotnetCampus.Ipc.Utils.Extensions; - using Microsoft.VisualStudio.TestTools.UnitTesting; -using MSTest.Extensions.Contracts; - namespace dotnetCampus.Ipc.Tests { [TestClass] public class ResponseManagerTests { - [ContractTestCase] - public void SendAndGetResponse() + [TestMethod("发送消息到另一个 IPC 服务,可以等待收到对方的返回值")] + public async Task SendAndGetResponse() { - "发送消息到另一个 IPC 服务,可以等待收到对方的返回值".Test(async () => - { - var ipcAName = Guid.NewGuid().ToString("N"); - var ipcBName = Guid.NewGuid().ToString("N"); - var requestByteList = new byte[] { 0xFF, 0xFE }; - var responseByteList = new byte[] { 0xF1, 0xF2 }; + var ipcAName = Guid.NewGuid().ToString("N"); + var ipcBName = Guid.NewGuid().ToString("N"); + var requestByteList = new byte[] { 0xFF, 0xFE }; + var responseByteList = new byte[] { 0xF1, 0xF2 }; - using var ipcA = new IpcProvider(ipcAName); - using var ipcB = new IpcProvider(ipcBName, new IpcConfiguration() + using var ipcA = new IpcProvider(ipcAName); + using var ipcB = new IpcProvider(ipcBName, new IpcConfiguration() + { + DefaultIpcRequestHandler = new DelegateIpcRequestHandler(c => { - DefaultIpcRequestHandler = new DelegateIpcRequestHandler(c => - { - Assert.AreEqual(ipcAName, c.Peer.PeerName); - c.Handled = true; - var span = c.IpcBufferMessage.Body.AsSpan(); - Assert.AreEqual(true, span.SequenceEqual(requestByteList)); - - return new IpcHandleRequestMessageResult(new IpcMessage("Return", - new IpcMessageBody(responseByteList))); - }) - }); - ipcA.StartServer(); - ipcB.StartServer(); - - var bPeer = await ipcA.GetAndConnectToPeerAsync(ipcBName); - // 从 A 发送消息给到 B 然后可以收到从 B 返回的消息 - var response = - await bPeer.GetResponseAsync(new IpcMessage("发送", new IpcMessageBody(requestByteList))); - Assert.AreEqual(true, response.Body.AsSpan().SequenceEqual(responseByteList)); + Assert.AreEqual(ipcAName, c.Peer.PeerName); + c.Handled = true; + var span = c.IpcBufferMessage.Body.AsSpan(); + Assert.AreEqual(true, span.SequenceEqual(requestByteList)); + + return new IpcHandleRequestMessageResult(new IpcMessage("Return", + new IpcMessageBody(responseByteList))); + }) }); + ipcA.StartServer(); + ipcB.StartServer(); + + var bPeer = await ipcA.GetAndConnectToPeerAsync(ipcBName); + // 从 A 发送消息给到 B 然后可以收到从 B 返回的消息 + var response = + await bPeer.GetResponseAsync(new IpcMessage("发送", new IpcMessageBody(requestByteList))); + Assert.AreEqual(true, response.Body.AsSpan().SequenceEqual(responseByteList)); } - [ContractTestCase] - public void GetResponseAsync() + [TestMethod("发送消息之后,能等待收到对应的回复")] + public async Task GetResponseAsync() { - "发送消息之后,能等待收到对应的回复".Test(async () => + var ipcMessageRequestManager = new IpcMessageRequestManager(new IpcProvider().IpcContext); + var requestByteList = new byte[] { 0xFF, 0xFE }; + var request = new IpcMessage("Tests", new IpcMessageBody(requestByteList)); + var ipcClientRequestMessage = ipcMessageRequestManager.CreateRequestMessage(request); + Assert.AreEqual(false, ipcClientRequestMessage.Task.IsCompleted); + + var requestStream = IpcBufferMessageContextToStream(ipcClientRequestMessage.IpcBufferMessageContext); + + IpcClientRequestArgs ipcClientRequestArgs = null; + ipcMessageRequestManager.OnIpcClientRequestReceived += (sender, args) => { - var ipcMessageRequestManager = new IpcMessageRequestManager(new IpcProvider().IpcContext); - var requestByteList = new byte[] { 0xFF, 0xFE }; - var request = new IpcMessage("Tests", new IpcMessageBody(requestByteList)); - var ipcClientRequestMessage = ipcMessageRequestManager.CreateRequestMessage(request); - Assert.AreEqual(false, ipcClientRequestMessage.Task.IsCompleted); + ipcClientRequestArgs = args; + }; + + Assert.IsNotNull(requestStream); + ipcMessageRequestManager.OnReceiveMessage(new PeerStreamMessageArgs(new IpcMessageContext(), "Foo", requestStream, ack: 100, + IpcMessageCommandType.RequestMessage)); + + Assert.IsNotNull(ipcClientRequestArgs); + var responseByteList = new byte[] { 0xF1, 0xF2 }; + var ipcMessageResponseManager = new IpcMessageResponseManager(); + var responseMessageContext = ipcMessageResponseManager.CreateResponseMessage( + ipcClientRequestArgs.MessageId, + new IpcMessage("Tests", new IpcMessageBody(responseByteList))); + var responseStream = IpcBufferMessageContextToStream(responseMessageContext); + ipcMessageRequestManager.OnReceiveMessage(new PeerStreamMessageArgs(new IpcMessageContext(), "Foo", responseStream, ack: 100, + IpcMessageCommandType.ResponseMessage)); + + // 在 OnReceiveMessage 收到消息,不是立刻释放 ipcClientRequestMessage 的,需要调度到线程池进行释放 + await ipcClientRequestMessage.Task.WaitTimeout(TimeSpan.FromSeconds(5)); + Assert.AreEqual(true, ipcClientRequestMessage.Task.IsCompleted); + } + [TestMethod("所有发送消息都收到回复后,将清空等待响应的数量")] + public async Task WaitingResponseCount() + { + // 请求的顺序是 + // A: 生成请求消息 + // A: 发送请求消息 + // B: 收到请求消息 + // B: 生成回复消息 + // B: 发送回复消息 + // A: 收到回复消息 + // A: 完成请求 + var aIpcMessageRequestManager = new IpcMessageRequestManager(new IpcProvider().IpcContext); + var requestByteList = new byte[] { 0xFF, 0xFE }; + var request = new IpcMessage("Tests", new IpcMessageBody(requestByteList)); + + var ipcClientRequestMessageList = new List(); + + for (int i = 0; i < 10; i++) + { + // 创建请求消息 + IpcClientRequestMessage ipcClientRequestMessage = aIpcMessageRequestManager.CreateRequestMessage(request); + ipcClientRequestMessageList.Add(ipcClientRequestMessage); + + Assert.AreEqual(i + 1, aIpcMessageRequestManager.WaitingResponseCount); + } + + // 创建的请求消息还没发送出去,需要进行发送 + // 发送的做法就是往 B 里面调用接收方法 + // 在测试里面不引入 IPC 的发送逻辑,因此 A 的发送就是调用 B 的接收 + var bIpcMessageRequestManager = new IpcMessageRequestManager(new IpcProvider().IpcContext); + var bIpcMessageResponseManager = new IpcMessageResponseManager(); + + // 接收 B 的消息,用的是事件 + var ipcClientRequestArgsList = new List(); + bIpcMessageRequestManager.OnIpcClientRequestReceived += (sender, args) => + { + ipcClientRequestArgsList.Add(args); + }; + + // 开始发送消息 + foreach (var ipcClientRequestMessage in ipcClientRequestMessageList) + { var requestStream = IpcBufferMessageContextToStream(ipcClientRequestMessage.IpcBufferMessageContext); + var args = new PeerStreamMessageArgs(new IpcMessageContext(), "Foo", requestStream, ack: 100, + IpcMessageCommandType.RequestMessage); - IpcClientRequestArgs ipcClientRequestArgs = null; - ipcMessageRequestManager.OnIpcClientRequestReceived += (sender, args) => - { - ipcClientRequestArgs = args; - }; + bIpcMessageRequestManager.OnReceiveMessage(args); + } - Assert.IsNotNull(requestStream); - ipcMessageRequestManager.OnReceiveMessage(new PeerStreamMessageArgs(new IpcMessageContext(), "Foo", requestStream, ack: 100, - IpcMessageCommandType.RequestMessage)); + // 因为 A 发送了 10 条消息,因此 B 需要接收到 10 条 + Assert.AreEqual(ipcClientRequestMessageList.Count, ipcClientRequestArgsList.Count); - Assert.IsNotNull(ipcClientRequestArgs); + // 逐条消息回复 + foreach (var ipcClientRequestArgs in ipcClientRequestArgsList) + { var responseByteList = new byte[] { 0xF1, 0xF2 }; - var ipcMessageResponseManager = new IpcMessageResponseManager(); - var responseMessageContext = ipcMessageResponseManager.CreateResponseMessage( + var responseMessageContext = bIpcMessageResponseManager.CreateResponseMessage( ipcClientRequestArgs.MessageId, new IpcMessage("Tests", new IpcMessageBody(responseByteList))); var responseStream = IpcBufferMessageContextToStream(responseMessageContext); - ipcMessageRequestManager.OnReceiveMessage(new PeerStreamMessageArgs(new IpcMessageContext(), "Foo", responseStream, ack: 100, + + // 回复就是发送消息给 A 相当于让 A 接收消息 + aIpcMessageRequestManager.OnReceiveMessage(new PeerStreamMessageArgs(new IpcMessageContext(), "Foo", responseStream, ack: 100, IpcMessageCommandType.ResponseMessage)); + } - // 在 OnReceiveMessage 收到消息,不是立刻释放 ipcClientRequestMessage 的,需要调度到线程池进行释放 - await ipcClientRequestMessage.Task.WaitTimeout(TimeSpan.FromSeconds(5)); - Assert.AreEqual(true, ipcClientRequestMessage.Task.IsCompleted); - }); - } + // 此时 A 没有等待回复的消息 + Assert.AreEqual(0, aIpcMessageRequestManager.WaitingResponseCount); + // 所有发送的消息都收到回复 - [ContractTestCase] - public void WaitingResponseCount() - { - "所有发送消息都收到回复后,将清空等待响应的数量".Test(async () => + foreach (var ipcClientRequestMessage in ipcClientRequestMessageList) { - // 请求的顺序是 - // A: 生成请求消息 - // A: 发送请求消息 - // B: 收到请求消息 - // B: 生成回复消息 - // B: 发送回复消息 - // A: 收到回复消息 - // A: 完成请求 - var aIpcMessageRequestManager = new IpcMessageRequestManager(new IpcProvider().IpcContext); - var requestByteList = new byte[] { 0xFF, 0xFE }; - var request = new IpcMessage("Tests", new IpcMessageBody(requestByteList)); - - var ipcClientRequestMessageList = new List(); - - for (int i = 0; i < 10; i++) - { - // 创建请求消息 - IpcClientRequestMessage ipcClientRequestMessage = aIpcMessageRequestManager.CreateRequestMessage(request); - ipcClientRequestMessageList.Add(ipcClientRequestMessage); - - Assert.AreEqual(i + 1, aIpcMessageRequestManager.WaitingResponseCount); - } - - // 创建的请求消息还没发送出去,需要进行发送 - // 发送的做法就是往 B 里面调用接收方法 - // 在测试里面不引入 IPC 的发送逻辑,因此 A 的发送就是调用 B 的接收 - var bIpcMessageRequestManager = new IpcMessageRequestManager(new IpcProvider().IpcContext); - var bIpcMessageResponseManager = new IpcMessageResponseManager(); - - // 接收 B 的消息,用的是事件 - var ipcClientRequestArgsList = new List(); - bIpcMessageRequestManager.OnIpcClientRequestReceived += (sender, args) => - { - ipcClientRequestArgsList.Add(args); - }; - - // 开始发送消息 - foreach (var ipcClientRequestMessage in ipcClientRequestMessageList) - { - var requestStream = IpcBufferMessageContextToStream(ipcClientRequestMessage.IpcBufferMessageContext); - var args = new PeerStreamMessageArgs(new IpcMessageContext(), "Foo", requestStream, ack: 100, - IpcMessageCommandType.RequestMessage); - - bIpcMessageRequestManager.OnReceiveMessage(args); - } - - // 因为 A 发送了 10 条消息,因此 B 需要接收到 10 条 - Assert.AreEqual(ipcClientRequestMessageList.Count, ipcClientRequestArgsList.Count); - - // 逐条消息回复 - foreach (var ipcClientRequestArgs in ipcClientRequestArgsList) - { - var responseByteList = new byte[] { 0xF1, 0xF2 }; - var responseMessageContext = bIpcMessageResponseManager.CreateResponseMessage( - ipcClientRequestArgs.MessageId, - new IpcMessage("Tests", new IpcMessageBody(responseByteList))); - var responseStream = IpcBufferMessageContextToStream(responseMessageContext); - - // 回复就是发送消息给 A 相当于让 A 接收消息 - aIpcMessageRequestManager.OnReceiveMessage(new PeerStreamMessageArgs(new IpcMessageContext(), "Foo", responseStream, ack: 100, - IpcMessageCommandType.ResponseMessage)); - } - - // 此时 A 没有等待回复的消息 - Assert.AreEqual(0, aIpcMessageRequestManager.WaitingResponseCount); - // 所有发送的消息都收到回复 - - foreach (var ipcClientRequestMessage in ipcClientRequestMessageList) - { - // 在 OnReceiveMessage 收到消息,不是立刻释放 ipcClientRequestMessage 的,需要调度到线程池进行释放 - await ipcClientRequestMessage.Task.WaitTimeout(); + // 在 OnReceiveMessage 收到消息,不是立刻释放 ipcClientRequestMessage 的,需要调度到线程池进行释放 + await ipcClientRequestMessage.Task.WaitTimeout(); - Assert.AreEqual(true, ipcClientRequestMessage.Task.IsCompleted); - } - }); + Assert.AreEqual(true, ipcClientRequestMessage.Task.IsCompleted); + } } private static MemoryStream IpcBufferMessageContextToStream(IpcBufferMessageContext ipcBufferMessageContext) diff --git a/tests/dotnetCampus.Ipc.Tests/TaskExtension.cs b/tests/dotnetCampus.Ipc.Tests/TaskExtension.cs index 102dc55e..751769db 100644 --- a/tests/dotnetCampus.Ipc.Tests/TaskExtension.cs +++ b/tests/dotnetCampus.Ipc.Tests/TaskExtension.cs @@ -1,7 +1,4 @@ -using System; -using System.Threading.Tasks; - -namespace dotnetCampus.Ipc.Tests +namespace dotnetCampus.Ipc.Tests { static class TaskExtension { diff --git a/tests/dotnetCampus.Ipc.Tests/Threading/IpcThreadPoolTests.cs b/tests/dotnetCampus.Ipc.Tests/Threading/IpcThreadPoolTests.cs index b889c9aa..0bbe4caf 100644 --- a/tests/dotnetCampus.Ipc.Tests/Threading/IpcThreadPoolTests.cs +++ b/tests/dotnetCampus.Ipc.Tests/Threading/IpcThreadPoolTests.cs @@ -1,47 +1,36 @@ using System.Text; -using System.Threading; -using System.Threading.Tasks; -using System.Xml.Linq; using dotnetCampus.Ipc.Context; using dotnetCampus.Ipc.Internals; using dotnetCampus.Ipc.Messages; using dotnetCampus.Ipc.Pipes; -using dotnetCampus.Ipc.Tests.CompilerServices; using Microsoft.VisualStudio.TestTools.UnitTesting; -using MSTest.Extensions.Contracts; namespace dotnetCampus.Ipc.Tests.Threading; [TestClass] public class IpcThreadPoolTests : IIpcRequestHandler { - [ContractTestCase] - public void RunRecursively() + [TestMethod("线程池满,等待新任务调度时,本递归调用不应出现 StackOverflowException。")] + public async Task RunRecursively() { - "线程池满,等待新任务调度时,本递归调用不应出现 StackOverflowException。".Test(async () => - { - var aName = $"IpcObjectTests.IpcTests.IpcThreadPoolTests.{nameof(RunRecursively)}.A"; - var bName = $"IpcObjectTests.IpcTests.IpcThreadPoolTests.{nameof(RunRecursively)}.B"; - var aProvider = new IpcProvider(aName, new IpcConfiguration - { - DefaultIpcRequestHandler = this, - }); - var bProvider = new IpcProvider(bName); - aProvider.StartServer(); - bProvider.StartServer(); - var aPeer = await bProvider.GetAndConnectToPeerAsync(aName); + var aName = $"IpcObjectTests.IpcTests.IpcThreadPoolTests.{nameof(RunRecursively)}.A"; + var bName = $"IpcObjectTests.IpcTests.IpcThreadPoolTests.{nameof(RunRecursively)}.B"; + var aProvider = new IpcProvider(aName, new IpcConfiguration { DefaultIpcRequestHandler = this, }); + var bProvider = new IpcProvider(bName); + aProvider.StartServer(); + bProvider.StartServer(); + var aPeer = await bProvider.GetAndConnectToPeerAsync(aName); - // 占满线程池,以便有机会等待新任务调度。 - var task1 = aPeer.GetResponseAsync(new IpcMessage("Test", Encoding.UTF8.GetBytes("Test"))); - var task2 = aPeer.GetResponseAsync(new IpcMessage("Test", Encoding.UTF8.GetBytes("Test"))); - var task3 = aPeer.GetResponseAsync(new IpcMessage("Test", Encoding.UTF8.GetBytes("Test"))); - var task4 = aPeer.GetResponseAsync(new IpcMessage("Test", Encoding.UTF8.GetBytes("Test"))); - var task5 = aPeer.GetResponseAsync(new IpcMessage("Test", Encoding.UTF8.GetBytes("Test"))); - var task6 = aPeer.GetResponseAsync(new IpcMessage("Test", Encoding.UTF8.GetBytes("Test"))); - var task7 = aPeer.GetResponseAsync(new IpcMessage("Test", Encoding.UTF8.GetBytes("Test"))); + // 占满线程池,以便有机会等待新任务调度。 + var task1 = aPeer.GetResponseAsync(new IpcMessage("Test", Encoding.UTF8.GetBytes("Test"))); + var task2 = aPeer.GetResponseAsync(new IpcMessage("Test", Encoding.UTF8.GetBytes("Test"))); + var task3 = aPeer.GetResponseAsync(new IpcMessage("Test", Encoding.UTF8.GetBytes("Test"))); + var task4 = aPeer.GetResponseAsync(new IpcMessage("Test", Encoding.UTF8.GetBytes("Test"))); + var task5 = aPeer.GetResponseAsync(new IpcMessage("Test", Encoding.UTF8.GetBytes("Test"))); + var task6 = aPeer.GetResponseAsync(new IpcMessage("Test", Encoding.UTF8.GetBytes("Test"))); + var task7 = aPeer.GetResponseAsync(new IpcMessage("Test", Encoding.UTF8.GetBytes("Test"))); - await Task.WhenAll(task1, task2, task3, task4, task5); - }); + await Task.WhenAll(task1, task2, task3, task4, task5); } public Task HandleRequest(IIpcRequestContext requestContext) diff --git a/tests/dotnetCampus.Ipc.Tests/Utils/Extensions/PeerMessageArgsExtensionTest.cs b/tests/dotnetCampus.Ipc.Tests/Utils/Extensions/PeerMessageArgsExtensionTest.cs index bb886e04..1972ecab 100644 --- a/tests/dotnetCampus.Ipc.Tests/Utils/Extensions/PeerMessageArgsExtensionTest.cs +++ b/tests/dotnetCampus.Ipc.Tests/Utils/Extensions/PeerMessageArgsExtensionTest.cs @@ -1,174 +1,170 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Text; +using System.Text; using dotnetCampus.Ipc.Messages; using dotnetCampus.Ipc.Utils.Extensions; using Microsoft.VisualStudio.TestTools.UnitTesting; -using MSTest.Extensions.Contracts; +namespace dotnetCampus.Ipc.Tests.Utils.Extensions; -namespace dotnetCampus.Ipc.Tests.Utils.Extensions +[TestClass] +public class PeerMessageArgsExtensionTest { - [TestClass] - public class PeerMessageArgsExtensionTest + [TestMethod("给定的 IpcMessage 不包含正确 byte 数组的有效负载,获取有效负载失败")] + public void GetPayload1() { - [ContractTestCase] - public void GetPayload() + var header = new byte[] { 0xF1, 0xC1, 0xAA, (byte) 'a' }; + var text = "abc"; + using var memoryStream = new MemoryStream(); + using (var binaryWriter = new BinaryWriter(memoryStream)) { - "给定的 IpcMessage 不包含正确 byte 数组的有效负载,获取有效负载失败".Test(() => - { - var header = new byte[] { 0xF1, 0xC1, 0xAA, (byte) 'a' }; - var text = "abc"; - using var memoryStream = new MemoryStream(); - using (var binaryWriter = new BinaryWriter(memoryStream)) - { - binaryWriter.Write(header); - - // 再写入一些测试数据 - var textByteList = Encoding.UTF8.GetBytes(text); - binaryWriter.Write(textByteList); - } - - var ipcMessage = new IpcMessage("test", new IpcMessageBody(memoryStream.ToArray())); - - // 要求的负载和传入的不相同 - var result = ipcMessage.TryGetPayload(new byte[] { 0xF1, 0xC1, 0xAA, (byte) 'b' }, out var subMessage); - - // 可以成功获取到有效负载 - Assert.AreEqual(false, result); - }); - - "给定的 IpcMessage 存在偏移,但包含正确 byte 数组的有效负载,可以成功获取到有效负载".Test(() => - { - var header = new byte[] { 0xF1, 0xC1, 0xAA, (byte) 'a' }; - var text = "abc"; - using var memoryStream = new MemoryStream(); - using (var binaryWriter = new BinaryWriter(memoryStream)) - { - // 写入一个 byte 垃圾,用于后续测试存在偏移 - binaryWriter.Write((byte) 0); - - binaryWriter.Write(header); - - // 再写入一些测试数据 - var textByteList = Encoding.UTF8.GetBytes(text); - binaryWriter.Write(textByteList); - } - // sizeof(header) + sizeof(text) = 4 + 3 = 7 - var ipcMessage = new IpcMessage("test", new IpcMessageBody(memoryStream.ToArray(), 1, 7)); - - var result = ipcMessage.TryGetPayload(header, out var subMessage); - - // 可以成功获取到有效负载 - Assert.AreEqual(true, result, "没有成功获取到有效负载"); - - var resultText = Encoding.UTF8.GetString(subMessage.Body.Buffer, subMessage.Body.Start, subMessage.Body.Length); - Assert.AreEqual(text, resultText); - }); - - "给定 IpcMessage 包含正确 byte 数组的有效负载,可以成功获取到有效负载".Test(() => - { - var header = new byte[] { 0xF1, 0xC1, 0xAA, (byte) 'a' }; - var text = "abc"; - using var memoryStream = new MemoryStream(); - using (var binaryWriter = new BinaryWriter(memoryStream)) - { - binaryWriter.Write(header); - - // 再写入一些测试数据 - var textByteList = Encoding.UTF8.GetBytes(text); - binaryWriter.Write(textByteList); - } - - var ipcMessage = new IpcMessage("test", new IpcMessageBody(memoryStream.ToArray())); - - var result = ipcMessage.TryGetPayload(header, out var subMessage); - - // 可以成功获取到有效负载 - Assert.AreEqual(true, result, "没有成功获取到有效负载"); - - var resultText = Encoding.UTF8.GetString(subMessage.Body.Buffer, subMessage.Body.Start, subMessage.Body.Length); - Assert.AreEqual(text, resultText); - }); - - "给定的 IpcMessage 不包含正确 ulong 的有效负载,获取有效负载失败".Test(() => - { - ulong header = 0x12312; - var text = "abc"; - using var memoryStream = new MemoryStream(); - using (var binaryWriter = new BinaryWriter(memoryStream)) - { - binaryWriter.Write(header); - - // 再写入一些测试数据 - var textByteList = Encoding.UTF8.GetBytes(text); - binaryWriter.Write(textByteList); - } - - var ipcMessage = new IpcMessage("test", new IpcMessageBody(memoryStream.ToArray())); - - // 要求的负载和传入的不相同 - var result = ipcMessage.TryGetPayload(0xFF, out var subMessage); - - // 可以成功获取到有效负载 - Assert.AreEqual(false, result); - }); - - "给定的 IpcMessage 存在偏移,但包含正确 ulong 的有效负载,可以成功获取到有效负载".Test(() => - { - ulong header = 0x12312; - var text = "abc"; - using var memoryStream = new MemoryStream(); - using (var binaryWriter = new BinaryWriter(memoryStream)) - { - // 写入一个 byte 垃圾,用于后续测试存在偏移 - binaryWriter.Write((byte) 0); - - binaryWriter.Write(header); - - // 再写入一些测试数据 - var textByteList = Encoding.UTF8.GetBytes(text); - binaryWriter.Write(textByteList); - } - // sizeof(ulong) + sizeof(text) = 8 + 3 = 11 - var ipcMessage = new IpcMessage("test", new IpcMessageBody(memoryStream.ToArray(), 1, 11)); - - var result = ipcMessage.TryGetPayload(header, out var subMessage); - - // 可以成功获取到有效负载 - Assert.AreEqual(true, result, "没有成功获取到有效负载"); - - var resultText = Encoding.UTF8.GetString(subMessage.Body.Buffer, subMessage.Body.Start, subMessage.Body.Length); - Assert.AreEqual(text, resultText); - }); - - "给定 IpcMessage 包含正确 ulong 的有效负载,可以成功获取到有效负载".Test(() => - { - ulong header = 0x12312; - var text = "abc"; - using var memoryStream = new MemoryStream(); - using (var binaryWriter = new BinaryWriter(memoryStream)) - { - binaryWriter.Write(header); - - // 再写入一些测试数据 - var textByteList = Encoding.UTF8.GetBytes(text); - binaryWriter.Write(textByteList); - } - - var ipcMessage = new IpcMessage("test", new IpcMessageBody(memoryStream.ToArray())); - - var result = ipcMessage.TryGetPayload(header, out var subMessage); - - // 可以成功获取到有效负载 - Assert.AreEqual(true, result, "没有成功获取到有效负载"); - - var resultText = Encoding.UTF8.GetString(subMessage.Body.Buffer, subMessage.Body.Start, subMessage.Body.Length); - Assert.AreEqual(text, resultText); - }); + binaryWriter.Write(header); + + // 再写入一些测试数据 + var textByteList = Encoding.UTF8.GetBytes(text); + binaryWriter.Write(textByteList); + } + + var ipcMessage = new IpcMessage("test", new IpcMessageBody(memoryStream.ToArray())); + + // 要求的负载和传入的不相同 + var result = ipcMessage.TryGetPayload(new byte[] { 0xF1, 0xC1, 0xAA, (byte) 'b' }, out var subMessage); + + // 可以成功获取到有效负载 + Assert.AreEqual(false, result); + } + + [TestMethod("给定的 IpcMessage 存在偏移,但包含正确 byte 数组的有效负载,可以成功获取到有效负载")] + public void GetPayload2() + { + var header = new byte[] { 0xF1, 0xC1, 0xAA, (byte) 'a' }; + var text = "abc"; + using var memoryStream = new MemoryStream(); + using (var binaryWriter = new BinaryWriter(memoryStream)) + { + // 写入一个 byte 垃圾,用于后续测试存在偏移 + binaryWriter.Write((byte) 0); + + binaryWriter.Write(header); + + // 再写入一些测试数据 + var textByteList = Encoding.UTF8.GetBytes(text); + binaryWriter.Write(textByteList); } + // sizeof(header) + sizeof(text) = 4 + 3 = 7 + var ipcMessage = new IpcMessage("test", new IpcMessageBody(memoryStream.ToArray(), 1, 7)); + + var result = ipcMessage.TryGetPayload(header, out var subMessage); + + // 可以成功获取到有效负载 + Assert.AreEqual(true, result, "没有成功获取到有效负载"); + + var resultText = Encoding.UTF8.GetString(subMessage.Body.Buffer, subMessage.Body.Start, subMessage.Body.Length); + Assert.AreEqual(text, resultText); + } + + [TestMethod("给定 IpcMessage 包含正确 byte 数组的有效负载,可以成功获取到有效负载")] + public void GetPayload3() + { + var header = new byte[] { 0xF1, 0xC1, 0xAA, (byte) 'a' }; + var text = "abc"; + using var memoryStream = new MemoryStream(); + using (var binaryWriter = new BinaryWriter(memoryStream)) + { + binaryWriter.Write(header); + + // 再写入一些测试数据 + var textByteList = Encoding.UTF8.GetBytes(text); + binaryWriter.Write(textByteList); + } + + var ipcMessage = new IpcMessage("test", new IpcMessageBody(memoryStream.ToArray())); + + var result = ipcMessage.TryGetPayload(header, out var subMessage); + + // 可以成功获取到有效负载 + Assert.AreEqual(true, result, "没有成功获取到有效负载"); + + var resultText = Encoding.UTF8.GetString(subMessage.Body.Buffer, subMessage.Body.Start, subMessage.Body.Length); + Assert.AreEqual(text, resultText); + } + + [TestMethod("给定的 IpcMessage 不包含正确 ulong 的有效负载,获取有效负载失败")] + public void GetPayload4() + { + ulong header = 0x12312; + var text = "abc"; + using var memoryStream = new MemoryStream(); + using (var binaryWriter = new BinaryWriter(memoryStream)) + { + binaryWriter.Write(header); + + // 再写入一些测试数据 + var textByteList = Encoding.UTF8.GetBytes(text); + binaryWriter.Write(textByteList); + } + + var ipcMessage = new IpcMessage("test", new IpcMessageBody(memoryStream.ToArray())); + + // 要求的负载和传入的不相同 + var result = ipcMessage.TryGetPayload(0xFF, out var subMessage); + + // 可以成功获取到有效负载 + Assert.AreEqual(false, result); + } + + [TestMethod("给定的 IpcMessage 存在偏移,但包含正确 ulong 的有效负载,可以成功获取到有效负载")] + public void GetPayload5() + { + ulong header = 0x12312; + var text = "abc"; + using var memoryStream = new MemoryStream(); + using (var binaryWriter = new BinaryWriter(memoryStream)) + { + // 写入一个 byte 垃圾,用于后续测试存在偏移 + binaryWriter.Write((byte) 0); + + binaryWriter.Write(header); + + // 再写入一些测试数据 + var textByteList = Encoding.UTF8.GetBytes(text); + binaryWriter.Write(textByteList); + } + // sizeof(ulong) + sizeof(text) = 8 + 3 = 11 + var ipcMessage = new IpcMessage("test", new IpcMessageBody(memoryStream.ToArray(), 1, 11)); + + var result = ipcMessage.TryGetPayload(header, out var subMessage); + + // 可以成功获取到有效负载 + Assert.AreEqual(true, result, "没有成功获取到有效负载"); + + var resultText = Encoding.UTF8.GetString(subMessage.Body.Buffer, subMessage.Body.Start, subMessage.Body.Length); + Assert.AreEqual(text, resultText); + } + + [TestMethod("给定 IpcMessage 包含正确 ulong 的有效负载,可以成功获取到有效负载")] + public void GetPayload6() + { + ulong header = 0x12312; + var text = "abc"; + using var memoryStream = new MemoryStream(); + using (var binaryWriter = new BinaryWriter(memoryStream)) + { + binaryWriter.Write(header); + + // 再写入一些测试数据 + var textByteList = Encoding.UTF8.GetBytes(text); + binaryWriter.Write(textByteList); + } + + var ipcMessage = new IpcMessage("test", new IpcMessageBody(memoryStream.ToArray())); + + var result = ipcMessage.TryGetPayload(header, out var subMessage); + + // 可以成功获取到有效负载 + Assert.AreEqual(true, result, "没有成功获取到有效负载"); + + var resultText = Encoding.UTF8.GetString(subMessage.Body.Buffer, subMessage.Body.Start, subMessage.Body.Length); + Assert.AreEqual(text, resultText); } } diff --git a/tests/dotnetCampus.Ipc.Tests/Utils/IO/AsyncBinaryReaderTests.cs b/tests/dotnetCampus.Ipc.Tests/Utils/IO/AsyncBinaryReaderTests.cs index e462007f..9af496b4 100644 --- a/tests/dotnetCampus.Ipc.Tests/Utils/IO/AsyncBinaryReaderTests.cs +++ b/tests/dotnetCampus.Ipc.Tests/Utils/IO/AsyncBinaryReaderTests.cs @@ -1,53 +1,44 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Text; -using dotnetCampus.Ipc.Utils.Buffers; +using dotnetCampus.Ipc.Utils.Buffers; using dotnetCampus.Ipc.Utils.IO; using Microsoft.VisualStudio.TestTools.UnitTesting; -using MSTest.Extensions.Contracts; -namespace dotnetCampus.Ipc.Utils.IO.Tests +namespace dotnetCampus.Ipc.Tests.Utils.IO; + +[TestClass] +public class AsyncBinaryReaderTests { - [TestClass()] - public class AsyncBinaryReaderTests + [TestMethod("给定的共享数组远远超过所需长度,可以成功读取正确的数值")] + public async Task AsyncBinaryReaderTest() { - [ContractTestCase] - public void AsyncBinaryReaderTest() - { - "给定的共享数组远远超过所需长度,可以成功读取正确的数值".Test(async () => - { - var memoryStream = new MemoryStream(); - var streamWriter = new BinaryWriter(memoryStream); - ushort n1 = 15; - streamWriter.Write(n1); - ulong n2 = 65521; - streamWriter.Write(n2); - uint n3 = 0; - streamWriter.Write(n3); - streamWriter.Flush(); - memoryStream.Position = 0; + var memoryStream = new MemoryStream(); + var streamWriter = new BinaryWriter(memoryStream); + ushort n1 = 15; + streamWriter.Write(n1); + ulong n2 = 65521; + streamWriter.Write(n2); + uint n3 = 0; + streamWriter.Write(n3); + streamWriter.Flush(); + memoryStream.Position = 0; - var asyncBinaryReader = new AsyncBinaryReader(memoryStream, new FakeSharedArrayPool()); - var r1 = await asyncBinaryReader.ReadUInt16Async(); - Assert.AreEqual(n1, r1.Result); - var r2 = await asyncBinaryReader.ReadReadUInt64Async(); - Assert.AreEqual(n2, r2.Result); - var r3 = await asyncBinaryReader.ReadUInt32Async(); - Assert.AreEqual(n3, r3.Result); - }); - } + var asyncBinaryReader = new AsyncBinaryReader(memoryStream, new FakeSharedArrayPool()); + var r1 = await asyncBinaryReader.ReadUInt16Async(); + Assert.AreEqual(n1, r1.Result); + var r2 = await asyncBinaryReader.ReadReadUInt64Async(); + Assert.AreEqual(n2, r2.Result); + var r3 = await asyncBinaryReader.ReadUInt32Async(); + Assert.AreEqual(n3, r3.Result); + } - class FakeSharedArrayPool : ISharedArrayPool + class FakeSharedArrayPool : ISharedArrayPool + { + public byte[] Rent(int minLength) { - public byte[] Rent(int minLength) - { - return new byte[1024]; - } + return new byte[1024]; + } - public void Return(byte[] array) - { - } + public void Return(byte[] array) + { } } } diff --git a/tests/dotnetCampus.Ipc.Tests/dotnetCampus.Ipc.Tests.csproj b/tests/dotnetCampus.Ipc.Tests/dotnetCampus.Ipc.Tests.csproj index d50ca424..ab5d8f69 100644 --- a/tests/dotnetCampus.Ipc.Tests/dotnetCampus.Ipc.Tests.csproj +++ b/tests/dotnetCampus.Ipc.Tests/dotnetCampus.Ipc.Tests.csproj @@ -15,7 +15,6 @@ runtime; build; native; contentfiles; analyzers; buildtransitive -