From 7da094af61bc48262d1f6a4bd9ad76c8e2b3e8d6 Mon Sep 17 00:00:00 2001 From: yallie Date: Mon, 13 Jan 2025 22:55:39 +0300 Subject: [PATCH] Minor changes. --- CoreRemoting.Tests/SessionTests.cs | 6 +- .../Tools/CustomMessageBuilder.cs | 81 ++++---- CoreRemoting.Tests/Tools/FactoryService.cs | 11 +- CoreRemoting.Tests/Tools/FakeAuthProvider.cs | 35 ++-- CoreRemoting.Tests/Tools/IFactoryService.cs | 9 +- CoreRemoting.Tests/Tools/IFailingService.cs | 5 - .../Tools/ISessionAwareService.cs | 16 +- CoreRemoting.Tests/Tools/ITestService.cs | 49 +++-- .../Tools/SessionAwareService.cs | 46 ++--- CoreRemoting.Tests/Tools/TestService.cs | 193 +++++++++--------- .../Tools/ValidationSyncContext.cs | 107 +++++----- 11 files changed, 271 insertions(+), 287 deletions(-) diff --git a/CoreRemoting.Tests/SessionTests.cs b/CoreRemoting.Tests/SessionTests.cs index 5d72335..272f7f0 100644 --- a/CoreRemoting.Tests/SessionTests.cs +++ b/CoreRemoting.Tests/SessionTests.cs @@ -208,13 +208,13 @@ public async Task CloseSession_method_should_close_session_gracefully_issue55() }); var disconnected = new TaskCompletionSource(); - client.Connect(); client.AfterDisconnect += () => disconnected.TrySetResult(true); + client.Connect(); // RemotingSession.Current should be accessible to the component constructor var proxy = client.CreateProxy(); - // Wait(1s) should end after CloseSession(0.5s) + // Wait(1s) should finish after CloseSession(0.5s) var proxy_Wait = proxy.Wait(1); // CloseSession shouldn't throw exceptions @@ -224,6 +224,6 @@ public async Task CloseSession_method_should_close_session_gracefully_issue55() await proxy_Wait; // Disconnection event should occur - await disconnected.Task.Timeout(2).ConfigureAwait(false); + await disconnected.Task.Timeout(2); } } \ No newline at end of file diff --git a/CoreRemoting.Tests/Tools/CustomMessageBuilder.cs b/CoreRemoting.Tests/Tools/CustomMessageBuilder.cs index 80c8759..ae8eb7e 100644 --- a/CoreRemoting.Tests/Tools/CustomMessageBuilder.cs +++ b/CoreRemoting.Tests/Tools/CustomMessageBuilder.cs @@ -5,48 +5,47 @@ using CoreRemoting.RpcMessaging; using CoreRemoting.Serialization; -namespace CoreRemoting.Tests.Tools +namespace CoreRemoting.Tests.Tools; + +/// +/// Custom client-side RPC message processor. +/// +public class CustomMessageBuilder : IMethodCallMessageBuilder { - /// - /// Custom client-side RPC message processor. - /// - public class CustomMessageBuilder : IMethodCallMessageBuilder + public CustomMessageBuilder() + { + Builder = new MethodCallMessageBuilder(); + } + + public Action ProcessMethodCallMessage { get; set; } = _ => { }; + + // ReSharper disable once MemberCanBePrivate.Global + public Action> ProcessMethodParameterInfos { get; set; } = _ => { }; + + // ReSharper disable once MemberCanBePrivate.Global + public Action ProcessMethodCallResultMessage { get; set; } = _ => { }; + + private MethodCallMessageBuilder Builder { get; set; } + + public MethodCallMessage BuildMethodCallMessage(ISerializerAdapter serializer, string remoteServiceName, MethodInfo targetMethod, object[] args) + { + var m = Builder.BuildMethodCallMessage(serializer, remoteServiceName, targetMethod, args); + ProcessMethodCallMessage(m); + return m; + } + + public IEnumerable BuildMethodParameterInfos(ISerializerAdapter serializer, MethodInfo targetMethod, object[] args) + { + var m = Builder.BuildMethodParameterInfos(serializer, targetMethod, args); + var methodCallParameterMessages = m as MethodCallParameterMessage[] ?? m.ToArray(); + ProcessMethodParameterInfos(methodCallParameterMessages); + return methodCallParameterMessages; + } + + public MethodCallResultMessage BuildMethodCallResultMessage(ISerializerAdapter serializer, Guid uniqueCallKey, MethodInfo method, object[] args, object returnValue) { - public CustomMessageBuilder() - { - Builder = new MethodCallMessageBuilder(); - } - - public Action ProcessMethodCallMessage { get; set; } = _ => { }; - - // ReSharper disable once MemberCanBePrivate.Global - public Action> ProcessMethodParameterInfos { get; set; } = _ => { }; - - // ReSharper disable once MemberCanBePrivate.Global - public Action ProcessMethodCallResultMessage { get; set; } = _ => { }; - - private MethodCallMessageBuilder Builder { get; set; } - - public MethodCallMessage BuildMethodCallMessage(ISerializerAdapter serializer, string remoteServiceName, MethodInfo targetMethod, object[] args) - { - var m = Builder.BuildMethodCallMessage(serializer, remoteServiceName, targetMethod, args); - ProcessMethodCallMessage(m); - return m; - } - - public IEnumerable BuildMethodParameterInfos(ISerializerAdapter serializer, MethodInfo targetMethod, object[] args) - { - var m = Builder.BuildMethodParameterInfos(serializer, targetMethod, args); - var methodCallParameterMessages = m as MethodCallParameterMessage[] ?? m.ToArray(); - ProcessMethodParameterInfos(methodCallParameterMessages); - return methodCallParameterMessages; - } - - public MethodCallResultMessage BuildMethodCallResultMessage(ISerializerAdapter serializer, Guid uniqueCallKey, MethodInfo method, object[] args, object returnValue) - { - var m = Builder.BuildMethodCallResultMessage(serializer, uniqueCallKey, method, args, returnValue); - ProcessMethodCallResultMessage(m); - return m; - } + var m = Builder.BuildMethodCallResultMessage(serializer, uniqueCallKey, method, args, returnValue); + ProcessMethodCallResultMessage(m); + return m; } } diff --git a/CoreRemoting.Tests/Tools/FactoryService.cs b/CoreRemoting.Tests/Tools/FactoryService.cs index 75bff23..d9a7c8b 100644 --- a/CoreRemoting.Tests/Tools/FactoryService.cs +++ b/CoreRemoting.Tests/Tools/FactoryService.cs @@ -1,10 +1,9 @@ -namespace CoreRemoting.Tests.Tools +namespace CoreRemoting.Tests.Tools; + +public class FactoryService : IFactoryService { - public class FactoryService : IFactoryService + public ITestService GetTestService() { - public ITestService GetTestService() - { - return new TestService(); - } + return new TestService(); } } \ No newline at end of file diff --git a/CoreRemoting.Tests/Tools/FakeAuthProvider.cs b/CoreRemoting.Tests/Tools/FakeAuthProvider.cs index 2495bee..c93b95e 100644 --- a/CoreRemoting.Tests/Tools/FakeAuthProvider.cs +++ b/CoreRemoting.Tests/Tools/FakeAuthProvider.cs @@ -1,27 +1,26 @@ using System; using CoreRemoting.Authentication; -namespace CoreRemoting.Tests.Tools +namespace CoreRemoting.Tests.Tools; + +public class FakeAuthProvider : IAuthenticationProvider { - public class FakeAuthProvider : IAuthenticationProvider + public Func AuthenticateFake { get; set; } + + public bool Authenticate(Credential[] credentials, out RemotingIdentity authenticatedIdentity) { - public Func AuthenticateFake { get; set; } - - public bool Authenticate(Credential[] credentials, out RemotingIdentity authenticatedIdentity) - { - var success = AuthenticateFake?.Invoke(credentials) ?? true; + var success = AuthenticateFake?.Invoke(credentials) ?? true; - authenticatedIdentity = - new RemotingIdentity() - { - AuthenticationType = "Fake", - Domain = "domain", - IsAuthenticated = success, - Name = credentials[0].Value, - Roles = ["Test"], - }; + authenticatedIdentity = + new RemotingIdentity() + { + AuthenticationType = "Fake", + Domain = "domain", + IsAuthenticated = success, + Name = credentials[0].Value, + Roles = ["Test"], + }; - return success; - } + return success; } } \ No newline at end of file diff --git a/CoreRemoting.Tests/Tools/IFactoryService.cs b/CoreRemoting.Tests/Tools/IFactoryService.cs index a80c3cc..ae30177 100644 --- a/CoreRemoting.Tests/Tools/IFactoryService.cs +++ b/CoreRemoting.Tests/Tools/IFactoryService.cs @@ -1,7 +1,6 @@ -namespace CoreRemoting.Tests.Tools +namespace CoreRemoting.Tests.Tools; + +public interface IFactoryService { - public interface IFactoryService - { - ITestService GetTestService(); - } + ITestService GetTestService(); } \ No newline at end of file diff --git a/CoreRemoting.Tests/Tools/IFailingService.cs b/CoreRemoting.Tests/Tools/IFailingService.cs index f9a6507..78f414e 100644 --- a/CoreRemoting.Tests/Tools/IFailingService.cs +++ b/CoreRemoting.Tests/Tools/IFailingService.cs @@ -1,8 +1,3 @@ -using System; -using System.Data; -using System.Threading.Tasks; -using CoreRemoting.Tests.ExternalTypes; - namespace CoreRemoting.Tests.Tools; public interface IFailingService diff --git a/CoreRemoting.Tests/Tools/ISessionAwareService.cs b/CoreRemoting.Tests/Tools/ISessionAwareService.cs index 92555f2..1cee856 100644 --- a/CoreRemoting.Tests/Tools/ISessionAwareService.cs +++ b/CoreRemoting.Tests/Tools/ISessionAwareService.cs @@ -1,16 +1,14 @@ using System.Threading.Tasks; -using System; -namespace CoreRemoting.Tests.Tools +namespace CoreRemoting.Tests.Tools; + +public interface ISessionAwareService { - public interface ISessionAwareService - { - bool HasSameSessionInstance { get; } + bool HasSameSessionInstance { get; } - string ClientAddress { get; } + string ClientAddress { get; } - Task Wait(double seconds); + Task Wait(double seconds); - Task CloseSession(double seconds); - } + Task CloseSession(double seconds); } diff --git a/CoreRemoting.Tests/Tools/ITestService.cs b/CoreRemoting.Tests/Tools/ITestService.cs index 37f4097..9fb7ba3 100644 --- a/CoreRemoting.Tests/Tools/ITestService.cs +++ b/CoreRemoting.Tests/Tools/ITestService.cs @@ -3,44 +3,43 @@ using System.Threading.Tasks; using CoreRemoting.Tests.ExternalTypes; -namespace CoreRemoting.Tests.Tools +namespace CoreRemoting.Tests.Tools; + +public delegate void ServerEventHandler(object sender); + +[ReturnAsProxy] +public interface ITestService : IBaseService { - public delegate void ServerEventHandler(object sender); - - [ReturnAsProxy] - public interface ITestService : IBaseService - { - event Action ServiceEvent; + event Action ServiceEvent; - event ServerEventHandler CustomDelegateEvent; - - object TestMethod(object arg); + event ServerEventHandler CustomDelegateEvent; + + object TestMethod(object arg); - void TestMethodWithDelegateArg(Action callback); + void TestMethodWithDelegateArg(Action callback); - void FireServiceEvent(); + void FireServiceEvent(); - void FireCustomDelegateEvent(); + void FireCustomDelegateEvent(); - [OneWay] - void OneWayMethod(); + [OneWay] + void OneWayMethod(); - void TestExternalTypeParameter(DataClass data); + void TestExternalTypeParameter(DataClass data); - string Echo(string text); + string Echo(string text); - string Reverse(string text); + string Reverse(string text); - void MethodWithOutParameter(out int counter); + void MethodWithOutParameter(out int counter); - void Error(string text); + void Error(string text); - Task ErrorAsync(string text); + Task ErrorAsync(string text); - void NonSerializableError(string text, params object[] data); + void NonSerializableError(string text, params object[] data); - DataTable TestDt(DataTable dt, long num); + DataTable TestDt(DataTable dt, long num); - (T duplicate, int size) Duplicate(T sample) where T : class; - } + (T duplicate, int size) Duplicate(T sample) where T : class; } \ No newline at end of file diff --git a/CoreRemoting.Tests/Tools/SessionAwareService.cs b/CoreRemoting.Tests/Tools/SessionAwareService.cs index 826bd43..ba8333b 100644 --- a/CoreRemoting.Tests/Tools/SessionAwareService.cs +++ b/CoreRemoting.Tests/Tools/SessionAwareService.cs @@ -1,37 +1,35 @@ using System; -using System.Threading; using System.Threading.Tasks; -namespace CoreRemoting.Tests.Tools +namespace CoreRemoting.Tests.Tools; + +internal class SessionAwareService : ISessionAwareService { - internal class SessionAwareService : ISessionAwareService + public SessionAwareService() { - public SessionAwareService() - { - CurrentSession = RemotingSession.Current; - if (CurrentSession == null) - throw new ArgumentNullException(nameof(CurrentSession)); + CurrentSession = RemotingSession.Current; + if (CurrentSession == null) + throw new ArgumentNullException(nameof(CurrentSession)); - if (CurrentSession.ClientAddress == null) - throw new ArgumentNullException(nameof(CurrentSession.ClientAddress)); - Console.WriteLine(CurrentSession.ClientAddress); - } + if (CurrentSession.ClientAddress == null) + throw new ArgumentNullException(nameof(CurrentSession.ClientAddress)); + Console.WriteLine(CurrentSession.ClientAddress); + } - public RemotingSession CurrentSession { get; } + public RemotingSession CurrentSession { get; } - public bool HasSameSessionInstance => - ReferenceEquals(CurrentSession, RemotingSession.Current); + public bool HasSameSessionInstance => + ReferenceEquals(CurrentSession, RemotingSession.Current); - public string ClientAddress => - CurrentSession.ClientAddress; + public string ClientAddress => + CurrentSession.ClientAddress; - public async Task Wait(double seconds) => - await Task.Delay(TimeSpan.FromSeconds(seconds)); + public async Task Wait(double seconds) => + await Task.Delay(TimeSpan.FromSeconds(seconds)); - public async Task CloseSession(double seconds) - { - RemotingSession.Current.Close(); - await Wait(seconds); - } + public async Task CloseSession(double seconds) + { + RemotingSession.Current.Close(); + await Wait(seconds); } } diff --git a/CoreRemoting.Tests/Tools/TestService.cs b/CoreRemoting.Tests/Tools/TestService.cs index 69918e1..d4842e2 100644 --- a/CoreRemoting.Tests/Tools/TestService.cs +++ b/CoreRemoting.Tests/Tools/TestService.cs @@ -4,125 +4,124 @@ using System.Threading.Tasks; using CoreRemoting.Tests.ExternalTypes; -namespace CoreRemoting.Tests.Tools +namespace CoreRemoting.Tests.Tools; + +public class TestService : ITestService { - public class TestService : ITestService - { - private int _counter; - - public Func TestMethodFake { get; set; } - - public Action OneWayMethodFake { get; set; } - - public Action TestExternalTypeParameterFake { get; set; } - - public event Action ServiceEvent; - - public event ServerEventHandler CustomDelegateEvent; - - public object TestMethod(object arg) - { - return TestMethodFake?.Invoke(arg); - } + private int _counter; + + public Func TestMethodFake { get; set; } + + public Action OneWayMethodFake { get; set; } + + public Action TestExternalTypeParameterFake { get; set; } + + public event Action ServiceEvent; + + public event ServerEventHandler CustomDelegateEvent; + + public object TestMethod(object arg) + { + return TestMethodFake?.Invoke(arg); + } - public void TestMethodWithDelegateArg(Action callback) - { - callback("test"); - } + public void TestMethodWithDelegateArg(Action callback) + { + callback("test"); + } - public void FireServiceEvent() - { - ServiceEvent?.Invoke(); - } + public void FireServiceEvent() + { + ServiceEvent?.Invoke(); + } - public void FireCustomDelegateEvent() - { - CustomDelegateEvent?.Invoke(null); - } + public void FireCustomDelegateEvent() + { + CustomDelegateEvent?.Invoke(null); + } - public void OneWayMethod() - { - OneWayMethodFake?.Invoke(); - } + public void OneWayMethod() + { + OneWayMethodFake?.Invoke(); + } - public void TestExternalTypeParameter(DataClass data) - { - TestExternalTypeParameterFake?.Invoke(data); - } + public void TestExternalTypeParameter(DataClass data) + { + TestExternalTypeParameterFake?.Invoke(data); + } - public string Echo(string text) - { - return text; - } + public string Echo(string text) + { + return text; + } - public string Reverse(string text) - { - return new string(text.Reverse().ToArray()); - } + public string Reverse(string text) + { + return new string(text.Reverse().ToArray()); + } - public void MethodWithOutParameter(out int counter) - { - _counter++; - counter = _counter; - } + public void MethodWithOutParameter(out int counter) + { + _counter++; + counter = _counter; + } - public bool BaseMethod() - { - return true; - } + public bool BaseMethod() + { + return true; + } - public void Error(string text) - { - throw new Exception(text); - } + public void Error(string text) + { + throw new Exception(text); + } - public async Task ErrorAsync(string text) - { - await Task.Delay(1).ConfigureAwait(false); - Error(text); - } + public async Task ErrorAsync(string text) + { + await Task.Delay(1).ConfigureAwait(false); + Error(text); + } - private class NonSerializable : Exception + private class NonSerializable : Exception + { + public NonSerializable(string message) + : base(message) { - public NonSerializable(string message) - : base(message) - { - } } + } - public void NonSerializableError(string text, params object[] data) - { - var ex = new NonSerializable(text); + public void NonSerializableError(string text, params object[] data) + { + var ex = new NonSerializable(text); - foreach (var item in data) - ex.Data[item] = item; + foreach (var item in data) + ex.Data[item] = item; - throw ex; - } + throw ex; + } - public DataTable TestDt(DataTable dt, long num) + public DataTable TestDt(DataTable dt, long num) + { + dt.Rows.Clear(); + return dt; + } + + public (T, int) Duplicate(T sample) where T : class + { + return sample switch { - dt.Rows.Clear(); - return dt; - } + byte[] arr => (Dup(arr) as T, arr.Length * 2), + int[] iarr => (Dup(iarr) as T, iarr.Length * 2 * sizeof(int)), + string str => ((str + str) as T, str.Length * 2 * sizeof(char)), + _ => throw new ArgumentOutOfRangeException(), + }; - public (T, int) Duplicate(T sample) where T : class + TItem[] Dup(TItem[] arr) { - return sample switch - { - byte[] arr => (Dup(arr) as T, arr.Length * 2), - int[] iarr => (Dup(iarr) as T, iarr.Length * 2 * sizeof(int)), - string str => ((str + str) as T, str.Length * 2 * sizeof(char)), - _ => throw new ArgumentOutOfRangeException(), - }; - - TItem[] Dup(TItem[] arr) - { - var length = arr.Length; - Array.Resize(ref arr, length * 2); - Array.Copy(arr, 0, arr, length, length); - return arr; - } + var length = arr.Length; + Array.Resize(ref arr, length * 2); + Array.Copy(arr, 0, arr, length, length); + return arr; } } } \ No newline at end of file diff --git a/CoreRemoting.Tests/Tools/ValidationSyncContext.cs b/CoreRemoting.Tests/Tools/ValidationSyncContext.cs index a69b74e..3eac54d 100644 --- a/CoreRemoting.Tests/Tools/ValidationSyncContext.cs +++ b/CoreRemoting.Tests/Tools/ValidationSyncContext.cs @@ -6,71 +6,70 @@ using CoreRemoting.Toolbox; using Xunit; -namespace CoreRemoting.Tests.Tools +namespace CoreRemoting.Tests.Tools; + +/// +/// Synchronization context for validating the ConfigureAwait usage across the library. +/// The idea is that if ConfigureAwait(false) is missing somewhere, then the continuation +/// is posted to the current synchronization context and can be detected automatically. +/// +/// Post or Send methods are called on the worker threads and the exceptions will be lost. +/// But Dispose is called on the main thread, so it can throw, and the exception will be +/// detected and reported by the unit test runner. +/// +/// References: +/// 1. https://btburnett.com/2016/04/testing-an-sdk-for-asyncawait-synchronizationcontext-deadlocks.html +/// 2. https://blog.stephencleary.com/2012/07/dont-block-on-async-code.html +/// +public class ValidationSyncContext : SynchronizationContext, IDisposable { - /// - /// Synchronization context for validating the ConfigureAwait usage across the library. - /// The idea is that if ConfigureAwait(false) is missing somewhere, then the continuation - /// is posted to the current synchronization context and can be detected automatically. - /// - /// Post or Send methods are called on the worker threads and the exceptions will be lost. - /// But Dispose is called on the main thread, so it can throw, and the exception will be - /// detected and reported by the unit test runner. - /// - /// References: - /// 1. https://btburnett.com/2016/04/testing-an-sdk-for-asyncawait-synchronizationcontext-deadlocks.html - /// 2. https://blog.stephencleary.com/2012/07/dont-block-on-async-code.html - /// - public class ValidationSyncContext : SynchronizationContext, IDisposable - { - private ConcurrentDictionary errors = new(); + private ConcurrentDictionary errors = new(); - public void Dispose() + public void Dispose() + { + if (errors.Any()) { - if (errors.Any()) + var message = "Post or Send methods were called " + errors.Count + " times."; + Console.WriteLine(message); + foreach (var pair in errors) { - var message = "Post or Send methods were called " + errors.Count + " times."; - Console.WriteLine(message); - foreach (var pair in errors) - { - Console.WriteLine("===================="); - Console.WriteLine($"{pair.Value.method}"); - Console.WriteLine("===================="); - Console.WriteLine($"{pair.Value.trace}"); - } - - Assert.Fail(message); + Console.WriteLine("===================="); + Console.WriteLine($"{pair.Value.method}"); + Console.WriteLine("===================="); + Console.WriteLine($"{pair.Value.trace}"); } + + Assert.Fail(message); } + } - public override void Post(SendOrPostCallback d, object state) - { - errors.GetOrAdd(errors.Count, c => (nameof(Post), new StackTrace())); + public override void Post(SendOrPostCallback d, object state) + { + errors.GetOrAdd(errors.Count, c => (nameof(Post), new StackTrace())); - base.Post(d, state); - } + base.Post(d, state); + } - public override void Send(SendOrPostCallback d, object state) - { - errors.GetOrAdd(errors.Count, c => (nameof(Send), new StackTrace())); + public override void Send(SendOrPostCallback d, object state) + { + errors.GetOrAdd(errors.Count, c => (nameof(Send), new StackTrace())); - base.Send(d, state); - } + base.Send(d, state); + } - public static IDisposable UseSyncContext(SynchronizationContext ctx) + public static IDisposable UseSyncContext(SynchronizationContext ctx) + { + var oldSyncContext = Current; + SetSynchronizationContext(ctx); + + return Disposable.Create(() => { - var oldSyncContext = Current; - SetSynchronizationContext(ctx); - - return Disposable.Create(() => - { - SetSynchronizationContext(oldSyncContext); - if (ctx is IDisposable disposable) - disposable.Dispose(); - }); - } - - public static IDisposable Install() => - UseSyncContext(new ValidationSyncContext()); + SetSynchronizationContext(oldSyncContext); + if (ctx is IDisposable disposable) + disposable.Dispose(); + }); } + + public static IDisposable Install() => + UseSyncContext(new ValidationSyncContext()); }