From 800122c98ac501e06bda7b47e49d4fb5d4a30008 Mon Sep 17 00:00:00 2001 From: Chris Rudolphi <1702962+clrudolphi@users.noreply.github.com> Date: Tue, 10 Feb 2026 08:35:35 -0600 Subject: [PATCH] Added two virtual properties to the FormatterBase class that provide the timeout values to use during Formatter disposal. These were previously hard-coded. This allows derivative formatters to set their own time-out values. The first real use of this is in the runtime tests in which the timeout values are set very small to allow those tests to complete much more quickly. --- CHANGELOG.md | 3 ++- Reqnroll/Formatters/FormatterBase.cs | 14 ++++++++++++-- .../Formatters/FileWritingFormatterBaseTests.cs | 3 +++ .../Formatters/FormatterBaseTests.cs | 2 ++ 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7085117ec..d23ef90d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,11 @@ # [vNext] ## Improvements: +* Refactor: Introduce virtual timeout properties FormattersBase class to allow individual formatters to override the defaults ## Bug fixes: -*Contributors of this release (in alphabetical order):* +*Contributors of this release (in alphabetical order):* @clrudolphi # v3.3.3 - 2026-01-27 diff --git a/Reqnroll/Formatters/FormatterBase.cs b/Reqnroll/Formatters/FormatterBase.cs index c152ee6e7..fb618d099 100644 --- a/Reqnroll/Formatters/FormatterBase.cs +++ b/Reqnroll/Formatters/FormatterBase.cs @@ -35,6 +35,16 @@ public abstract class FormatterBase : ICucumberMessageFormatter, IDisposable public string Name => _pluginName; + /// + /// Gets the timeout duration to wait for formatter task completion during disposal. + /// + protected virtual TimeSpan DisposeTimeout => TimeSpan.FromSeconds(15); + + /// + /// Gets the timeout duration to wait after cancellation during disposal. + /// + protected virtual TimeSpan DisposeCancellationTimeout => TimeSpan.FromSeconds(15); + protected FormatterBase(IFormattersConfigurationProvider configurationProvider, IFormatterLog logger, string pluginName) { _configurationProvider = configurationProvider; @@ -134,7 +144,7 @@ public virtual void Dispose() Logger.WriteMessage($"DEBUG: Formatters: Dispose is waiting on the formatter task {Name}."); // In this situation, the TestEngine is shutting down and has called Dispose on the global container. // Forcing the Dispose to wait until the formatter has had a chance to complete. - var timeoutTask = Task.Delay(TimeSpan.FromSeconds(15)); + var timeoutTask = Task.Delay(DisposeTimeout); var finishedTask = Task.WhenAny(timeoutTask, _formatterTask).GetAwaiter().GetResult(); if (finishedTask == timeoutTask) { @@ -151,7 +161,7 @@ public virtual void Dispose() _logger.WriteMessage($"DEBUG: Formatters:PluginBase.Dispose - cancellation message can't be sent as the collection is closed."); } _logger.WriteMessage($"DEBUG: Formatters.PluginBase.Dispose - waiting again after cancellation."); - timeoutTask = Task.Delay(TimeSpan.FromSeconds(15)); + timeoutTask = Task.Delay(DisposeCancellationTimeout); finishedTask = Task.WhenAny(timeoutTask, _formatterTask).GetAwaiter().GetResult(); if (finishedTask == timeoutTask) { diff --git a/Tests/Reqnroll.RuntimeTests/Formatters/FileWritingFormatterBaseTests.cs b/Tests/Reqnroll.RuntimeTests/Formatters/FileWritingFormatterBaseTests.cs index 89132f6f1..e5f99688a 100644 --- a/Tests/Reqnroll.RuntimeTests/Formatters/FileWritingFormatterBaseTests.cs +++ b/Tests/Reqnroll.RuntimeTests/Formatters/FileWritingFormatterBaseTests.cs @@ -39,6 +39,9 @@ private class TestFileWritingFormatter : FileWritingFormatterBase public bool FinalizeInitializationCalled = false; public Stream? LastStream; + protected override TimeSpan DisposeTimeout => TimeSpan.FromMilliseconds(100); + protected override TimeSpan DisposeCancellationTimeout => TimeSpan.FromMilliseconds(100); + public TestFileWritingFormatter(IFormattersConfigurationProvider config, IFormatterLog logger, IFileSystem fileSystem) : base(config, logger, fileSystem, "testPlugin", ".txt", "default.txt") { } diff --git a/Tests/Reqnroll.RuntimeTests/Formatters/FormatterBaseTests.cs b/Tests/Reqnroll.RuntimeTests/Formatters/FormatterBaseTests.cs index 9306179c2..9ccb3118b 100644 --- a/Tests/Reqnroll.RuntimeTests/Formatters/FormatterBaseTests.cs +++ b/Tests/Reqnroll.RuntimeTests/Formatters/FormatterBaseTests.cs @@ -28,6 +28,8 @@ private class TestFormatter : FormatterBase public bool ReportInitializedCalled = false; public bool CloseAsyncCalled = false; public bool CompleteWriterOnLaunchInner = false; + protected override TimeSpan DisposeTimeout => TimeSpan.FromMilliseconds(100); + protected override TimeSpan DisposeCancellationTimeout => TimeSpan.FromMilliseconds(100); public TestFormatter(IFormattersConfigurationProvider config, IFormatterLog logger, string name) : base(config, logger, name) { }