diff --git a/.github/workflows/publish-artifacts-examples-tests.yml b/.github/workflows/publish-artifacts-examples-tests.yml
index cc08b5f73..ef25f1cca 100644
--- a/.github/workflows/publish-artifacts-examples-tests.yml
+++ b/.github/workflows/publish-artifacts-examples-tests.yml
@@ -79,6 +79,7 @@ jobs:
# Ensure we preserve access to NuGet.org
- name: Configure NuGet.org source
+ continue-on-error: true
run: |
dotnet nuget add source https://api.nuget.org/v3/index.json --name nuget.org
diff --git a/libraries/src/AWS.Lambda.Powertools.Common/Core/ConsoleWrapper.cs b/libraries/src/AWS.Lambda.Powertools.Common/Core/ConsoleWrapper.cs
index c71c05aec..c2c93eb4b 100644
--- a/libraries/src/AWS.Lambda.Powertools.Common/Core/ConsoleWrapper.cs
+++ b/libraries/src/AWS.Lambda.Powertools.Common/Core/ConsoleWrapper.cs
@@ -22,41 +22,77 @@ namespace AWS.Lambda.Powertools.Common;
public class ConsoleWrapper : IConsoleWrapper
{
private static bool _override;
+ private static TextWriter _testOutputStream;
+ private static bool _outputResetPerformed = false;
+ private static bool _inTestMode = false;
///
public void WriteLine(string message)
{
- OverrideLambdaLogger();
- Console.WriteLine(message);
+ if (_inTestMode && _testOutputStream != null)
+ {
+ _testOutputStream.WriteLine(message);
+ }
+ else
+ {
+ EnsureConsoleOutputOnce();
+ Console.WriteLine(message);
+ }
}
///
public void Debug(string message)
{
- OverrideLambdaLogger();
- System.Diagnostics.Debug.WriteLine(message);
+ if (_inTestMode && _testOutputStream != null)
+ {
+ _testOutputStream.WriteLine(message);
+ }
+ else
+ {
+ EnsureConsoleOutputOnce();
+ System.Diagnostics.Debug.WriteLine(message);
+ }
}
///
public void Error(string message)
{
- if (!_override)
+ if (_inTestMode && _testOutputStream != null)
{
- var errordOutput = new StreamWriter(Console.OpenStandardError());
- errordOutput.AutoFlush = true;
- Console.SetError(errordOutput);
+ _testOutputStream.WriteLine(message);
+ }
+ else
+ {
+ if (!_override)
+ {
+ var errordOutput = new StreamWriter(Console.OpenStandardError());
+ errordOutput.AutoFlush = true;
+ Console.SetError(errordOutput);
+ }
+ Console.Error.WriteLine(message);
}
-
- Console.Error.WriteLine(message);
}
- internal static void SetOut(StringWriter consoleOut)
+ ///
+ /// Set the ConsoleWrapper to use a different TextWriter
+ /// This is useful for unit tests where you want to capture the output
+ ///
+ public static void SetOut(TextWriter consoleOut)
{
+ _testOutputStream = consoleOut;
+ _inTestMode = true;
_override = true;
Console.SetOut(consoleOut);
}
- private void OverrideLambdaLogger()
+ private static void EnsureConsoleOutputOnce()
+ {
+ if (_outputResetPerformed) return;
+ OverrideLambdaLogger();
+ _outputResetPerformed = true;
+ }
+
+ private static void OverrideLambdaLogger()
{
if (_override)
{
@@ -73,8 +109,22 @@ internal static void WriteLine(string logLevel, string message)
Console.WriteLine($"{DateTime.UtcNow:yyyy-MM-ddTHH:mm:ss.fffZ}\t{logLevel}\t{message}");
}
+ ///
+ /// Reset the ConsoleWrapper to its original state
+ ///
public static void ResetForTest()
{
_override = false;
+ _inTestMode = false;
+ _testOutputStream = null;
+ _outputResetPerformed = false;
+ }
+
+ ///
+ /// Clear the output reset flag
+ ///
+ public static void ClearOutputResetFlag()
+ {
+ _outputResetPerformed = false;
}
}
\ No newline at end of file
diff --git a/libraries/tests/AWS.Lambda.Powertools.BatchProcessing.Tests/Internal/BatchProcessingInternalTests.cs b/libraries/tests/AWS.Lambda.Powertools.BatchProcessing.Tests/Internal/BatchProcessingInternalTests.cs
index c218e419b..daf430826 100644
--- a/libraries/tests/AWS.Lambda.Powertools.BatchProcessing.Tests/Internal/BatchProcessingInternalTests.cs
+++ b/libraries/tests/AWS.Lambda.Powertools.BatchProcessing.Tests/Internal/BatchProcessingInternalTests.cs
@@ -35,7 +35,7 @@ public void BatchProcessing_Set_Execution_Environment_Context_SQS()
var sqsBatchProcessor = new SqsBatchProcessor(conf);
// Assert
- Assert.Equal($"{Constants.FeatureContextIdentifier}/BatchProcessing/1.0.0",
+ Assert.Equal($"{Constants.FeatureContextIdentifier}/BatchProcessing/{env.GetAssemblyVersion(this)}",
env.GetEnvironmentVariable("AWS_EXECUTION_ENV"));
Assert.NotNull(sqsBatchProcessor);
@@ -52,7 +52,7 @@ public void BatchProcessing_Set_Execution_Environment_Context_Kinesis()
var KinesisEventBatchProcessor = new KinesisEventBatchProcessor(conf);
// Assert
- Assert.Equal($"{Constants.FeatureContextIdentifier}/BatchProcessing/1.0.0",
+ Assert.Equal($"{Constants.FeatureContextIdentifier}/BatchProcessing/{env.GetAssemblyVersion(this)}",
env.GetEnvironmentVariable("AWS_EXECUTION_ENV"));
Assert.NotNull(KinesisEventBatchProcessor);
@@ -69,7 +69,7 @@ public void BatchProcessing_Set_Execution_Environment_Context_DynamoDB()
var dynamoDbStreamBatchProcessor = new DynamoDbStreamBatchProcessor(conf);
// Assert
- Assert.Equal($"{Constants.FeatureContextIdentifier}/BatchProcessing/1.0.0",
+ Assert.Equal($"{Constants.FeatureContextIdentifier}/BatchProcessing/{env.GetAssemblyVersion(this)}",
env.GetEnvironmentVariable("AWS_EXECUTION_ENV"));
Assert.NotNull(dynamoDbStreamBatchProcessor);
diff --git a/libraries/tests/AWS.Lambda.Powertools.Common.Tests/ConsoleWrapperTests.cs b/libraries/tests/AWS.Lambda.Powertools.Common.Tests/ConsoleWrapperTests.cs
index fdc79d957..020630a33 100644
--- a/libraries/tests/AWS.Lambda.Powertools.Common.Tests/ConsoleWrapperTests.cs
+++ b/libraries/tests/AWS.Lambda.Powertools.Common.Tests/ConsoleWrapperTests.cs
@@ -6,19 +6,28 @@ namespace AWS.Lambda.Powertools.Common.Tests;
public class ConsoleWrapperTests : IDisposable
{
+ private StringWriter _writer;
+
+ public ConsoleWrapperTests()
+ {
+ // Setup a new StringWriter for each test
+ _writer = new StringWriter();
+ // Reset static state for clean testing
+ ConsoleWrapper.ResetForTest();
+ }
+
[Fact]
public void WriteLine_Should_Write_To_Console()
{
// Arrange
var consoleWrapper = new ConsoleWrapper();
- var writer = new StringWriter();
- ConsoleWrapper.SetOut(writer);
+ ConsoleWrapper.SetOut(_writer);
// Act
consoleWrapper.WriteLine("test message");
// Assert
- Assert.Equal($"test message{Environment.NewLine}", writer.ToString());
+ Assert.Equal($"test message{Environment.NewLine}", _writer.ToString());
}
[Fact]
@@ -26,16 +35,15 @@ public void Error_Should_Write_To_Error_Console()
{
// Arrange
var consoleWrapper = new ConsoleWrapper();
- var writer = new StringWriter();
- ConsoleWrapper.SetOut(writer);
- Console.SetError(writer);
+ ConsoleWrapper.SetOut(_writer);
+ Console.SetError(_writer);
// Act
consoleWrapper.Error("error message");
- writer.Flush();
+ _writer.Flush();
// Assert
- Assert.Equal($"error message{Environment.NewLine}", writer.ToString());
+ Assert.Equal($"error message{Environment.NewLine}", _writer.ToString());
}
[Fact]
@@ -43,122 +51,149 @@ public void SetOut_Should_Override_Console_Output()
{
// Arrange
var consoleWrapper = new ConsoleWrapper();
- var writer = new StringWriter();
- ConsoleWrapper.SetOut(writer);
+ ConsoleWrapper.SetOut(_writer);
// Act
consoleWrapper.WriteLine("test message");
// Assert
- Assert.Equal($"test message{Environment.NewLine}", writer.ToString());
+ Assert.Equal($"test message{Environment.NewLine}", _writer.ToString());
}
[Fact]
public void OverrideLambdaLogger_Should_Override_Console_Out()
{
-// Arrange
- var originalOut = Console.Out;
- try
- {
- var consoleWrapper = new ConsoleWrapper();
-
- // Act - create a custom StringWriter and set it after constructor
- // but before WriteLine (which triggers OverrideLambdaLogger)
- var writer = new StringWriter();
- ConsoleWrapper.SetOut(writer);
-
- consoleWrapper.WriteLine("test message");
-
- // Assert
- Assert.Equal($"test message{Environment.NewLine}", writer.ToString());
- }
- finally
- {
- // Restore original console out
- ConsoleWrapper.ResetForTest();
- }
+ // Arrange
+ var consoleWrapper = new ConsoleWrapper();
+ ConsoleWrapper.SetOut(_writer);
+
+ // Act
+ consoleWrapper.WriteLine("test message");
+
+ // Assert
+ Assert.Equal($"test message{Environment.NewLine}", _writer.ToString());
+ }
+
+ [Fact]
+ public void WriteLine_WritesMessageToConsole()
+ {
+ // Arrange
+ var consoleWrapper = new ConsoleWrapper();
+ ConsoleWrapper.SetOut(_writer);
+
+ // Act
+ consoleWrapper.WriteLine("Test message");
+
+ // Assert
+ var output = _writer.ToString();
+ Assert.Contains("Test message", output);
+ }
+
+ [Fact]
+ public void SetOut_OverridesConsoleOutput()
+ {
+ // Act
+ ConsoleWrapper.SetOut(_writer);
+ Console.WriteLine("Test override");
+
+ // Assert
+ var output = _writer.ToString();
+ Assert.Contains("Test override", output);
}
+
+ [Fact]
+ public void StaticWriteLine_FormatsLogMessageCorrectly()
+ {
+ // Arrange
+ ConsoleWrapper.SetOut(_writer);
+
+ // Act - Using reflection to call internal static method
+ typeof(ConsoleWrapper)
+ .GetMethod("WriteLine", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static,
+ null, new[] { typeof(string), typeof(string) }, null)
+ ?.Invoke(null, new object[] { "INFO", "Test log message" });
+
+ // Assert
+ var output = _writer.ToString();
+ Assert.Matches(@"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z\tINFO\tTest log message", output);
+ }
+
+ [Fact]
+ public void ClearOutputResetFlag_ResetsFlag()
+ {
+ // Arrange
+ var consoleWrapper = new ConsoleWrapper();
+ ConsoleWrapper.SetOut(_writer);
+
+ // Act
+ consoleWrapper.WriteLine("First message"); // Should set the reset flag
+ ConsoleWrapper.ClearOutputResetFlag();
+ consoleWrapper.WriteLine("Second message"); // Should set it again
+
+ // Assert
+ Assert.Equal($"First message{Environment.NewLine}Second message{Environment.NewLine}", _writer.ToString());
+ }
+
+ [Fact]
+ public void Debug_InTestMode_WritesToTestOutputStream()
+ {
+ // Arrange
+ var consoleWrapper = new ConsoleWrapper();
+ ConsoleWrapper.SetOut(_writer);
+
+ // Act
+ consoleWrapper.Debug("debug message");
+
+ // Assert
+ Assert.Equal($"debug message{Environment.NewLine}", _writer.ToString());
+ }
+
+ [Fact]
+ public void Debug_NotInTestMode_WritesToDebugConsole()
+ {
+ // Since capturing Debug output is difficult in a unit test
+ // We'll use a mock or just verify the path doesn't throw
+ // Arrange
+ var consoleWrapper = new ConsoleWrapper();
+ ConsoleWrapper.ResetForTest(); // Ensure we're not in test mode
+
+ // Act & Assert - Just verify it doesn't throw
+ var exception = Record.Exception(() => consoleWrapper.Debug("debug message"));
+ Assert.Null(exception);
+ }
+
+ [Fact]
+ public void Error_DoesNotThrowWhenNotOverridden()
+ {
+ // Arrange
+ var consoleWrapper = new ConsoleWrapper();
+ ConsoleWrapper.ResetForTest(); // Reset to ensure _override is false
+
+ // Act & Assert - Just verify it doesn't throw
+ var exception = Record.Exception(() => consoleWrapper.Error("error without override"));
+ Assert.Null(exception);
+ }
+
[Fact]
- public void WriteLine_WritesMessageToConsole()
- {
- // Arrange
- var consoleWrapper = new ConsoleWrapper();
- var originalOutput = Console.Out;
- using var stringWriter = new StringWriter();
- ConsoleWrapper.SetOut(stringWriter);
-
- try
- {
- // Act
- consoleWrapper.WriteLine("Test message");
-
- // Assert
- var output = stringWriter.ToString();
- Assert.Contains("Test message", output);
- }
- finally
- {
- // Restore original output
- ConsoleWrapper.ResetForTest();
- }
- }
-
- [Fact]
- public void SetOut_OverridesConsoleOutput()
- {
- // Arrange
- var originalOutput = Console.Out;
- using var stringWriter = new StringWriter();
-
- try
- {
- // Act
- typeof(ConsoleWrapper)
- .GetMethod("SetOut", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static)
- ?.Invoke(null, new object[] { stringWriter });
-
- Console.WriteLine("Test override");
-
- // Assert
- var output = stringWriter.ToString();
- Assert.Contains("Test override", output);
- }
- finally
- {
- // Restore original output
- ConsoleWrapper.ResetForTest();
- }
- }
-
- [Fact]
- public void StaticWriteLine_FormatsLogMessageCorrectly()
- {
- // Arrange
- var originalOutput = Console.Out;
- using var stringWriter = new StringWriter();
- ConsoleWrapper.SetOut(stringWriter);
-
- try
- {
- // Act
- typeof(ConsoleWrapper)
- .GetMethod("WriteLine", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static, null, new[] { typeof(string), typeof(string) }, null)
- ?.Invoke(null, new object[] { "INFO", "Test log message" });
-
- // Assert
- var output = stringWriter.ToString();
- Assert.Matches(@"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z\tINFO\tTest log message", output);
- }
- finally
- {
- // Restore original output
- ConsoleWrapper.ResetForTest();
- }
- }
-
- public void Dispose()
- {
- ConsoleWrapper.ResetForTest();
- }
+ public void Error_UsesTestOutputStreamWhenInTestMode()
+ {
+ // Arrange
+ var consoleWrapper = new ConsoleWrapper();
+
+ // Set test mode
+ ConsoleWrapper.SetOut(_writer);
+
+ // Act
+ consoleWrapper.Error("error in test mode");
+
+ // Assert
+ Assert.Contains("error in test mode", _writer.ToString());
+ }
+
+ public void Dispose()
+ {
+ ConsoleWrapper.ResetForTest();
+ _writer?.Dispose();
+ }
}
\ No newline at end of file
diff --git a/libraries/tests/AWS.Lambda.Powertools.Idempotency.Tests/Internal/IdempotentAspectTests.cs b/libraries/tests/AWS.Lambda.Powertools.Idempotency.Tests/Internal/IdempotentAspectTests.cs
index be80a4c45..8cc7e7f99 100644
--- a/libraries/tests/AWS.Lambda.Powertools.Idempotency.Tests/Internal/IdempotentAspectTests.cs
+++ b/libraries/tests/AWS.Lambda.Powertools.Idempotency.Tests/Internal/IdempotentAspectTests.cs
@@ -272,7 +272,7 @@ public void Idempotency_Set_Execution_Environment_Context()
var xRayRecorder = new Idempotency(conf);
// Assert
- Assert.Equal($"{Constants.FeatureContextIdentifier}/Idempotency/1.0.0",
+ Assert.Equal($"{Constants.FeatureContextIdentifier}/Idempotency/{env.GetAssemblyVersion(this)}",
env.GetEnvironmentVariable("AWS_EXECUTION_ENV"));
Assert.NotNull(xRayRecorder);
diff --git a/libraries/tests/AWS.Lambda.Powertools.Logging.Tests/PowertoolsLoggerTest.cs b/libraries/tests/AWS.Lambda.Powertools.Logging.Tests/PowertoolsLoggerTest.cs
index f4ba2a434..099e8a2a2 100644
--- a/libraries/tests/AWS.Lambda.Powertools.Logging.Tests/PowertoolsLoggerTest.cs
+++ b/libraries/tests/AWS.Lambda.Powertools.Logging.Tests/PowertoolsLoggerTest.cs
@@ -1369,7 +1369,7 @@ public void Log_Set_Execution_Environment_Context()
logger.LogInformation("Test");
// Assert
- Assert.Equal($"{Constants.FeatureContextIdentifier}/Logging/1.0.0",
+ Assert.Equal($"{Constants.FeatureContextIdentifier}/Logging/{env.GetAssemblyVersion(this)}",
env.GetEnvironmentVariable("AWS_EXECUTION_ENV"));
}
diff --git a/libraries/tests/AWS.Lambda.Powertools.Metrics.Tests/MetricsTests.cs b/libraries/tests/AWS.Lambda.Powertools.Metrics.Tests/MetricsTests.cs
index adcee3727..a1c1ee515 100644
--- a/libraries/tests/AWS.Lambda.Powertools.Metrics.Tests/MetricsTests.cs
+++ b/libraries/tests/AWS.Lambda.Powertools.Metrics.Tests/MetricsTests.cs
@@ -24,7 +24,7 @@ public void Metrics_Set_Execution_Environment_Context()
_ = new Metrics(conf);
// Assert
- Assert.Equal($"{Constants.FeatureContextIdentifier}/Metrics/1.0.0",
+ Assert.Equal($"{Constants.FeatureContextIdentifier}/Metrics/{env.GetAssemblyVersion(this)}",
env.GetEnvironmentVariable("AWS_EXECUTION_ENV"));
}
diff --git a/libraries/tests/AWS.Lambda.Powertools.Tracing.Tests/XRayRecorderTests.cs b/libraries/tests/AWS.Lambda.Powertools.Tracing.Tests/XRayRecorderTests.cs
index 5318b7b35..a4e9e515c 100644
--- a/libraries/tests/AWS.Lambda.Powertools.Tracing.Tests/XRayRecorderTests.cs
+++ b/libraries/tests/AWS.Lambda.Powertools.Tracing.Tests/XRayRecorderTests.cs
@@ -40,7 +40,7 @@ public void Tracing_Set_Execution_Environment_Context()
var xRayRecorder = new XRayRecorder(awsXray, conf);
// Assert
- Assert.Equal($"{Constants.FeatureContextIdentifier}/Tracing/1.0.0",
+ Assert.Equal($"{Constants.FeatureContextIdentifier}/Tracing/{env.GetAssemblyVersion(this)}",
env.GetEnvironmentVariable("AWS_EXECUTION_ENV"));
Assert.NotNull(xRayRecorder);