Skip to content

chore: Fix execution env verion and ConsoleWrapper for test mode #840

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 8, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/publish-artifacts-examples-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
74 changes: 62 additions & 12 deletions libraries/src/AWS.Lambda.Powertools.Common/Core/ConsoleWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,41 +22,77 @@
public class ConsoleWrapper : IConsoleWrapper
{
private static bool _override;
private static TextWriter _testOutputStream;
private static bool _outputResetPerformed = false;
private static bool _inTestMode = false;

/// <inheritdoc />
public void WriteLine(string message)
{
OverrideLambdaLogger();
Console.WriteLine(message);
if (_inTestMode && _testOutputStream != null)
{
_testOutputStream.WriteLine(message);
}
else
{
EnsureConsoleOutputOnce();
Console.WriteLine(message);
}
}

/// <inheritdoc />
public void Debug(string message)
{
OverrideLambdaLogger();
System.Diagnostics.Debug.WriteLine(message);
if (_inTestMode && _testOutputStream != null)
{
_testOutputStream.WriteLine(message);
}

Check warning on line 49 in libraries/src/AWS.Lambda.Powertools.Common/Core/ConsoleWrapper.cs

View check run for this annotation

Codecov / codecov/patch

libraries/src/AWS.Lambda.Powertools.Common/Core/ConsoleWrapper.cs#L47-L49

Added lines #L47 - L49 were not covered by tests
else
{
EnsureConsoleOutputOnce();
System.Diagnostics.Debug.WriteLine(message);
}

Check warning on line 54 in libraries/src/AWS.Lambda.Powertools.Common/Core/ConsoleWrapper.cs

View check run for this annotation

Codecov / codecov/patch

libraries/src/AWS.Lambda.Powertools.Common/Core/ConsoleWrapper.cs#L51-L54

Added lines #L51 - L54 were not covered by tests
}

/// <inheritdoc />
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
{

Check warning on line 65 in libraries/src/AWS.Lambda.Powertools.Common/Core/ConsoleWrapper.cs

View check run for this annotation

Codecov / codecov/patch

libraries/src/AWS.Lambda.Powertools.Common/Core/ConsoleWrapper.cs#L65

Added line #L65 was not covered by tests
if (!_override)
{
var errordOutput = new StreamWriter(Console.OpenStandardError());
errordOutput.AutoFlush = true;
Console.SetError(errordOutput);
}
Console.Error.WriteLine(message);

Check warning on line 72 in libraries/src/AWS.Lambda.Powertools.Common/Core/ConsoleWrapper.cs

View check run for this annotation

Codecov / codecov/patch

libraries/src/AWS.Lambda.Powertools.Common/Core/ConsoleWrapper.cs#L67-L72

Added lines #L67 - L72 were not covered by tests
}

Console.Error.WriteLine(message);
}

internal static void SetOut(StringWriter consoleOut)
/// <summary>
/// Set the ConsoleWrapper to use a different TextWriter
/// This is useful for unit tests where you want to capture the output
/// </summary>
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)
{
Expand All @@ -73,8 +109,22 @@
Console.WriteLine($"{DateTime.UtcNow:yyyy-MM-ddTHH:mm:ss.fffZ}\t{logLevel}\t{message}");
}

/// <summary>
/// Reset the ConsoleWrapper to its original state
/// </summary>
public static void ResetForTest()
{
_override = false;
_inTestMode = false;
_testOutputStream = null;
_outputResetPerformed = false;
}

/// <summary>
/// Clear the output reset flag
/// </summary>
public static void ClearOutputResetFlag()
{
_outputResetPerformed = false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
Expand All @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,159 +6,136 @@ 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]
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]
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 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();
}
}
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);

[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();
}
}
// Act
consoleWrapper.WriteLine("First message"); // Should set the reset flag
ConsoleWrapper.ClearOutputResetFlag();
consoleWrapper.WriteLine("Second message"); // Should set it again

[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();
}
// Assert
Assert.Equal($"First message{Environment.NewLine}Second message{Environment.NewLine}", _writer.ToString());
}

public void Dispose()
{
ConsoleWrapper.ResetForTest();
_writer?.Dispose();
}
}
Loading
Loading