Skip to content

Commit

Permalink
chore: save uncomplete work.
Browse files Browse the repository at this point in the history
  • Loading branch information
DingpingZhang committed Oct 4, 2022
1 parent 68ce56c commit cd0f6fc
Show file tree
Hide file tree
Showing 7 changed files with 76 additions and 65 deletions.
2 changes: 1 addition & 1 deletion HandyIpc.Tests/BuildInTypeTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public void TestBuildInTypesWithSocket()

private static void TestCases(IBuildInType instance)
{
Assert.Throws<TestException>(instance.TestVoidWithoutParams);
Helper.AssertInnerException<TestException>(instance.TestVoidWithoutParams);

instance.TestDoNothing();

Expand Down
73 changes: 22 additions & 51 deletions HandyIpc.Tests/EventTypeTest.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Threading.Tasks;
using HandyIpc;
using HandyIpcTests.Fixtures;
using HandyIpcTests.Interfaces;
Expand All @@ -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<IEventType>();
TestEventHandlerSubscribeAndUnsubscribe(instance);
await TestEventHandlerSubscribeAndUnsubscribe(instance);
}

//[Fact]
public void TestEventHandlerWithNamedPipe()
[Fact]
public async Task TestEventHandlerWithNamedPipe()
{
var instance = _namedPipeFixture.Client.Resolve<IEventType>();
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);
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion HandyIpc.Tests/GenericTypeTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public async Task TestCases(IGenericType<ClassWithNewCtor, string> remote)
Assert.Equal(expected, actual);
}

await Assert.ThrowsAsync<TestException>(async () => await remote.TestAsync());
await Helper.AssertInnerException<TestException>(remote.TestAsync);

{
ClassWithNewCtor.InitialName = Guid.NewGuid().ToString();
Expand Down
34 changes: 34 additions & 0 deletions HandyIpc.Tests/Helper.cs
Original file line number Diff line number Diff line change
@@ -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<T>(Action function)
{
try
{
function();
}
catch (IpcException e)
{
Assert.Equal(typeof(T), e.InnerException!.GetType());
}
}

public static async Task AssertInnerException<T>(Func<Task> function)
{
try
{
await function();
}
catch (IpcException e)
{
Assert.Equal(typeof(T), e.InnerException!.GetType());
}
}
}
}
6 changes: 3 additions & 3 deletions HandyIpc.Tests/TaskReturnTypeTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,13 +75,13 @@ private static async Task TestCases(ITaskReturnType instance)

instance.SyncMethod();

Assert.Throws<TestException>(instance.SyncMethodWithException);
Helper.AssertInnerException<TestException>(instance.SyncMethodWithException);

await instance.TestDoNothing();

await Assert.ThrowsAsync<TestException>(instance.TestException);
await Helper.AssertInnerException<TestException>(instance.TestException);

await Assert.ThrowsAsync<TestException>(() => instance.TestGenericException(string.Empty));
await Helper.AssertInnerException<TestException>(() => instance.TestGenericException(string.Empty));

Assert.Equal(await local.TestReturnDouble(), await instance.TestReturnDouble());

Expand Down
23 changes: 15 additions & 8 deletions HandyIpc/Core/AwaiterManager.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;
using HandyIpc.Exceptions;

Expand Down Expand Up @@ -35,30 +36,34 @@ public void Subscribe(string name, Action<byte[]> 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));
}
}

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;
}

Expand All @@ -81,6 +86,8 @@ private class Awaiter

public IConnection Connection { get; }

public CancellationTokenSource Cancellation { get; } = new();

public Awaiter(Action<byte[]> handler, IConnection connection)
{
Handler = handler;
Expand Down
1 change: 0 additions & 1 deletion HandyIpc/Core/NotifierManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
}
Expand Down

0 comments on commit cd0f6fc

Please sign in to comment.