diff --git a/perf/BenchmarkApp/PerformanceTest.Client/PerformanceTest.Client.csproj b/perf/BenchmarkApp/PerformanceTest.Client/PerformanceTest.Client.csproj index 60510a7f6..063ae6290 100644 --- a/perf/BenchmarkApp/PerformanceTest.Client/PerformanceTest.Client.csproj +++ b/perf/BenchmarkApp/PerformanceTest.Client/PerformanceTest.Client.csproj @@ -2,7 +2,7 @@ Exe - net7.0 + net8.0 enable enable CLIENT;$(DefineConstants) diff --git a/perf/BenchmarkApp/PerformanceTest.Server/PerformanceTest.Server.csproj b/perf/BenchmarkApp/PerformanceTest.Server/PerformanceTest.Server.csproj index e8015791b..b1aafde2a 100644 --- a/perf/BenchmarkApp/PerformanceTest.Server/PerformanceTest.Server.csproj +++ b/perf/BenchmarkApp/PerformanceTest.Server/PerformanceTest.Server.csproj @@ -1,7 +1,7 @@ - net7.0 + net8.0 enable enable SERVER;$(DefineConstants) diff --git a/perf/SourceGeneratorPerf/SourceGeneratorPerf/SourceGeneratorPerf.csproj b/perf/SourceGeneratorPerf/SourceGeneratorPerf/SourceGeneratorPerf.csproj index eeb836b60..72ac67c8c 100644 --- a/perf/SourceGeneratorPerf/SourceGeneratorPerf/SourceGeneratorPerf.csproj +++ b/perf/SourceGeneratorPerf/SourceGeneratorPerf/SourceGeneratorPerf.csproj @@ -2,7 +2,7 @@ Exe - net7.0 + net8.0 enable enable diff --git a/samples/ChatApp/ChatApp.Server/ChatApp.Server.csproj b/samples/ChatApp/ChatApp.Server/ChatApp.Server.csproj index 1c22a039b..20a8c7784 100644 --- a/samples/ChatApp/ChatApp.Server/ChatApp.Server.csproj +++ b/samples/ChatApp/ChatApp.Server/ChatApp.Server.csproj @@ -2,7 +2,7 @@ Exe - net7.0 + net8.0 latest diff --git a/samples/JwtAuthentication/JwtAuthApp.Client/JwtAuthApp.Client.csproj b/samples/JwtAuthentication/JwtAuthApp.Client/JwtAuthApp.Client.csproj index eda654116..199ba6a58 100644 --- a/samples/JwtAuthentication/JwtAuthApp.Client/JwtAuthApp.Client.csproj +++ b/samples/JwtAuthentication/JwtAuthApp.Client/JwtAuthApp.Client.csproj @@ -2,7 +2,7 @@ Exe - net7.0 + net8.0 enable enable diff --git a/samples/JwtAuthentication/JwtAuthApp.Server/JwtAuthApp.Server.csproj b/samples/JwtAuthentication/JwtAuthApp.Server/JwtAuthApp.Server.csproj index 17261a33f..6c8353f2b 100644 --- a/samples/JwtAuthentication/JwtAuthApp.Server/JwtAuthApp.Server.csproj +++ b/samples/JwtAuthentication/JwtAuthApp.Server/JwtAuthApp.Server.csproj @@ -2,7 +2,7 @@ Exe - net7.0 + net8.0 enable latest diff --git a/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/DynamicClient/DynamicStreamingHubClientBuilder.cs b/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/DynamicClient/DynamicStreamingHubClientBuilder.cs index 36e494043..ab907ade1 100644 --- a/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/DynamicClient/DynamicStreamingHubClientBuilder.cs +++ b/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/DynamicClient/DynamicStreamingHubClientBuilder.cs @@ -427,7 +427,7 @@ static void DefineMethods(TypeBuilder typeBuilder, Type interfaceType, Type rece { il.Emit(OpCodes.Newobj, typeof(ValueTask).GetConstructor(new [] { typeof(Task) })!); } - else if (def.MethodInfo.IsGenericMethod && def.MethodInfo.ReturnType.GetGenericTypeDefinition() == typeof(ValueTask<>)) + else if (def.MethodInfo.ReturnType.IsGenericType && def.MethodInfo.ReturnType.GetGenericTypeDefinition() == typeof(ValueTask<>)) { var returnTypeOfT = def.MethodInfo.ReturnType.GetGenericArguments()[0]; il.Emit(OpCodes.Newobj, typeof(ValueTask<>).MakeGenericType(returnTypeOfT).GetConstructor(new [] { typeof(Task<>).MakeGenericType(returnTypeOfT) })!); @@ -533,7 +533,7 @@ static void DefineMethodsFireAndForget(TypeBuilder typeBuilder, Type interfaceTy { il.Emit(OpCodes.Newobj, typeof(ValueTask).GetConstructor(new [] { typeof(Task) })!); } - else if (def.MethodInfo.IsGenericMethod && def.MethodInfo.ReturnType.GetGenericTypeDefinition() == typeof(ValueTask<>)) + else if (def.MethodInfo.ReturnType.IsGenericType && def.MethodInfo.ReturnType.GetGenericTypeDefinition() == typeof(ValueTask<>)) { var returnTypeOfT = def.MethodInfo.ReturnType.GetGenericArguments()[0]; il.Emit(OpCodes.Newobj, typeof(ValueTask<>).MakeGenericType(returnTypeOfT).GetConstructor(new [] { typeof(Task<>).MakeGenericType(returnTypeOfT) })!); diff --git a/src/MagicOnion.Client/DynamicClient/DynamicStreamingHubClientBuilder.cs b/src/MagicOnion.Client/DynamicClient/DynamicStreamingHubClientBuilder.cs index 36e494043..ab907ade1 100644 --- a/src/MagicOnion.Client/DynamicClient/DynamicStreamingHubClientBuilder.cs +++ b/src/MagicOnion.Client/DynamicClient/DynamicStreamingHubClientBuilder.cs @@ -427,7 +427,7 @@ static void DefineMethods(TypeBuilder typeBuilder, Type interfaceType, Type rece { il.Emit(OpCodes.Newobj, typeof(ValueTask).GetConstructor(new [] { typeof(Task) })!); } - else if (def.MethodInfo.IsGenericMethod && def.MethodInfo.ReturnType.GetGenericTypeDefinition() == typeof(ValueTask<>)) + else if (def.MethodInfo.ReturnType.IsGenericType && def.MethodInfo.ReturnType.GetGenericTypeDefinition() == typeof(ValueTask<>)) { var returnTypeOfT = def.MethodInfo.ReturnType.GetGenericArguments()[0]; il.Emit(OpCodes.Newobj, typeof(ValueTask<>).MakeGenericType(returnTypeOfT).GetConstructor(new [] { typeof(Task<>).MakeGenericType(returnTypeOfT) })!); @@ -533,7 +533,7 @@ static void DefineMethodsFireAndForget(TypeBuilder typeBuilder, Type interfaceTy { il.Emit(OpCodes.Newobj, typeof(ValueTask).GetConstructor(new [] { typeof(Task) })!); } - else if (def.MethodInfo.IsGenericMethod && def.MethodInfo.ReturnType.GetGenericTypeDefinition() == typeof(ValueTask<>)) + else if (def.MethodInfo.ReturnType.IsGenericType && def.MethodInfo.ReturnType.GetGenericTypeDefinition() == typeof(ValueTask<>)) { var returnTypeOfT = def.MethodInfo.ReturnType.GetGenericArguments()[0]; il.Emit(OpCodes.Newobj, typeof(ValueTask<>).MakeGenericType(returnTypeOfT).GetConstructor(new [] { typeof(Task<>).MakeGenericType(returnTypeOfT) })!); diff --git a/src/MagicOnion.Client/MagicOnion.Client.csproj b/src/MagicOnion.Client/MagicOnion.Client.csproj index 2a2060d3b..293255c72 100644 --- a/src/MagicOnion.Client/MagicOnion.Client.csproj +++ b/src/MagicOnion.Client/MagicOnion.Client.csproj @@ -1,7 +1,7 @@ - netstandard2.0;netstandard2.1;net6.0;net7.0 + netstandard2.0;netstandard2.1;net6.0;net7.0;net8.0 $(_LangVersionUnityBaseline) enable diff --git a/src/MagicOnion.Internal/MagicOnion.Internal.csproj b/src/MagicOnion.Internal/MagicOnion.Internal.csproj index c4c204038..d40ee4d99 100644 --- a/src/MagicOnion.Internal/MagicOnion.Internal.csproj +++ b/src/MagicOnion.Internal/MagicOnion.Internal.csproj @@ -1,7 +1,7 @@ - netstandard2.0;netstandard2.1;net6.0 + netstandard2.0;netstandard2.1;net6.0;net8.0 $(_LangVersionUnityBaseline) enable diff --git a/src/MagicOnion.Server/MagicOnion.Server.csproj b/src/MagicOnion.Server/MagicOnion.Server.csproj index 208422cf3..4bc84fde0 100644 --- a/src/MagicOnion.Server/MagicOnion.Server.csproj +++ b/src/MagicOnion.Server/MagicOnion.Server.csproj @@ -1,7 +1,7 @@ - net6.0;net7.0 + net6.0;net7.0;net8.0 enable enable diff --git a/src/MagicOnion.Shared/MagicOnion.Shared.csproj b/src/MagicOnion.Shared/MagicOnion.Shared.csproj index c1cf71ecc..303f3bfb8 100644 --- a/src/MagicOnion.Shared/MagicOnion.Shared.csproj +++ b/src/MagicOnion.Shared/MagicOnion.Shared.csproj @@ -1,7 +1,7 @@ - netstandard2.0;netstandard2.1;net6.0 + netstandard2.0;netstandard2.1;net6.0;net8.0 $(_LangVersionUnityBaseline) enable diff --git a/src/MagicOnion/MagicOnion.csproj b/src/MagicOnion/MagicOnion.csproj index 3ec079721..a5030d537 100644 --- a/src/MagicOnion/MagicOnion.csproj +++ b/src/MagicOnion/MagicOnion.csproj @@ -1,7 +1,7 @@ - net6.0;net7.0 + net6.0;net7.0;net8.0 Library False diff --git a/tests/MagicOnion.Abstractions.Tests/MagicOnion.Abstractions.Tests.csproj b/tests/MagicOnion.Abstractions.Tests/MagicOnion.Abstractions.Tests.csproj index 343e88920..786eea496 100644 --- a/tests/MagicOnion.Abstractions.Tests/MagicOnion.Abstractions.Tests.csproj +++ b/tests/MagicOnion.Abstractions.Tests/MagicOnion.Abstractions.Tests.csproj @@ -1,7 +1,7 @@ - net7.0 + net8.0 enable enable diff --git a/tests/MagicOnion.Client.Tests/ChannelAsyncStreamReader.cs b/tests/MagicOnion.Client.Tests/ChannelAsyncStreamReader.cs new file mode 100644 index 000000000..dbcf726e9 --- /dev/null +++ b/tests/MagicOnion.Client.Tests/ChannelAsyncStreamReader.cs @@ -0,0 +1,29 @@ +using System.Threading.Channels; + +namespace MagicOnion.Client.Tests; + +class ChannelAsyncStreamReader : IAsyncStreamReader +{ + readonly ChannelReader reader; + + public T Current { get; private set; } = default!; + + public ChannelAsyncStreamReader(Channel channel) + { + reader = channel.Reader; + } + + public async Task MoveNext(CancellationToken cancellationToken) + { + if (await reader.WaitToReadAsync(cancellationToken)) + { + if (reader.TryRead(out var item)) + { + Current = item; + return true; + } + } + + return false; + } +} diff --git a/tests/MagicOnion.Client.Tests/ChannelClientStreamWriter.cs b/tests/MagicOnion.Client.Tests/ChannelClientStreamWriter.cs new file mode 100644 index 000000000..0109e583c --- /dev/null +++ b/tests/MagicOnion.Client.Tests/ChannelClientStreamWriter.cs @@ -0,0 +1,27 @@ +using System.Threading.Channels; + +namespace MagicOnion.Client.Tests; + +class ChannelClientStreamWriter : IClientStreamWriter +{ + readonly ChannelWriter writer; + + public WriteOptions? WriteOptions { get; set; } + + public ChannelClientStreamWriter(ChannelWriter writer) + { + this.writer = writer; + } + + public Task CompleteAsync() + { + writer.Complete(); + return Task.CompletedTask; + } + + public Task WriteAsync(T message) + { + writer.TryWrite(message); + return Task.CompletedTask; + } +} diff --git a/tests/MagicOnion.Client.Tests/MagicOnion.Client.Tests.csproj b/tests/MagicOnion.Client.Tests/MagicOnion.Client.Tests.csproj index 95ef73d84..13484171c 100644 --- a/tests/MagicOnion.Client.Tests/MagicOnion.Client.Tests.csproj +++ b/tests/MagicOnion.Client.Tests/MagicOnion.Client.Tests.csproj @@ -1,7 +1,7 @@ - net7.0 + net8.0 enable enable false diff --git a/tests/MagicOnion.Client.Tests/StreamingHubClientTestHelper.cs b/tests/MagicOnion.Client.Tests/StreamingHubClientTestHelper.cs new file mode 100644 index 000000000..347421f14 --- /dev/null +++ b/tests/MagicOnion.Client.Tests/StreamingHubClientTestHelper.cs @@ -0,0 +1,111 @@ +using System.Buffers; +using System.Diagnostics; +using System.Threading.Channels; + +namespace MagicOnion.Client.Tests; + +class StreamingHubClientTestHelper + where TStreamingHub : IStreamingHub + where TReceiver : class +{ + readonly Channel requestChannel; + readonly Channel responseChannel; + readonly CallInvoker callInvokerMock; + readonly TReceiver receiver; + readonly IStreamingHubClientFactoryProvider? factoryProvider; + + public TReceiver Receiver => receiver; + public CallInvoker CallInvoker => callInvokerMock; + + public StreamingHubClientTestHelper(IStreamingHubClientFactoryProvider? factoryProvider = null) + { + requestChannel = Channel.CreateUnbounded(); + var requestStream = new ChannelClientStreamWriter(requestChannel); + responseChannel = Channel.CreateUnbounded(); + var responseStream = new ChannelAsyncStreamReader(responseChannel); + + this.factoryProvider = factoryProvider; + + callInvokerMock = Substitute.For(); + callInvokerMock.AsyncDuplexStreamingCall(default(Method)!, default, default) + .ReturnsForAnyArgs(x => + { + return new AsyncDuplexStreamingCall( + requestStream, + responseStream, + _ => Task.FromResult(new Metadata { { "x-magiconion-streaminghub-version", "2" } }), + _ => Status.DefaultSuccess, + _ => Metadata.Empty, + _ => { }, + new object()); + }); + + receiver = Substitute.For(); + } + + public static async Task<(StreamingHubClientTestHelper Helper, TStreamingHub Client)> CreateAndConnectAsync(CancellationToken cancellationToken = default) + { + var helper = new StreamingHubClientTestHelper(); + return (helper, await helper.ConnectAsync(cancellationToken)); + } + + public async Task ConnectAsync(CancellationToken cancellationToken = default) + { + return await StreamingHubClient.ConnectAsync( + callInvokerMock, + receiver, + cancellationToken: cancellationToken, + factoryProvider: factoryProvider + ); + } + + public async Task<(int MessageId, int MethodId, T Requst)> ReadRequestAsync() + { + var requestPayload = await requestChannel.Reader.ReadAsync(); + return ReadRequestPayload(requestPayload); + } + + public async Task<(int MethodId, T Requst)> ReadFireAndForgetRequestAsync() + { + var requestPayload = await requestChannel.Reader.ReadAsync(); + return ReadFireAndForgetRequestPayload(requestPayload); + } + + public void WriteResponse(int messageId, int methodId, T response) + { + responseChannel.Writer.TryWrite(BuildResponsePayload(messageId, methodId, response)); + } + + static byte[] BuildResponsePayload(int messageId, int methodId, T response) + { + var bufferWriter = new ArrayBufferWriter(); + var messagePackWriter = new MessagePackWriter(bufferWriter); + messagePackWriter.WriteArrayHeader(3); + messagePackWriter.Write(messageId); + messagePackWriter.Write(methodId); + MessagePackSerializer.Serialize(ref messagePackWriter, response); + messagePackWriter.Flush(); + return bufferWriter.WrittenSpan.ToArray(); + } + + static (int MessageId, int MethodId, T Body) ReadRequestPayload(ReadOnlyMemory payload) + { + // Array[3][messageId (int), methodId (int), request body...] + var messagePackReader = new MessagePackReader(payload); + var arraySize = messagePackReader.ReadArrayHeader(); + Debug.Assert(arraySize == 3); + var messageId = messagePackReader.ReadInt32(); + var methodId = messagePackReader.ReadInt32(); + return (messageId, methodId, MessagePackSerializer.Deserialize(ref messagePackReader)); + } + + static (int MethodId, T Body) ReadFireAndForgetRequestPayload(ReadOnlyMemory payload) + { + // Array[2][methodId (int), request body...] + var messagePackReader = new MessagePackReader(payload); + var arraySize = messagePackReader.ReadArrayHeader(); + Debug.Assert(arraySize == 2); + var methodId = messagePackReader.ReadInt32(); + return (methodId, MessagePackSerializer.Deserialize(ref messagePackReader)); + } +} diff --git a/tests/MagicOnion.Client.Tests/StreamingHubTest.cs b/tests/MagicOnion.Client.Tests/StreamingHubTest.cs new file mode 100644 index 000000000..686141479 --- /dev/null +++ b/tests/MagicOnion.Client.Tests/StreamingHubTest.cs @@ -0,0 +1,390 @@ +using MagicOnion.Client.DynamicClient; + +namespace MagicOnion.Client.Tests; + +public class StreamingHubTest +{ + [Fact] + public async Task Task_NoReturnValue_Parameter_Zero() + { + var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(10)); + var helper = new StreamingHubClientTestHelper(factoryProvider: DynamicStreamingHubClientFactoryProvider.Instance); + var client = await helper.ConnectAsync(timeout.Token); + + // Invoke Hub Method + var t = client.NoReturnValue_Parameter_Zero().WaitAsync(timeout.Token); + + // Read a hub method request payload + var (messageId, methodId, requestBody) = await helper.ReadRequestAsync(); + // Write a response to the stream + helper.WriteResponse(messageId, methodId, Nil.Default); + + // Wait for hub method completion. + await t; + + Assert.Equal(Nil.Default, requestBody); + } + + [Fact] + public async Task Task_Parameter_Zero() + { + var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(10)); + var helper = new StreamingHubClientTestHelper(factoryProvider: DynamicStreamingHubClientFactoryProvider.Instance); + var client = await helper.ConnectAsync(timeout.Token); + + // Invoke Hub Method + var t = client.Parameter_Zero().WaitAsync(timeout.Token); + + // Read a hub method request payload + var (messageId, methodId, requestBody) = await helper.ReadRequestAsync(); + // Write a response to the stream + helper.WriteResponse(messageId, methodId, 123); + + // Wait for hub method completion. + var result = await t; + + Assert.Equal(Nil.Default, requestBody); + Assert.Equal(123, result); + } + + [Fact] + public async Task Task_Parameter_One() + { + var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(10)); + var helper = new StreamingHubClientTestHelper(factoryProvider: DynamicStreamingHubClientFactoryProvider.Instance); + var client = await helper.ConnectAsync(timeout.Token); + + // Invoke Hub Method + var t = client.Parameter_One(12345).WaitAsync(timeout.Token); + + // Read a hub method request payload + var (messageId, methodId, requestBody) = await helper.ReadRequestAsync(); + // Write a response to the stream + helper.WriteResponse(messageId, methodId, 456); + + // Wait for hub method completion. + var result = await t; + + Assert.Equal(12345, requestBody); + Assert.Equal(456, result); + } + + [Fact] + public async Task Task_Parameter_Two() + { + var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(10)); + var helper = new StreamingHubClientTestHelper(factoryProvider: DynamicStreamingHubClientFactoryProvider.Instance); + var client = await helper.ConnectAsync(timeout.Token); + + // Invoke Hub Method + var t = client.Parameter_Two(12345, "Hello").WaitAsync(timeout.Token); + + // Read a hub method request payload + var (messageId, methodId, requestBody) = await helper.ReadRequestAsync>(); + // Write a response to the stream + helper.WriteResponse(messageId, methodId, 456); + + // Wait for hub method completion. + var result = await t; + + Assert.Equal(12345, requestBody.Item1); + Assert.Equal("Hello", requestBody.Item2); + Assert.Equal(456, result); + } + + [Fact] + public async Task Task_Parameter_Many() + { + var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(10)); + var helper = new StreamingHubClientTestHelper(factoryProvider: DynamicStreamingHubClientFactoryProvider.Instance); + var client = await helper.ConnectAsync(timeout.Token); + + // Invoke Hub Method + var t = client.Parameter_Many(12345, "Hello", 0xfffffff1L, true, 128, 12.345, 'X').WaitAsync(timeout.Token); + + // Read a hub method request payload + var (messageId, methodId, requestBody) = await helper.ReadRequestAsync>(); + // Write a response to the stream + helper.WriteResponse(messageId, methodId, 456); + + // Wait for hub method completion. + var result = await t; + + Assert.Equal(12345, requestBody.Item1); + Assert.Equal("Hello", requestBody.Item2); + Assert.Equal(0xfffffff1L, requestBody.Item3); + Assert.True(requestBody.Item4); + Assert.Equal(128, requestBody.Item5); + Assert.Equal(12.345, requestBody.Item6); + Assert.Equal('X', requestBody.Item7); + Assert.Equal(456, result); + } + + [Fact] + public async Task Task_Forget_NoReturnValue_Parameter_Zero() + { + var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(10)); + var helper = new StreamingHubClientTestHelper(factoryProvider: DynamicStreamingHubClientFactoryProvider.Instance); + var client = await helper.ConnectAsync(timeout.Token); + + // Use Fire-and-forget client + client = client.FireAndForget(); + + // Invoke Hub Method + var t = client.NoReturnValue_Parameter_Zero().WaitAsync(timeout.Token); + + // Read a hub method request payload + var (methodId, requestBody) = await helper.ReadFireAndForgetRequestAsync(); + + // Wait for hub method completion. + await t; + + Assert.Equal(Nil.Default, requestBody); + } + + [Fact] + public async Task Task_Forget_Parameter_Zero() + { + var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(10)); + var helper = new StreamingHubClientTestHelper(factoryProvider: DynamicStreamingHubClientFactoryProvider.Instance); + var client = await helper.ConnectAsync(timeout.Token); + + // Use Fire-and-forget client + client = client.FireAndForget(); + + // Invoke Hub Method + var t = client.Parameter_Zero().WaitAsync(timeout.Token); + + // Read a hub method request payload + var (methodId, requestBody) = await helper.ReadFireAndForgetRequestAsync(); + + // Wait for hub method completion. + var result = await t; + + Assert.Equal(Nil.Default, requestBody); + Assert.Equal(default, result); + } + + [Fact] + public async Task Task_Forget_Parameter_One() + { + var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(10)); + var helper = new StreamingHubClientTestHelper(factoryProvider: DynamicStreamingHubClientFactoryProvider.Instance); + var client = await helper.ConnectAsync(timeout.Token); + + // Use Fire-and-forget client + client = client.FireAndForget(); + + // Invoke Hub Method + var t = client.Parameter_One(123).WaitAsync(timeout.Token); + + // Read a hub method request payload + var (methodId, requestBody) = await helper.ReadFireAndForgetRequestAsync(); + + // Wait for hub method completion. + var result = await t; + + Assert.Equal(123, requestBody); + Assert.Equal(default, result); + } + + [Fact] + public async Task ValueTask_NoReturnValue_Parameter_Zero() + { + var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(10)); + var helper = new StreamingHubClientTestHelper(factoryProvider: DynamicStreamingHubClientFactoryProvider.Instance); + var client = await helper.ConnectAsync(timeout.Token); + + // Invoke Hub Method + var t = client.ValueTask_NoReturnValue_Parameter_Zero().AsTask().WaitAsync(timeout.Token); + + // Read a hub method request payload + var (messageId, methodId, requestBody) = await helper.ReadRequestAsync(); + // Write a response to the stream + helper.WriteResponse(messageId, methodId, Nil.Default); + + // Wait for hub method completion. + await t; + + Assert.Equal(Nil.Default, requestBody); + } + + [Fact] + public async Task ValueTask_Parameter_Zero() + { + var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(10)); + var helper = new StreamingHubClientTestHelper(factoryProvider: DynamicStreamingHubClientFactoryProvider.Instance); + var client = await helper.ConnectAsync(timeout.Token); + + // Invoke Hub Method + var t = client.ValueTask_Parameter_Zero().AsTask().WaitAsync(timeout.Token); + + // Read a hub method request payload + var (messageId, methodId, requestBody) = await helper.ReadRequestAsync(); + // Write a response to the stream + helper.WriteResponse(messageId, methodId, 123); + + // Wait for hub method completion. + var result = await t; + + Assert.Equal(Nil.Default, requestBody); + Assert.Equal(123, result); + } + + [Fact] + public async Task ValueTask_Parameter_One() + { + var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(10)); + var helper = new StreamingHubClientTestHelper(factoryProvider: DynamicStreamingHubClientFactoryProvider.Instance); + var client = await helper.ConnectAsync(timeout.Token); + + // Invoke Hub Method + var t = client.ValueTask_Parameter_One(12345).AsTask().WaitAsync(timeout.Token); + + // Read a hub method request payload + var (messageId, methodId, requestBody) = await helper.ReadRequestAsync(); + // Write a response to the stream + helper.WriteResponse(messageId, methodId, 456); + + // Wait for hub method completion. + var result = await t; + + Assert.Equal(12345, requestBody); + Assert.Equal(456, result); + } + + [Fact] + public async Task ValueTask_Parameter_Two() + { + var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(10)); + var helper = new StreamingHubClientTestHelper(factoryProvider: DynamicStreamingHubClientFactoryProvider.Instance); + var client = await helper.ConnectAsync(timeout.Token); + + // Invoke Hub Method + var t = client.ValueTask_Parameter_Two(12345, "Hello").AsTask().WaitAsync(timeout.Token); + + // Read a hub method request payload + var (messageId, methodId, requestBody) = await helper.ReadRequestAsync>(); + // Write a response to the stream + helper.WriteResponse(messageId, methodId, 456); + + // Wait for hub method completion. + var result = await t; + + Assert.Equal(12345, requestBody.Item1); + Assert.Equal("Hello", requestBody.Item2); + Assert.Equal(456, result); + } + + [Fact] + public async Task ValueTask_Parameter_Many() + { + var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(10)); + var helper = new StreamingHubClientTestHelper(factoryProvider: DynamicStreamingHubClientFactoryProvider.Instance); + var client = await helper.ConnectAsync(timeout.Token); + + // Invoke Hub Method + var t = client.ValueTask_Parameter_Many(12345, "Hello", 0xfffffff1L, true, 128, 12.345, 'X').AsTask().WaitAsync(timeout.Token); + + // Read a hub method request payload + var (messageId, methodId, requestBody) = await helper.ReadRequestAsync>(); + // Write a response to the stream + helper.WriteResponse(messageId, methodId, 456); + + // Wait for hub method completion. + var result = await t; + + Assert.Equal(12345, requestBody.Item1); + Assert.Equal("Hello", requestBody.Item2); + Assert.Equal(0xfffffff1L, requestBody.Item3); + Assert.True(requestBody.Item4); + Assert.Equal(128, requestBody.Item5); + Assert.Equal(12.345, requestBody.Item6); + Assert.Equal('X', requestBody.Item7); + Assert.Equal(456, result); + } + + [Fact] + public async Task ValueTask_Forget_NoReturnValue_Parameter_Zero() + { + var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(10)); + var helper = new StreamingHubClientTestHelper(factoryProvider: DynamicStreamingHubClientFactoryProvider.Instance); + var client = await helper.ConnectAsync(timeout.Token); + + // Use Fire-and-forget client + client = client.FireAndForget(); + + // Invoke Hub Method + var t = client.ValueTask_NoReturnValue_Parameter_Zero().AsTask().WaitAsync(timeout.Token); + + // Read a hub method request payload + var (methodId, requestBody) = await helper.ReadFireAndForgetRequestAsync(); + + // Wait for hub method completion. + await t; + + Assert.Equal(Nil.Default, requestBody); + } + + [Fact] + public async Task ValueTask_Forget_Parameter_Zero() + { + var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(10)); + var helper = new StreamingHubClientTestHelper(factoryProvider: DynamicStreamingHubClientFactoryProvider.Instance); + var client = await helper.ConnectAsync(timeout.Token); + + // Use Fire-and-forget client + client = client.FireAndForget(); + + // Invoke Hub Method + var t = client.ValueTask_Parameter_Zero().AsTask().WaitAsync(timeout.Token); + + // Read a hub method request payload + var (methodId, requestBody) = await helper.ReadFireAndForgetRequestAsync(); + + // Wait for hub method completion. + var result = await t; + + Assert.Equal(Nil.Default, requestBody); + Assert.Equal(default, result); + } + + [Fact] + public async Task ValueTask_Forget_Parameter_One() + { + var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(10)); + var helper = new StreamingHubClientTestHelper(factoryProvider: DynamicStreamingHubClientFactoryProvider.Instance); + var client = await helper.ConnectAsync(timeout.Token); + + // Use Fire-and-forget client + client = client.FireAndForget(); + + // Invoke Hub Method + var t = client.ValueTask_Parameter_One(123).AsTask().WaitAsync(timeout.Token); + + // Read a hub method request payload + var (methodId, requestBody) = await helper.ReadFireAndForgetRequestAsync(); + + // Wait for hub method completion. + var result = await t; + + Assert.Equal(123, requestBody); + Assert.Equal(default, result); + } +} + +public interface IGreeterHubReceiver +{ } +public interface IGreeterHub : IStreamingHub +{ + Task NoReturnValue_Parameter_Zero(); + Task Parameter_Zero(); + Task Parameter_One(int arg0); + Task Parameter_Two(int arg0, string arg1); + Task Parameter_Many(int arg0, string arg1, long arg2, bool arg3, byte arg4, double arg5, char arg6); + ValueTask ValueTask_NoReturnValue_Parameter_Zero(); + ValueTask ValueTask_Parameter_Zero(); + ValueTask ValueTask_Parameter_One(int arg0); + ValueTask ValueTask_Parameter_Two(int arg0, string arg1); + ValueTask ValueTask_Parameter_Many(int arg0, string arg1, long arg2, bool arg3, byte arg4, double arg5, char arg6); +} diff --git a/tests/MagicOnion.Integration.Tests/MagicOnion.Integration.Tests.csproj b/tests/MagicOnion.Integration.Tests/MagicOnion.Integration.Tests.csproj index c2071e47e..d8fa4950a 100644 --- a/tests/MagicOnion.Integration.Tests/MagicOnion.Integration.Tests.csproj +++ b/tests/MagicOnion.Integration.Tests/MagicOnion.Integration.Tests.csproj @@ -1,7 +1,7 @@ - net7.0 + net8.0 enable enable diff --git a/tests/MagicOnion.Serialization.MemoryPack.Tests/MagicOnion.Serialization.MemoryPack.Tests.csproj b/tests/MagicOnion.Serialization.MemoryPack.Tests/MagicOnion.Serialization.MemoryPack.Tests.csproj index 7c4214734..af1deb128 100644 --- a/tests/MagicOnion.Serialization.MemoryPack.Tests/MagicOnion.Serialization.MemoryPack.Tests.csproj +++ b/tests/MagicOnion.Serialization.MemoryPack.Tests/MagicOnion.Serialization.MemoryPack.Tests.csproj @@ -1,7 +1,7 @@ - net7.0 + net8.0 enable enable diff --git a/tests/MagicOnion.Serialization.MessagePack.Tests/MagicOnion.Serialization.MessagePack.Tests.csproj b/tests/MagicOnion.Serialization.MessagePack.Tests/MagicOnion.Serialization.MessagePack.Tests.csproj index 3683a53f8..179ebc8db 100644 --- a/tests/MagicOnion.Serialization.MessagePack.Tests/MagicOnion.Serialization.MessagePack.Tests.csproj +++ b/tests/MagicOnion.Serialization.MessagePack.Tests/MagicOnion.Serialization.MessagePack.Tests.csproj @@ -1,7 +1,7 @@ - net7.0 + net8.0 enable enable diff --git a/tests/MagicOnion.Server.Redis.Tests/MagicOnion.Server.Redis.Tests.csproj b/tests/MagicOnion.Server.Redis.Tests/MagicOnion.Server.Redis.Tests.csproj index 062b7d4b6..ae4428483 100644 --- a/tests/MagicOnion.Server.Redis.Tests/MagicOnion.Server.Redis.Tests.csproj +++ b/tests/MagicOnion.Server.Redis.Tests/MagicOnion.Server.Redis.Tests.csproj @@ -1,7 +1,7 @@ - net7.0 + net8.0 enable enable diff --git a/tests/MagicOnion.Server.Tests/MagicOnion.Server.Tests.csproj b/tests/MagicOnion.Server.Tests/MagicOnion.Server.Tests.csproj index c4b2f5b70..60d5a2cc5 100644 --- a/tests/MagicOnion.Server.Tests/MagicOnion.Server.Tests.csproj +++ b/tests/MagicOnion.Server.Tests/MagicOnion.Server.Tests.csproj @@ -1,7 +1,7 @@ - net7.0 + net8.0 default enable false diff --git a/tests/MagicOnion.Server.Tests/MagicOnionMetricsTest.cs b/tests/MagicOnion.Server.Tests/MagicOnionMetricsTest.cs index bb7a7d5ca..ad01e51da 100644 --- a/tests/MagicOnion.Server.Tests/MagicOnionMetricsTest.cs +++ b/tests/MagicOnion.Server.Tests/MagicOnionMetricsTest.cs @@ -161,7 +161,7 @@ public Task MethodAsync() => Task.CompletedTask; public async Task SleepAsync() => await Task.Delay(100); - public async Task ThrowAsync() + public Task ThrowAsync() => throw new InvalidOperationException(); } diff --git a/tests/samples/AuthSample/AuthSample.csproj b/tests/samples/AuthSample/AuthSample.csproj index 94b3e4ecf..91e29c1e7 100644 --- a/tests/samples/AuthSample/AuthSample.csproj +++ b/tests/samples/AuthSample/AuthSample.csproj @@ -1,7 +1,7 @@ - net7.0 + net8.0 enable enable diff --git a/tests/samples/AuthSample/FakeAuthenticationHandler.cs b/tests/samples/AuthSample/FakeAuthenticationHandler.cs index dfe5310f1..49d24a9bf 100644 --- a/tests/samples/AuthSample/FakeAuthenticationHandler.cs +++ b/tests/samples/AuthSample/FakeAuthenticationHandler.cs @@ -8,7 +8,9 @@ namespace AuthSample; public class FakeAuthenticationHandler : AuthenticationHandler { +#pragma warning disable CS0618 // Type or member is obsolete public FakeAuthenticationHandler(IOptionsMonitor options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock) +#pragma warning restore CS0618 // Type or member is obsolete { } diff --git a/tests/samples/BasicServerSample/BasicServerSample.csproj b/tests/samples/BasicServerSample/BasicServerSample.csproj index 90b64fb1c..663ca915a 100644 --- a/tests/samples/BasicServerSample/BasicServerSample.csproj +++ b/tests/samples/BasicServerSample/BasicServerSample.csproj @@ -1,7 +1,7 @@ - net7.0 + net8.0 enable enable diff --git a/tests/samples/MagicOnionEngineTest/MagicOnionEngineTest.csproj b/tests/samples/MagicOnionEngineTest/MagicOnionEngineTest.csproj index 7e062937f..ccd3af8bb 100644 --- a/tests/samples/MagicOnionEngineTest/MagicOnionEngineTest.csproj +++ b/tests/samples/MagicOnionEngineTest/MagicOnionEngineTest.csproj @@ -1,7 +1,7 @@ - net7.0 + net8.0 enable enable diff --git a/tests/samples/MagicOnionTestServer/MagicOnionTestServer.csproj b/tests/samples/MagicOnionTestServer/MagicOnionTestServer.csproj index 7e062937f..ccd3af8bb 100644 --- a/tests/samples/MagicOnionTestServer/MagicOnionTestServer.csproj +++ b/tests/samples/MagicOnionTestServer/MagicOnionTestServer.csproj @@ -1,7 +1,7 @@ - net7.0 + net8.0 enable enable