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.
json-serializing-nullable-fields-issue
Robert Dailey 9 months ago
parent 9d72a01c73
commit 372fd804fe

@ -55,8 +55,8 @@
<PackageVersion Include="NUnit" Version="3.13.3" />
<PackageVersion Include="NUnit.Analyzers" Version="3.6.1" />
<PackageVersion Include="NUnit3TestAdapter" Version="4.5.0" />
<PackageVersion Include="Serilog.Sinks.Observable" Version="2.0.2" />
<PackageVersion Include="Serilog.Sinks.NUnit" Version="1.0.3" />
<PackageVersion Include="Serilog.Sinks.TestCorrelator" Version="3.2.0" />
<PackageVersion Include="Spectre.Console.Testing" Version="0.47.0" />
<PackageVersion Include="TestableIO.System.IO.Abstractions.TestingHelpers" Version="19.2.51" />
</ItemGroup>
@ -65,4 +65,4 @@
<PackageVersion Include="System.Net.Http" Version="4.3.4" />
<PackageVersion Include="System.Text.RegularExpressions" Version="4.3.1" />
</ItemGroup>
</Project>
</Project>

@ -22,8 +22,8 @@
<PackageReference Include="NUnit" PrivateAssets="All" />
<PackageReference Include="NUnit.Analyzers" PrivateAssets="All" />
<PackageReference Include="NUnit3TestAdapter" PrivateAssets="All" />
<PackageReference Include="Serilog.Sinks.Observable" PrivateAssets="All" />
<PackageReference Include="Serilog.Sinks.NUnit" PrivateAssets="All" />
<PackageReference Include="Serilog.Sinks.TestCorrelator" PrivateAssets="All" />
<PackageReference Include="Spectre.Console.Testing" PrivateAssets="All" />
<PackageReference Include="TestableIO.System.IO.Abstractions.Extensions" PrivateAssets="All" />
<PackageReference Include="TestableIO.System.IO.Abstractions.TestingHelpers" PrivateAssets="All" />

@ -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]

@ -3,6 +3,7 @@
<ProjectReference Include="..\..\Recyclarr.Common\Recyclarr.Common.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="JetBrains.Annotations" />
<PackageReference Include="Serilog.Sinks.Console" />
</ItemGroup>
</Project>

@ -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<string> _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<string> GetRenderedMessages()
{
return TestCorrelator.GetLogEventsFromContextGuid(_logContext.Guid)
.Select(x => x.RenderMessage());
}
public IEnumerable<string> Messages => _messages;
}

@ -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<IContainer>(() =>
{
@ -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<IContainer> _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

@ -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<ConfigurationLoader>();
const string testYml =

@ -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<ConfigurationLoader>();
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");
}
}

Loading…
Cancel
Save