From 295e9310ce888189048600a03108bf7eee69ea2c Mon Sep 17 00:00:00 2001 From: Dingping Zhang Date: Tue, 23 Nov 2021 20:05:07 +0800 Subject: [PATCH] chore: save uncomplete work. --- HandyIpc.Tests/BuildInTypeTest.cs | 2 +- HandyIpc.Tests/EventTypeTest.cs | 73 +++++++++------------------- HandyIpc.Tests/GenericTypeTest.cs | 2 +- HandyIpc.Tests/Helper.cs | 34 +++++++++++++ HandyIpc.Tests/TaskReturnTypeTest.cs | 6 +-- HandyIpc/Core/AwaiterManager.cs | 23 ++++++--- HandyIpc/Core/NotifierManager.cs | 1 - 7 files changed, 76 insertions(+), 65 deletions(-) create mode 100644 HandyIpc.Tests/Helper.cs diff --git a/HandyIpc.Tests/BuildInTypeTest.cs b/HandyIpc.Tests/BuildInTypeTest.cs index 56e5b06..8affa15 100644 --- a/HandyIpc.Tests/BuildInTypeTest.cs +++ b/HandyIpc.Tests/BuildInTypeTest.cs @@ -36,7 +36,7 @@ public void TestBuildInTypesWithSocket() private static void TestCases(IBuildInType instance) { - Assert.Throws(instance.TestVoidWithoutParams); + Helper.AssertInnerException(instance.TestVoidWithoutParams); instance.TestDoNothing(); diff --git a/HandyIpc.Tests/EventTypeTest.cs b/HandyIpc.Tests/EventTypeTest.cs index c72be9d..73e29e8 100644 --- a/HandyIpc.Tests/EventTypeTest.cs +++ b/HandyIpc.Tests/EventTypeTest.cs @@ -1,4 +1,5 @@ using System; +using System.Threading.Tasks; using HandyIpc; using HandyIpcTests.Fixtures; using HandyIpcTests.Interfaces; @@ -18,76 +19,46 @@ public EventTypeTest(NamedPipeFixture namedPipeFixture, SocketFixture socketFixt _socketFixture = socketFixture; } - //[Fact] - public void TestEventHandlerWithSocket() + [Fact] + public async Task TestEventHandlerWithSocket() { var instance = _socketFixture.Client.Resolve(); - TestEventHandlerSubscribeAndUnsubscribe(instance); + await TestEventHandlerSubscribeAndUnsubscribe(instance); } - //[Fact] - public void TestEventHandlerWithNamedPipe() + [Fact] + public async Task TestEventHandlerWithNamedPipe() { var instance = _namedPipeFixture.Client.Resolve(); - TestEventHandlerSubscribeAndUnsubscribe(instance); + await TestEventHandlerSubscribeAndUnsubscribe(instance); } - private static void TestEventHandlerSubscribeAndUnsubscribe(IEventType instance) + private static async Task TestEventHandlerSubscribeAndUnsubscribe(IEventType instance) { // Some issues will occur only when the number of tests is high. // In particular, it tests whether the event calls are synchronized. const int testCount = 10000; - int count1 = 0; - int count2 = 0; - int count3 = 0; - - // ReSharper disable AccessToModifiedClosure - void Handler1(object? _, EventArgs e) => count1++; - EventHandler handler2 = (_, _) => count2++; - EventHandler handler3 = (_, _) => count3++; - // ReSharper restore AccessToModifiedClosure - - instance.Changed += Handler1; - instance.Changed += handler2; - instance.Changed += handler3; - - for (int i = 0; i < testCount; i++) + int count = 0; + Task WrapAsAsync(IEventType source) { - instance.RaiseChanged(EventArgs.Empty); - Assert.Equal(i + 1, count1); - Assert.Equal(i + 1, count2); - Assert.Equal(i + 1, count3); - } + TaskCompletionSource tcs = new(); + source.Changed += OnChanged; + source.RaiseChanged(EventArgs.Empty); + return tcs.Task; - count1 = 0; - count2 = 0; - count3 = 0; - - instance.Changed -= Handler1; - instance.Changed -= handler2; - instance.Changed -= handler3; - - for (int i = 0; i < testCount; i++) - { - instance.RaiseChanged(EventArgs.Empty); - Assert.Equal(0, count1); - Assert.Equal(0, count2); - Assert.Equal(0, count3); + void OnChanged(object? sender, EventArgs e) + { + source.Changed -= OnChanged; + count++; + tcs.SetResult(); + } } - instance.Changed += Handler1; - instance.Changed += Handler1; - instance.Changed += handler2; - instance.Changed += handler2; - instance.Changed += handler3; - for (int i = 0; i < testCount; i++) { - instance.RaiseChanged(EventArgs.Empty); - Assert.Equal(2 * (i + 1), count1); - Assert.Equal(2 * (i + 1), count2); - Assert.Equal(i + 1, count3); + await WrapAsAsync(instance); + Assert.Equal(i + 1, count); } } } diff --git a/HandyIpc.Tests/GenericTypeTest.cs b/HandyIpc.Tests/GenericTypeTest.cs index 8e78d18..4a92f13 100644 --- a/HandyIpc.Tests/GenericTypeTest.cs +++ b/HandyIpc.Tests/GenericTypeTest.cs @@ -47,7 +47,7 @@ public async Task TestCases(IGenericType remote) Assert.Equal(expected, actual); } - await Assert.ThrowsAsync(async () => await remote.TestAsync()); + await Helper.AssertInnerException(remote.TestAsync); { ClassWithNewCtor.InitialName = Guid.NewGuid().ToString(); diff --git a/HandyIpc.Tests/Helper.cs b/HandyIpc.Tests/Helper.cs new file mode 100644 index 0000000..d24192f --- /dev/null +++ b/HandyIpc.Tests/Helper.cs @@ -0,0 +1,34 @@ +using System; +using System.Threading.Tasks; +using HandyIpc.Exceptions; +using Xunit; + +namespace HandyIpcTests +{ + public static class Helper + { + public static void AssertInnerException(Action function) + { + try + { + function(); + } + catch (IpcException e) + { + Assert.Equal(typeof(T), e.InnerException!.GetType()); + } + } + + public static async Task AssertInnerException(Func function) + { + try + { + await function(); + } + catch (IpcException e) + { + Assert.Equal(typeof(T), e.InnerException!.GetType()); + } + } + } +} diff --git a/HandyIpc.Tests/TaskReturnTypeTest.cs b/HandyIpc.Tests/TaskReturnTypeTest.cs index 36d7066..b11d46b 100644 --- a/HandyIpc.Tests/TaskReturnTypeTest.cs +++ b/HandyIpc.Tests/TaskReturnTypeTest.cs @@ -75,13 +75,13 @@ private static async Task TestCases(ITaskReturnType instance) instance.SyncMethod(); - Assert.Throws(instance.SyncMethodWithException); + Helper.AssertInnerException(instance.SyncMethodWithException); await instance.TestDoNothing(); - await Assert.ThrowsAsync(instance.TestException); + await Helper.AssertInnerException(instance.TestException); - await Assert.ThrowsAsync(() => instance.TestGenericException(string.Empty)); + await Helper.AssertInnerException(() => instance.TestGenericException(string.Empty)); Assert.Equal(await local.TestReturnDouble(), await instance.TestReturnDouble()); diff --git a/HandyIpc/Core/AwaiterManager.cs b/HandyIpc/Core/AwaiterManager.cs index be55a1e..cada430 100644 --- a/HandyIpc/Core/AwaiterManager.cs +++ b/HandyIpc/Core/AwaiterManager.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Concurrent; +using System.Threading; using System.Threading.Tasks; using HandyIpc.Exceptions; @@ -35,8 +36,10 @@ public void Subscribe(string name, Action callback) public void Unsubscribe(string name) { - if (_awaiters.TryRemove(name, out _)) + if (_awaiters.TryRemove(name, out Awaiter awaiter)) { + awaiter.Cancellation.Cancel(); + // Send a signal to dispose the remote connection. _sender.Invoke(Subscription.Remove(_key, name, _serializer)); } } @@ -44,21 +47,23 @@ public void Unsubscribe(string name) private void LoopWait(string name, Awaiter awaiter) { using IConnection connection = awaiter.Connection; - while (true) + using CancellationTokenSource cancellation = awaiter.Cancellation; + CancellationToken token = cancellation.Token; + + while (!token.IsCancellationRequested) { // Will blocked until accepted a notification. byte[] input = connection.Read(); - if (input.Length == 0) + if (token.IsCancellationRequested) { - // The server unexpectedly closes the connection and the client should retry automatically. - _awaiters.TryRemove(name, out _); - Subscribe(name, awaiter.Handler); break; } - // Empty type means this unsubscribe, it is a special signal from the server. - if (input.IsEmpty()) + if (input.Length == 0) { + // The server unexpectedly closes the connection and the client should retry automatically. + _awaiters.TryRemove(name, out _); + Subscribe(name, awaiter.Handler); break; } @@ -81,6 +86,8 @@ private class Awaiter public IConnection Connection { get; } + public CancellationTokenSource Cancellation { get; } = new(); + public Awaiter(Action handler, IConnection connection) { Handler = handler; diff --git a/HandyIpc/Core/NotifierManager.cs b/HandyIpc/Core/NotifierManager.cs index 62eea7a..98459c6 100644 --- a/HandyIpc/Core/NotifierManager.cs +++ b/HandyIpc/Core/NotifierManager.cs @@ -72,7 +72,6 @@ public void Unsubscribe(int processId) { if (_connections.TryRemove(processId, out IConnection connection)) { - // Send a signal to notify end this connection. connection.Dispose(); } }