diff --git a/Directory.Packages.props b/Directory.Packages.props index 0c18175..b0c762e 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -27,6 +27,8 @@ + + diff --git a/src/AsyncLogSinkBase.cs b/src/AsyncLogSinkBase.cs index c56fb1c..a2611a5 100644 --- a/src/AsyncLogSinkBase.cs +++ b/src/AsyncLogSinkBase.cs @@ -63,7 +63,7 @@ public TWriter Writer } } } = writer; - + /// /// Gets or sets a value indicating whether this sink is disabled. /// @@ -73,7 +73,7 @@ public TWriter Writer public bool IsDisabled { get => Volatile.Read(ref isDisabled) == 1; - set => Interlocked.Exchange(ref isDisabled, value ? 1 : 0); + private set => Interlocked.Exchange(ref isDisabled, value ? 1 : 0); } // ┌─────────────────────────────────────────────────────────────────────────────┐ @@ -122,6 +122,23 @@ public IDisposable RegisterLogMessageWriter(IAsyncLogMessageWriter logMessageWriters.TryRemove(typeof(TPayload), out _)); } + /// + /// Disables this log sink, preventing it from processing any log messages until it is re-enabled. + /// + /// A that, when disposed, re-enables the log sink. + /// Thrown if the log sink is already disabled. + public IDisposable Disable() + { + if (IsDisabled) + { + throw new InvalidOperationException("The log sink is already disabled."); + } + + IsDisabled = true; + + return new DelegateDisposable(() => IsDisabled = false); + } + // ┌─────────────────────────────────────────────────────────────────────────────┐ // │ Private Methods │ // └─────────────────────────────────────────────────────────────────────────────┘ diff --git a/src/LogMessageWriter/IHasWriter.cs b/src/LogMessageWriter/IHasWriter.cs index f579912..15d52d7 100644 --- a/src/LogMessageWriter/IHasWriter.cs +++ b/src/LogMessageWriter/IHasWriter.cs @@ -13,5 +13,5 @@ public interface IHasWriter /// /// Gets or sets the . /// - public TWriter Writer { get; set;} + public TWriter Writer { get; set; } } \ No newline at end of file diff --git a/tests/AsyncLogSinkBaseTests/src/MethodTests/DisableMethodTests.cs b/tests/AsyncLogSinkBaseTests/src/MethodTests/DisableMethodTests.cs new file mode 100644 index 0000000..0452d0c --- /dev/null +++ b/tests/AsyncLogSinkBaseTests/src/MethodTests/DisableMethodTests.cs @@ -0,0 +1,107 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using AwesomeAssertions; +using FakeItEasy; +using WB.Logging; +using WB.Logging.LogSinks.Base; + +namespace AsyncLogSinkBaseTests.MethodTests.DisableMethodTests; + +internal sealed class TestWriter +{ +} + +internal sealed class TestLogSink() : AsyncLogSinkBase(new TestLogMessageWriter(), new TestWriter()) +{ +} + +internal sealed class TestLogMessageWriter : IAsyncLogMessageWriter +{ + public bool Called { get; private set; } + + public TestWriter Writer { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + + public IAsyncLogSink? LogSink { get; set; } + + public ValueTask WriteAsync(DateTimeOffset timestamp, LogLevel? logLevel, IEnumerable senders, object? payload) + { + Called = true; + + return ValueTask.CompletedTask; + } +} + +public sealed class TheDisableMethod +{ + [Test] + public void ShouldSetIsDisabledToTrue() + { + // Arrange + TestLogSink logSink = new(); + + // Act + logSink.Disable(); + + // Assert + logSink.IsDisabled.Should().BeTrue(because: "calling Disable() should set IsDisabled to true"); + } + + [Test] + public void ShouldThrowInvalidOperationExceptionIfAlreadyDisabled() + { + // Arrange + TestLogSink logSink = new(); + + // Act + Action action = () => + { + logSink.Disable(); + logSink.Disable(); + }; + + // Act & Assert + action.Should().Throw(because: "calling Disable() on an already disabled log sink should throw an InvalidOperationException"); + } + + [Test] + [Arguments(true, false, DisplayName = "when log sink is disabled")] + [Arguments(false, true, DisplayName = "when log sink is enabled")] + public async Task ShouldPreventProcessingLogMessages(bool isDisabled, bool logMessageWriterCalled) + { + // Arrange + TestLogMessageWriter logMessageWriter = new(); + TestLogSink logSink = new(); + logSink.RegisterLogMessageWriter(logMessageWriter); + + if (isDisabled) + { + logSink.Disable(); + } + + ILogMessage logMessage = A.Fake>(); + + // Act + await logSink.SubmitAsync(logMessage); + + // Assert + logMessageWriter.Called.Should().Be(logMessageWriterCalled, because: "the log message writer should only be called if the log sink is not disabled"); + } + + [Test] + public void ShouldReEnableLogSinkWhenReturnedIDisposableIsDisposed() + { + // Arrange + TestLogSink logSink = new(); + + // Act + using (logSink.Disable()) + { + // Assert + logSink.IsDisabled.Should().BeTrue(because: "the log sink should be disabled within the using block"); + } + + // Assert + logSink.IsDisabled.Should().BeFalse(because: "the log sink should be re-enabled after the using block"); + } +} \ No newline at end of file diff --git a/tests/AsyncLogSinkBaseTests/src/PropertyTests/IsDisabledPropertyTests.cs b/tests/AsyncLogSinkBaseTests/src/PropertyTests/IsDisabledPropertyTests.cs index c0c85a8..a4e8877 100644 --- a/tests/AsyncLogSinkBaseTests/src/PropertyTests/IsDisabledPropertyTests.cs +++ b/tests/AsyncLogSinkBaseTests/src/PropertyTests/IsDisabledPropertyTests.cs @@ -45,24 +45,4 @@ public void ShouldReturnFalseByDefault() // Assert isDisabled.Should().BeFalse(because: "log sinks should be enabled by default"); } - - [Test] - [Arguments(true, false)] - [Arguments(false, true)] - public async Task ShouldSetAndGetIsDisabledProperty(bool isDisabled, bool logMessageWriterCalled) - { - // Arrange - TestLogSink logSink = new() - { - IsDisabled = isDisabled - }; - - TestLogMessageWriter logMessageWriter = (TestLogMessageWriter)logSink.DefaultLogMessageWriter; - - // Act - await logSink.SubmitAsync(new LogMessage() { Payload = new object() }).ConfigureAwait(false); - - // Assert - logMessageWriter.Called.Should().Be(logMessageWriterCalled, because: "the log message writer should only be called when the log sink is not disabled"); - } } \ No newline at end of file diff --git a/tests/Directory.Build.props b/tests/Directory.Build.props index c9c7a36..7366369 100644 --- a/tests/Directory.Build.props +++ b/tests/Directory.Build.props @@ -13,9 +13,17 @@ + + + + all + runtime; build; native; contentfiles; analyzers + + + \ No newline at end of file