Skip to content

Commit

Permalink
Introduce InMemorySinkSnapshot to reduce the chance of assertions blo…
Browse files Browse the repository at this point in the history
…wing up.
  • Loading branch information
sandermvanvliet committed Jun 10, 2022
1 parent da82aae commit 5108686
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 64 deletions.
9 changes: 9 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
# Changelog

## Serilog.Sinks.InMemory 0.7.0

- Introduce `InMemorySinkSnapshot` for testing (see below).
- Change target frameworks for test projects to net462, netcoreapp3.1 and net6.0

## Serilog.Sinks.InMemory.Assertions: 0.9.1

- Use the new snapshot mechanism from `InMemorySink` instead of using reflection to achieve that.

## Serilog.Sinks.InMemory.Assertions: 0.9.0

This release introduces support for FluentAssertions 6.x and maintains backwards compatibility with FluentAssertions 5.x releases.
Expand Down
29 changes: 3 additions & 26 deletions src/Serilog.Sinks.InMemory.Assertions/InMemorySinkAssertions.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Linq;
using FluentAssertions.Execution;
using FluentAssertions.Primitives;
using Serilog.Events;

namespace Serilog.Sinks.InMemory.Assertions
{
Expand All @@ -24,30 +20,11 @@ public InMemorySinkAssertions(InMemorySink instance) : base(SnapshotOf(instance)
*
* For now we copy the LogEvents from the current sink and use reflection to assign
* it to a new instance of InMemorySink that will be used by the assertions,
* effectively snapshotting the InMemorySink that was used by the tests.
* effectively creating a snapshot of the InMemorySink that was used by the tests.
*/
private static InMemorySink SnapshotOf(InMemorySink instance)
{
// Capture the current log events
var logEvents = instance.LogEvents.ToList();

// Create a new sink instance
var snapshot = new InMemorySink();

// Get the field that holds the collection of log events
var field = snapshot.GetType().GetField("_logEvents", BindingFlags.NonPublic | BindingFlags.Instance);

if (field == null)
{
throw new InvalidOperationException(
"Can't snapshot the InMemorySink instance because the private field that holds the messages could not be found.");
}

// Assign the snapshot of log events to the field
((List<LogEvent>)field.GetValue(snapshot)).AddRange(logEvents);

// Return the new snapshotted InMemorySink instance
return snapshot;
return instance.Snapshot();
}

protected override string Identifier => nameof(InMemorySink);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,36 +1,40 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>

<PropertyGroup>
<IsPackable>true</IsPackable>
<Version>0.9.0</Version>
<Title>Serilog in-memory sink assertion extensions</Title>
<Description>FluentAssertions extensions to use with the Serilog.Sinks.InMemory package</Description>
<Copyright>2021 Sander van Vliet</Copyright>
<Authors>Sander van Vliet</Authors>
<PackageProjectUrl>https://github.com/sandermvanvliet/SerilogSinksInMemory/</PackageProjectUrl>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<RepositoryUrl>https://github.com/sandermvanvliet/SerilogSinksInMemory/</RepositoryUrl>
<RepositoryType>git</RepositoryType>
</PropertyGroup>
<PropertyGroup>
<IsPackable>true</IsPackable>
<Version>0.9.1</Version>
<Title>Serilog in-memory sink assertion extensions</Title>
<Description>FluentAssertions extensions to use with the Serilog.Sinks.InMemory package</Description>
<Copyright>2021 Sander van Vliet</Copyright>
<Authors>Sander van Vliet</Authors>
<PackageProjectUrl>https://github.com/sandermvanvliet/SerilogSinksInMemory/</PackageProjectUrl>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<RepositoryUrl>https://github.com/sandermvanvliet/SerilogSinksInMemory/</RepositoryUrl>
<RepositoryType>git</RepositoryType>
</PropertyGroup>

<PropertyGroup>
<PackageVersion>$(Version)$(VersionSuffix)</PackageVersion>
</PropertyGroup>
<PropertyGroup>
<PackageVersion>$(Version)$(VersionSuffix)</PackageVersion>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="FluentAssertions" Version="5.*">
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Serilog.Sinks.InMemory" Version="0.*">
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Serilog" Version="2.*">
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<PackageReference Include="FluentAssertions" Version="5.*">
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Serilog.Sinks.InMemory" Version="0.*">
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Serilog" Version="2.*">
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Serilog.Sinks.InMemory\Serilog.Sinks.InMemory.csproj" Condition="'$(Configuration)'=='Debug'" />
</ItemGroup>

</Project>
38 changes: 30 additions & 8 deletions src/Serilog.Sinks.InMemory/InMemorySink.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Serilog.Core;
using Serilog.Events;
Expand All @@ -11,32 +12,53 @@ public class InMemorySink : ILogEventSink, IDisposable
private static readonly AsyncLocal<InMemorySink> LocalInstance = new AsyncLocal<InMemorySink>();

private readonly List<LogEvent> _logEvents;
private readonly object _snapShotLock = new object();

public InMemorySink()
public InMemorySink() : this(new List<LogEvent>())
{
_logEvents = new List<LogEvent>();
}

public static InMemorySink Instance {
get {
protected InMemorySink(List<LogEvent> logEvents)
{
_logEvents = logEvents;
}

public static InMemorySink Instance
{
get
{
if (LocalInstance.Value == null)
{
LocalInstance.Value = new InMemorySink();
}

return LocalInstance.Value;
}
}

public IEnumerable<LogEvent> LogEvents => _logEvents.AsReadOnly();

public void Emit(LogEvent logEvent)
public void Dispose()
{
_logEvents.Add(logEvent);
_logEvents.Clear();
}

public void Dispose()
public virtual void Emit(LogEvent logEvent)
{
_logEvents.Clear();
lock (_snapShotLock)
{
_logEvents.Add(logEvent);
}
}

public InMemorySink Snapshot()
{
lock (_snapShotLock)
{
var currentLogEvents = _logEvents.AsReadOnly().ToList();

return new InMemorySinkSnapshot(currentLogEvents);
}
}
}
}
21 changes: 21 additions & 0 deletions src/Serilog.Sinks.InMemory/InMemorySinkSnapshot.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using Serilog.Events;

namespace Serilog.Sinks.InMemory
{
/// <summary>
/// A snapshot of an InMemorySink instance that is used for assertions
/// </summary>
internal class InMemorySinkSnapshot : InMemorySink
{
public InMemorySinkSnapshot(List<LogEvent> logEvents) : base(logEvents)
{
}

public override void Emit(LogEvent logEvent)
{
throw new InvalidOperationException("Can't write log events to a in-memory sink snapshot because it is a read-only representation");
}
}
}
2 changes: 1 addition & 1 deletion src/Serilog.Sinks.InMemory/Serilog.Sinks.InMemory.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<PropertyGroup>
<IsPackable>true</IsPackable>
<Version>0.6.0</Version>
<Version>0.7.0</Version>
<Title>Serilog in-memory sink</Title>
<Description>A sink to be used for testing log messages using Serilog</Description>
<Copyright>2020 Sander van Vliet</Copyright>
Expand Down

0 comments on commit 5108686

Please sign in to comment.