diff --git a/tests/MagicOnion.Integration.Tests/MagicOnion.Integration.Tests.csproj b/tests/MagicOnion.Integration.Tests/MagicOnion.Integration.Tests.csproj index ae27f22f5..a21ac4a77 100644 --- a/tests/MagicOnion.Integration.Tests/MagicOnion.Integration.Tests.csproj +++ b/tests/MagicOnion.Integration.Tests/MagicOnion.Integration.Tests.csproj @@ -4,6 +4,7 @@ net8.0 enable enable + 14 diff --git a/tests/MagicOnion.Integration.Tests/StreamingHubTest.UnknownMethodId.cs b/tests/MagicOnion.Integration.Tests/StreamingHubTest.UnknownMethodId.cs index 818c04f88..226b86771 100644 --- a/tests/MagicOnion.Integration.Tests/StreamingHubTest.UnknownMethodId.cs +++ b/tests/MagicOnion.Integration.Tests/StreamingHubTest.UnknownMethodId.cs @@ -23,7 +23,7 @@ public async Task UnknownMethodId(TestStreamingHubClientFactory clientFactory) Assert.NotNull(ex); var rpcException = Assert.IsType(ex); Assert.Equal(StatusCode.Unimplemented, rpcException.Status.StatusCode); - Assert.Contains(factory.Logs, x => x.Contains("HubMethodNotFound\tStreamingHub method '-1'")); + Assert.Contains(factory.Logs.GetSnapshot(), x => x.Id.Name == "HubMethodNotFound" && x.Message.Contains("StreamingHub method '-1'")); } } diff --git a/tests/MagicOnion.Server.InternalTesting/MagicOnion.Server.InternalTesting.csproj b/tests/MagicOnion.Server.InternalTesting/MagicOnion.Server.InternalTesting.csproj index 3b51f3ab3..32ccd3f05 100644 --- a/tests/MagicOnion.Server.InternalTesting/MagicOnion.Server.InternalTesting.csproj +++ b/tests/MagicOnion.Server.InternalTesting/MagicOnion.Server.InternalTesting.csproj @@ -4,6 +4,7 @@ net8.0 enable enable + 14 diff --git a/tests/MagicOnion.Server.InternalTesting/MagicOnionApplicationFactory.cs b/tests/MagicOnion.Server.InternalTesting/MagicOnionApplicationFactory.cs index b4d31fd62..377c2e138 100644 --- a/tests/MagicOnion.Server.InternalTesting/MagicOnionApplicationFactory.cs +++ b/tests/MagicOnion.Server.InternalTesting/MagicOnionApplicationFactory.cs @@ -4,6 +4,7 @@ using System.Collections.Concurrent; using Microsoft.Extensions.Logging; using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.Logging.Testing; namespace MagicOnion.Server.InternalTesting; @@ -19,18 +20,12 @@ protected override IEnumerable GetServiceImplementationTypes() public abstract class MagicOnionApplicationFactory : WebApplicationFactory { public const string ItemsKey = "MagicOnionApplicationFactory.Items"; - public ConcurrentDictionary Items => Services.GetRequiredKeyedService>(ItemsKey); - public ConcurrentBag Logs { get; } = new(); protected override void ConfigureWebHost(IWebHostBuilder builder) { builder.ConfigureLogging(logger => { - logger.AddFakeLogging(options => - { - options.OutputFormatter = x => $"{x.Timestamp}\t{x.Level}\t{x.Id}\t{x.Message}\t{x.Exception}"; - options.OutputSink = x => Logs.Add(x); - }); + logger.AddFakeLogging(); }); builder.ConfigureServices(services => { @@ -53,18 +48,28 @@ protected virtual void OnConfigureMagicOnionBuilder(IMagicOnionServerBuilder bui public WebApplicationFactory WithMagicOnionOptions(Action configure) { - return this.WithWebHostBuilder(x => + return WithWebHostBuilder(builder => { - x.ConfigureServices(services => + builder.ConfigureServices(services => { services.Configure(configure); }); }); } +} + - public void Initialize() +public static class WebApplicationBuilderExtensions +{ + extension(WebApplicationFactory @this) { - Items.Clear(); - Logs.Clear(); + public ConcurrentDictionary Items => @this.Services.GetRequiredKeyedService>(MagicOnionApplicationFactory.ItemsKey); + public FakeLogCollector Logs => @this.Services.GetRequiredService(); + + public void Initialize() + { + @this.Logs.Clear(); + @this.Items.Clear(); + } } } diff --git a/tests/MagicOnion.Server.JsonTranscoding.Tests/MagicOnion.Server.JsonTranscoding.Tests.csproj b/tests/MagicOnion.Server.JsonTranscoding.Tests/MagicOnion.Server.JsonTranscoding.Tests.csproj index 6321e4207..ffdcb70a4 100644 --- a/tests/MagicOnion.Server.JsonTranscoding.Tests/MagicOnion.Server.JsonTranscoding.Tests.csproj +++ b/tests/MagicOnion.Server.JsonTranscoding.Tests/MagicOnion.Server.JsonTranscoding.Tests.csproj @@ -6,6 +6,8 @@ enable true + + 14 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 2bdcfb7f0..e97b4c373 100644 --- a/tests/MagicOnion.Server.Redis.Tests/MagicOnion.Server.Redis.Tests.csproj +++ b/tests/MagicOnion.Server.Redis.Tests/MagicOnion.Server.Redis.Tests.csproj @@ -4,6 +4,7 @@ net8.0 enable enable + 14 diff --git a/tests/MagicOnion.Server.Tests/MagicOnion.Server.Tests.csproj b/tests/MagicOnion.Server.Tests/MagicOnion.Server.Tests.csproj index 9a0364722..df02efd3e 100644 --- a/tests/MagicOnion.Server.Tests/MagicOnion.Server.Tests.csproj +++ b/tests/MagicOnion.Server.Tests/MagicOnion.Server.Tests.csproj @@ -2,7 +2,7 @@ net8.0 - default + 14 enable diff --git a/tests/MagicOnion.Server.Tests/MagicOnionMetricsTest.cs b/tests/MagicOnion.Server.Tests/MagicOnionMetricsTest.cs index 1b85503c7..4eca54088 100644 --- a/tests/MagicOnion.Server.Tests/MagicOnionMetricsTest.cs +++ b/tests/MagicOnion.Server.Tests/MagicOnionMetricsTest.cs @@ -25,6 +25,7 @@ public MagicOnionMetricsTest(MagicOnionApplicationFactory(new MagicOnionMetrics(meterFactory)); }); }); + this.factory.Initialize(); } [Fact] diff --git a/tests/MagicOnion.Server.Tests/RawBytesResponseTest.cs b/tests/MagicOnion.Server.Tests/RawBytesResponseTest.cs index 23a2babf5..4f042108e 100644 --- a/tests/MagicOnion.Server.Tests/RawBytesResponseTest.cs +++ b/tests/MagicOnion.Server.Tests/RawBytesResponseTest.cs @@ -15,6 +15,7 @@ public class RawBytesResponseTest : IClassFixture factory) { this.factory = factory.WithMagicOnionOptions(options => {}); + this.factory.Initialize(); } [Fact] diff --git a/tests/MagicOnion.Server.Tests/StreamingHubConnectionEventsTest.cs b/tests/MagicOnion.Server.Tests/StreamingHubConnectionEventsTest.cs index 7069bf4f0..2f30d3966 100644 --- a/tests/MagicOnion.Server.Tests/StreamingHubConnectionEventsTest.cs +++ b/tests/MagicOnion.Server.Tests/StreamingHubConnectionEventsTest.cs @@ -6,6 +6,7 @@ using Microsoft.AspNetCore.Mvc.Testing; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Testing; using NSubstitute; namespace MagicOnion.Server.Tests; @@ -13,15 +14,11 @@ namespace MagicOnion.Server.Tests; public class StreamingHubConnectionEventsTest: IClassFixture> { readonly WebApplicationFactory factory; - readonly ConcurrentBag logs; - readonly ConcurrentDictionary items; public StreamingHubConnectionEventsTest(MagicOnionApplicationFactory factory) { - factory.Initialize(); this.factory = factory; - this.logs = factory.Logs; - this.items = factory.Items; + this.factory.Initialize(); } [Fact] @@ -37,10 +34,10 @@ public async Task EventsCalled() await client.DisposeAsync(); await Task.Delay(100, TestContext.Current.CancellationToken); - Assert.True((bool)items.GetValueOrDefault("OnConnecting", false)); - Assert.True((bool)items.GetValueOrDefault("OnConnected", false)); - Assert.True((bool)items.GetValueOrDefault("OnDisconnected", false)); - Assert.Equal(["E/OnDisconnected", "E/OnConnected", "E/OnConnecting"], logs.Select(x => x.Split('\t')[3]).Where(x => x.StartsWith("E"))); + Assert.True((bool)factory.Items.GetValueOrDefault("OnConnecting", false)); + Assert.True((bool)factory.Items.GetValueOrDefault("OnConnected", false)); + Assert.True((bool)factory.Items.GetValueOrDefault("OnDisconnected", false)); + Assert.Equal(["E/OnConnecting", "E/OnConnected", "E/OnDisconnected"], factory.Logs.GetSnapshot().Select(x => x.Message).Where(x => x.StartsWith("E/"))); } [Fact] @@ -56,10 +53,11 @@ await StreamingHubClient.ConnectAsync x.Contains("\tE/OnConnecting\t"))); - Assert.False(logs.Any(x => x.Contains("\tE/OnConnected\t"))); - Assert.False(logs.Any(x => x.Contains("\tError\t"))); + Assert.Contains(logSnapshot.Select(x => x.Message), x => x == "E/OnConnecting"); + Assert.DoesNotContain(logSnapshot.Select(x => x.Message), x => x == "E/OnConnected"); + Assert.DoesNotContain(logSnapshot.Select(x => x.Message), x => x == "Error"); } [Fact] @@ -78,11 +76,13 @@ await StreamingHubClient.ConnectAsync(async () => await client.HelloAsync()); + var logSnapshot = factory.Logs.GetSnapshot(); Assert.Contains("StreamingHubClient has already been disconnected from the server", ex.Message); Assert.Equal(StatusCode.Unavailable, ex.StatusCode); - Assert.True(logs.Any(x => x.Contains("\tE/OnConnecting\t"))); - Assert.True(logs.Any(x => x.Contains("\tE/OnConnected\t"))); - Assert.False(logs.Any(x => x.Contains("\tError\t"))); + Assert.Contains(logSnapshot.Select(x => x.Message), x => x == "E/OnConnecting"); + Assert.Contains(logSnapshot.Select(x => x.Message), x => x == "E/OnConnected"); + Assert.DoesNotContain(logSnapshot.Select(x => x.Message), x => x == "Error"); + } } diff --git a/tests/MagicOnion.Server.Tests/StreamingHubDisconnectionTest.cs b/tests/MagicOnion.Server.Tests/StreamingHubDisconnectionTest.cs index 0728860a7..90da056fa 100644 --- a/tests/MagicOnion.Server.Tests/StreamingHubDisconnectionTest.cs +++ b/tests/MagicOnion.Server.Tests/StreamingHubDisconnectionTest.cs @@ -5,20 +5,19 @@ using MagicOnion.Server.Hubs; using Microsoft.AspNetCore.Mvc.Testing; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Testing; using NSubstitute; namespace MagicOnion.Server.Tests; public class StreamingHubDisconnectionTest : IClassFixture> { - readonly ConcurrentBag logs; readonly WebApplicationFactory factory; public StreamingHubDisconnectionTest(MagicOnionApplicationFactory factory) { - factory.Initialize(); this.factory = factory; - this.logs = factory.Logs; + this.factory.Initialize(); } [Fact] @@ -42,8 +41,9 @@ public async Task DisconnectWhileConsumingHubMethodQueue() await Task.Delay(500); - var doWorkAsyncCallCount = logs.Count(x => x.Contains("DoWorkAsync:Begin")); - var doWorkAsyncDoneCallCount = logs.Count(x => x.Contains("DoWorkAsync:Done")); + var logs = factory.Logs.GetSnapshot(); + var doWorkAsyncCallCount = logs.Count(x => x.Message == "DoWorkAsync:Begin"); + var doWorkAsyncDoneCallCount = logs.Count(x => x.Message == "DoWorkAsync:Done"); Assert.True(doWorkAsyncCallCount < 3); Assert.True(doWorkAsyncCallCount == doWorkAsyncDoneCallCount); } diff --git a/tests/MagicOnion.Server.Tests/StreamingHubThrowOnDisconnectTest.cs b/tests/MagicOnion.Server.Tests/StreamingHubThrowOnDisconnectTest.cs index 9884a34fb..921c82ca4 100644 --- a/tests/MagicOnion.Server.Tests/StreamingHubThrowOnDisconnectTest.cs +++ b/tests/MagicOnion.Server.Tests/StreamingHubThrowOnDisconnectTest.cs @@ -7,18 +7,17 @@ using Microsoft.AspNetCore.Mvc.Testing; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Testing; using NSubstitute; namespace MagicOnion.Server.Tests; public class StreamingHubThrowOnDisconnectTest : IClassFixture> { - readonly ConcurrentBag logs; readonly WebApplicationFactory factory; public StreamingHubThrowOnDisconnectTest(MagicOnionApplicationFactory factory) { - factory.Initialize(); this.factory = factory.WithWebHostBuilder(builder => { builder.ConfigureServices(services => @@ -31,7 +30,7 @@ public StreamingHubThrowOnDisconnectTest(MagicOnionApplicationFactory x.Contains("OnDisconnected"))); + var logs = this.factory.Logs.GetSnapshot(); + Assert.True(logs.Any(x => x.Message == "OnDisconnected")); Assert.True(pendingTaskRegistry.IsDisposed); } } diff --git a/tests/MagicOnion.Server.Tests/UnaryServiceTest.cs b/tests/MagicOnion.Server.Tests/UnaryServiceTest.cs index 777bad478..fd5891c50 100644 --- a/tests/MagicOnion.Server.Tests/UnaryServiceTest.cs +++ b/tests/MagicOnion.Server.Tests/UnaryServiceTest.cs @@ -4,23 +4,24 @@ using MagicOnion.Client; using MessagePack; using Microsoft.AspNetCore.Mvc.Testing; +using Microsoft.Extensions.Logging.Testing; namespace MagicOnion.Server.Tests; public class UnaryServiceTest_ReturnExceptionStackTrace : IClassFixture> { - readonly ConcurrentBag logs; readonly WebApplicationFactory factory; + readonly FakeLogCollector logs; public UnaryServiceTest_ReturnExceptionStackTrace(MagicOnionApplicationFactory factory) { - factory.Initialize(); this.factory = factory.WithMagicOnionOptions(options => { options.IsReturnExceptionStackTraceInErrorDetail = true; }); - this.logs = factory.Logs; + this.factory.Initialize(); + this.logs = this.factory.Logs; } [Fact] @@ -32,7 +33,7 @@ public async Task ReturnTypeIsNilAndNonSuccessResponse() var ex = await Assert.ThrowsAsync(async () => await client.ReturnTypeIsNilAndNonSuccessResponseAsync(StatusCode.AlreadyExists)); Assert.Equal(StatusCode.AlreadyExists, ex.StatusCode); Assert.Equal(nameof(IUnaryTestService.ReturnTypeIsNilAndNonSuccessResponseAsync), ex.Status.Detail); - Assert.Single(logs); + Assert.Equal(1, logs.Count); } [Fact] @@ -43,7 +44,7 @@ public async Task Throw_NoParameterReturnNil() var ex = await Assert.ThrowsAsync(async () => await client.ThrowAsync()); Assert.Equal(StatusCode.Unknown, ex.StatusCode); - Assert.Single(logs); + Assert.Equal(1, logs.Count); Assert.Contains("Something went wrong", ex.Message); } @@ -55,7 +56,7 @@ public async Task Throw_OneParameterReturnNil() var ex = await Assert.ThrowsAsync(async () => await client.ThrowOneValueTypeParameterReturnNilAsync(1234)); Assert.Equal(StatusCode.Unknown, ex.StatusCode); - Assert.Single(logs); + Assert.Equal(1, factory.Logs.Count); Assert.Contains("Something went wrong", ex.Message); } @@ -67,14 +68,14 @@ public async Task Throw_TwoParameterReturnNil() var ex = await Assert.ThrowsAsync(async () => await client.ThrowTwoValueTypeParameterReturnNilAsync(1234, 5678)); Assert.Equal(StatusCode.Unknown, ex.StatusCode); - Assert.Single(logs); + Assert.Equal(1, logs.Count); Assert.Contains("Something went wrong", ex.Message); } } public class UnaryServiceTest : IClassFixture> { - readonly ConcurrentBag logs; + readonly FakeLogCollector logs; readonly WebApplicationFactory factory; public UnaryServiceTest(MagicOnionApplicationFactory factory) @@ -92,7 +93,7 @@ public async Task Throw_NoParameterReturnNil() var ex = await Assert.ThrowsAsync(async () => await client.ThrowAsync()); Assert.Equal(StatusCode.Unknown, ex.StatusCode); - Assert.Single(logs); + Assert.Single(logs.GetSnapshot()); Assert.DoesNotContain("Something went wrong", ex.Message); } @@ -104,7 +105,7 @@ public async Task Throw_OneParameterReturnNil() var ex = await Assert.ThrowsAsync(async () => await client.ThrowOneValueTypeParameterReturnNilAsync(1234)); Assert.Equal(StatusCode.Unknown, ex.StatusCode); - Assert.Single(logs); + Assert.Single(logs.GetSnapshot()); Assert.DoesNotContain("Something went wrong", ex.Message); } @@ -116,7 +117,7 @@ public async Task Throw_TwoParameterReturnNil() var ex = await Assert.ThrowsAsync(async () => await client.ThrowTwoValueTypeParameterReturnNilAsync(1234, 5678)); Assert.Equal(StatusCode.Unknown, ex.StatusCode); - Assert.Single(logs); + Assert.Single(logs.GetSnapshot()); Assert.DoesNotContain("Something went wrong", ex.Message); }