From 372fd804fe05d8f4eb81f1d2f5e6b7687fd40808 Mon Sep 17 00:00:00 2001 From: Robert Dailey Date: Fri, 25 Aug 2023 10:18:59 -0500 Subject: [PATCH] refactor: Replace TestCorrelator with Observable sink This replacement is necessary to support parallelized unit tests. TestCorrelator as well as even the InMemory sink rely on static objects, which makes multithreaded tests impossible. --- src/Directory.Packages.props | 4 +- src/tests/Directory.Build.props | 2 +- .../Recyclarr.Common.Tests/JsonUtilsTest.cs | 39 +++++-------------- .../Recyclarr.TestLibrary.csproj | 1 + .../Recyclarr.TestLibrary/TestableLogger.cs | 29 +++----------- .../TrashLibIntegrationFixture.cs | 14 +------ .../Parsing/ConfigurationLoaderSecretsTest.cs | 2 - .../Config/Parsing/ConfigurationLoaderTest.cs | 7 +--- 8 files changed, 22 insertions(+), 76 deletions(-) diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index 40a64c7f..745c9bfd 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -55,8 +55,8 @@ + - @@ -65,4 +65,4 @@ - \ No newline at end of file + diff --git a/src/tests/Directory.Build.props b/src/tests/Directory.Build.props index e7828b1e..ae7a068b 100644 --- a/src/tests/Directory.Build.props +++ b/src/tests/Directory.Build.props @@ -22,8 +22,8 @@ + - diff --git a/src/tests/Recyclarr.Common.Tests/JsonUtilsTest.cs b/src/tests/Recyclarr.Common.Tests/JsonUtilsTest.cs index ce0866d3..b1a83a17 100644 --- a/src/tests/Recyclarr.Common.Tests/JsonUtilsTest.cs +++ b/src/tests/Recyclarr.Common.Tests/JsonUtilsTest.cs @@ -1,7 +1,6 @@ using System.IO.Abstractions; using System.IO.Abstractions.Extensions; -using Serilog.Events; -using Serilog.Sinks.TestCorrelator; +using Recyclarr.TestLibrary; namespace Recyclarr.Common.Tests; @@ -12,34 +11,23 @@ public class JsonUtilsTest [Test] public void Log_files_that_do_not_exist() { - using var logContext = TestCorrelator.CreateContext(); var fs = new MockFileSystem(); - var log = new LoggerConfiguration() - .MinimumLevel.Is(LogEventLevel.Debug) - .WriteTo.TestCorrelator() - .CreateLogger(); + var log = new TestableLogger(); var path = fs.CurrentDirectory().SubDirectory("doesnt_exist"); var result = JsonUtils.GetJsonFilesInDirectories(new[] {path}, log); result.Should().BeEmpty(); - TestCorrelator.GetLogEventsFromContextGuid(logContext.Guid) - .Should().ContainSingle() - .Which.RenderMessage() - .Should().Match("*doesnt_exist*"); + log.Messages.Should().ContainSingle() + .Which.Should().Match("*doesnt_exist*"); } [Test] public void Log_files_that_only_exist() { var fs = new MockFileSystem(); - var log = new LoggerConfiguration() - .MinimumLevel.Is(LogEventLevel.Debug) - .WriteTo.TestCorrelator() - .CreateLogger(); - - using var logContext = TestCorrelator.CreateContext(); + var log = new TestableLogger(); var path = fs.CurrentDirectory().SubDirectory("exists").File("test.json"); fs.AddFile(path.FullName, new MockFileData("")); @@ -50,21 +38,14 @@ public class JsonUtilsTest .Which.FullName .Should().Be(path.FullName); - TestCorrelator.GetLogEventsFromContextGuid(logContext.Guid) - .Should().BeEmpty(); + log.Messages.Should().BeEmpty(); } [Test] public void Log_files_that_both_exist_and_do_not_exist() { var fs = new MockFileSystem(); - var log = new LoggerConfiguration() - .MinimumLevel.Is(LogEventLevel.Debug) - .WriteTo.TestCorrelator() - .CreateLogger(); - - using var logContext = TestCorrelator.CreateContext(); - + var log = new TestableLogger(); var paths = new[] { fs.CurrentDirectory().SubDirectory("does_not_exist"), @@ -82,10 +63,8 @@ public class JsonUtilsTest .Which.FullName .Should().Be(existingFile); - TestCorrelator.GetLogEventsFromContextGuid(logContext.Guid) - .Should().ContainSingle() - .Which.RenderMessage() - .Should().Match("*does_not_exist*"); + log.Messages.Should().ContainSingle() + .Which.Should().Match("*does_not_exist*"); } [Test] diff --git a/src/tests/Recyclarr.TestLibrary/Recyclarr.TestLibrary.csproj b/src/tests/Recyclarr.TestLibrary/Recyclarr.TestLibrary.csproj index f7756c52..c5916839 100644 --- a/src/tests/Recyclarr.TestLibrary/Recyclarr.TestLibrary.csproj +++ b/src/tests/Recyclarr.TestLibrary/Recyclarr.TestLibrary.csproj @@ -3,6 +3,7 @@ + diff --git a/src/tests/Recyclarr.TestLibrary/TestableLogger.cs b/src/tests/Recyclarr.TestLibrary/TestableLogger.cs index 9584a4ea..8799a3db 100644 --- a/src/tests/Recyclarr.TestLibrary/TestableLogger.cs +++ b/src/tests/Recyclarr.TestLibrary/TestableLogger.cs @@ -1,23 +1,22 @@ +using JetBrains.Annotations; using Serilog.Core; using Serilog.Events; -using Serilog.Sinks.TestCorrelator; namespace Recyclarr.TestLibrary; -public sealed class TestableLogger : ILogger, IDisposable +[UsedImplicitly] +public sealed class TestableLogger : ILogger { private readonly Logger _log; - private ITestCorrelatorContext _logContext; + private readonly List _messages = new(); public TestableLogger() { _log = new LoggerConfiguration() .MinimumLevel.Is(LogEventLevel.Verbose) - .WriteTo.TestCorrelator() + .WriteTo.Observers(o => o.Subscribe(x => _messages.Add(x.RenderMessage()))) .WriteTo.Console() .CreateLogger(); - - _logContext = TestCorrelator.CreateContext(); } public void Write(LogEvent logEvent) @@ -25,21 +24,5 @@ public sealed class TestableLogger : ILogger, IDisposable _log.Write(logEvent); } - public void Dispose() - { - _logContext.Dispose(); - _log.Dispose(); - } - - public void ResetCapturedLogs() - { - _logContext.Dispose(); - _logContext = TestCorrelator.CreateContext(); - } - - public IEnumerable GetRenderedMessages() - { - return TestCorrelator.GetLogEventsFromContextGuid(_logContext.Guid) - .Select(x => x.RenderMessage()); - } + public IEnumerable Messages => _messages; } diff --git a/src/tests/Recyclarr.TrashLib.TestLibrary/TrashLibIntegrationFixture.cs b/src/tests/Recyclarr.TrashLib.TestLibrary/TrashLibIntegrationFixture.cs index ace193a2..bf85a590 100644 --- a/src/tests/Recyclarr.TrashLib.TestLibrary/TrashLibIntegrationFixture.cs +++ b/src/tests/Recyclarr.TrashLib.TestLibrary/TrashLibIntegrationFixture.cs @@ -3,11 +3,11 @@ using System.IO.Abstractions.Extensions; using Autofac; using Autofac.Features.ResolveAnything; using Recyclarr.Common; +using Recyclarr.TestLibrary; using Recyclarr.TestLibrary.Autofac; using Recyclarr.TrashLib.ApiServices.System; using Recyclarr.TrashLib.Repo.VersionControl; using Recyclarr.TrashLib.Startup; -using Serilog.Events; using Spectre.Console; using Spectre.Console.Testing; @@ -24,7 +24,6 @@ public abstract class TrashLibIntegrationFixture : IDisposable }); Paths = new AppPaths(Fs.CurrentDirectory().SubDirectory("test").SubDirectory("recyclarr")); - Logger = CreateLogger(); _container = new Lazy(() => { @@ -63,15 +62,6 @@ public abstract class TrashLibIntegrationFixture : IDisposable // not in the TrashLibAutofacModule. } - private static ILogger CreateLogger() - { - return new LoggerConfiguration() - .MinimumLevel.Is(LogEventLevel.Verbose) - .WriteTo.TestCorrelator() - .WriteTo.Console() - .CreateLogger(); - } - // ReSharper disable MemberCanBePrivate.Global private readonly Lazy _container; @@ -80,7 +70,7 @@ public abstract class TrashLibIntegrationFixture : IDisposable protected MockFileSystem Fs { get; } protected TestConsole Console { get; } = new(); protected IAppPaths Paths { get; } - protected ILogger Logger { get; } + protected TestableLogger Logger { get; } = new(); // ReSharper restore MemberCanBePrivate.Global diff --git a/src/tests/Recyclarr.TrashLib.Tests/Config/Parsing/ConfigurationLoaderSecretsTest.cs b/src/tests/Recyclarr.TrashLib.Tests/Config/Parsing/ConfigurationLoaderSecretsTest.cs index f5375bfe..97d52b3e 100644 --- a/src/tests/Recyclarr.TrashLib.Tests/Config/Parsing/ConfigurationLoaderSecretsTest.cs +++ b/src/tests/Recyclarr.TrashLib.Tests/Config/Parsing/ConfigurationLoaderSecretsTest.cs @@ -2,7 +2,6 @@ using System.IO.Abstractions; using Recyclarr.TrashLib.Config; using Recyclarr.TrashLib.Config.Parsing; using Recyclarr.TrashLib.TestLibrary; -using Serilog.Sinks.TestCorrelator; namespace Recyclarr.TrashLib.Tests.Config.Parsing; @@ -59,7 +58,6 @@ public class ConfigurationLoaderSecretsTest : TrashLibIntegrationFixture [Test] public void Throw_when_referencing_invalid_secret() { - using var logContext = TestCorrelator.CreateContext(); var configLoader = Resolve(); const string testYml = diff --git a/src/tests/Recyclarr.TrashLib.Tests/Config/Parsing/ConfigurationLoaderTest.cs b/src/tests/Recyclarr.TrashLib.Tests/Config/Parsing/ConfigurationLoaderTest.cs index a58bf78b..fe078a1a 100644 --- a/src/tests/Recyclarr.TrashLib.Tests/Config/Parsing/ConfigurationLoaderTest.cs +++ b/src/tests/Recyclarr.TrashLib.Tests/Config/Parsing/ConfigurationLoaderTest.cs @@ -10,7 +10,6 @@ using Recyclarr.TrashLib.Config; using Recyclarr.TrashLib.Config.Parsing; using Recyclarr.TrashLib.Config.Services; using Recyclarr.TrashLib.TestLibrary; -using Serilog.Sinks.TestCorrelator; namespace Recyclarr.TrashLib.Tests.Config.Parsing; @@ -129,8 +128,6 @@ public class ConfigurationLoaderTest : TrashLibIntegrationFixture [Test] public void No_log_when_file_not_empty_but_has_no_desired_sections() { - using var logContext = TestCorrelator.CreateContext(); - var sut = Resolve(); const string testYml = """ @@ -142,8 +139,6 @@ public class ConfigurationLoaderTest : TrashLibIntegrationFixture sut.Load(testYml).GetConfigsOfType(SupportedServices.Sonarr); - TestCorrelator.GetLogEventsFromContextGuid(logContext.Guid) - .Select(x => x.RenderMessage()) - .Should().NotContain("Configuration is empty"); + Logger.Messages.Should().NotContain("Configuration is empty"); } }