diff --git a/Libraries/src/Amazon.Lambda.RuntimeSupport/Helpers/ConsoleLoggerWriter.cs b/Libraries/src/Amazon.Lambda.RuntimeSupport/Helpers/ConsoleLoggerWriter.cs
index 2caa708e3..a2417cbcc 100644
--- a/Libraries/src/Amazon.Lambda.RuntimeSupport/Helpers/ConsoleLoggerWriter.cs
+++ b/Libraries/src/Amazon.Lambda.RuntimeSupport/Helpers/ConsoleLoggerWriter.cs
@@ -227,6 +227,7 @@ public LogLevelLoggerWriter(IEnvironmentVariables environmentVariables)
///
public LogLevelLoggerWriter(TextWriter stdOutWriter, TextWriter stdErrorWriter)
{
+ _environmentVariables = new SystemEnvironmentVariables();
Initialize(stdOutWriter, stdErrorWriter);
}
@@ -325,7 +326,7 @@ public IRuntimeApiHeaders CurrentRuntimeApiHeaders
{
get
{
- if (Utils.IsUsingMultiConcurrency(_environmentVariables))
+ if (_currentRuntimeApiHeadersStorage != null && Utils.IsUsingMultiConcurrency(_environmentVariables))
{
return _currentRuntimeApiHeadersStorage.Value;
}
@@ -333,7 +334,7 @@ public IRuntimeApiHeaders CurrentRuntimeApiHeaders
}
set
{
- if (Utils.IsUsingMultiConcurrency(_environmentVariables))
+ if (_currentRuntimeApiHeadersStorage != null && Utils.IsUsingMultiConcurrency(_environmentVariables))
{
_currentRuntimeApiHeadersStorage.Value = value;
}
diff --git a/Libraries/test/Amazon.Lambda.RuntimeSupport.Tests/Amazon.Lambda.RuntimeSupport.UnitTests/HandlerTests.cs b/Libraries/test/Amazon.Lambda.RuntimeSupport.Tests/Amazon.Lambda.RuntimeSupport.UnitTests/HandlerTests.cs
index 80f9d13d0..20340f561 100644
--- a/Libraries/test/Amazon.Lambda.RuntimeSupport.Tests/Amazon.Lambda.RuntimeSupport.UnitTests/HandlerTests.cs
+++ b/Libraries/test/Amazon.Lambda.RuntimeSupport.Tests/Amazon.Lambda.RuntimeSupport.UnitTests/HandlerTests.cs
@@ -250,7 +250,7 @@ private async Task TestHandlerFailAsync(string handler, string expect
var userCodeLoader = new UserCodeLoader(new SystemEnvironmentVariables(), handler, _internalLogger);
var initializer = new UserCodeInitializer(userCodeLoader, _internalLogger);
var handlerWrapper = HandlerWrapper.GetHandlerWrapper(userCodeLoader.Invoke);
- var bootstrap = new LambdaBootstrap(handlerWrapper, initializer.InitializeAsync)
+ var bootstrap = new LambdaBootstrap(handlerWrapper.Handler, initializer.InitializeAsync, null, _environmentVariables)
{
Client = testRuntimeApiClient
};
@@ -388,7 +388,9 @@ private async Task ExecHandlerAsync(string handler, string dataIn
var userCodeLoader = new UserCodeLoader(new SystemEnvironmentVariables(), handler, _internalLogger);
var handlerWrapper = HandlerWrapper.GetHandlerWrapper(userCodeLoader.Invoke);
var initializer = new UserCodeInitializer(userCodeLoader, _internalLogger);
- var bootstrap = new LambdaBootstrap(handlerWrapper, initializer.InitializeAsync)
+ // Pass null initializer to bootstrap so RunAsync won't re-invoke Init(),
+ // which would re-register AssemblyLoad event handlers and re-construct the invoke delegate.
+ var bootstrap = new LambdaBootstrap(handlerWrapper.Handler, null, null, _environmentVariables)
{
Client = testRuntimeApiClient
};
@@ -403,7 +405,13 @@ private async Task ExecHandlerAsync(string handler, string dataIn
Assert.DoesNotContain($"^^[{assertLoggedByInitialize}]^^", actionWriter.ToString());
}
- await bootstrap.InitializeAsync();
+ await initializer.InitializeAsync();
+
+ // Re-set logging actions after initialization in case Init's AssemblyLoad event
+ // handler overwrote them when loading Amazon.Lambda.Core as a handler dependency.
+ UserCodeLoader.SetCustomerLoggerLogAction(assembly, actionWriter.ToLoggingAction(), _internalLogger);
+ UserCodeLoader.SetCustomerLoggerLogAction(assembly, actionWriter.ToLoggingWithLevelAction(), _internalLogger);
+ UserCodeLoader.SetCustomerLoggerLogAction(assembly, actionWriter.ToLoggingWithLevelAndExceptionAction(), _internalLogger);
if (assertLoggedByInitialize != null)
{
diff --git a/Libraries/test/Amazon.Lambda.RuntimeSupport.Tests/Amazon.Lambda.RuntimeSupport.UnitTests/LambdaBootstrapTests.cs b/Libraries/test/Amazon.Lambda.RuntimeSupport.Tests/Amazon.Lambda.RuntimeSupport.UnitTests/LambdaBootstrapTests.cs
index e1636ff16..97b40cb60 100644
--- a/Libraries/test/Amazon.Lambda.RuntimeSupport.Tests/Amazon.Lambda.RuntimeSupport.UnitTests/LambdaBootstrapTests.cs
+++ b/Libraries/test/Amazon.Lambda.RuntimeSupport.Tests/Amazon.Lambda.RuntimeSupport.UnitTests/LambdaBootstrapTests.cs
@@ -165,7 +165,7 @@ public async Task TraceIdEnvironmentVariableIsSet()
[Fact]
public async Task HandlerThrowsException()
{
- using (var bootstrap = new LambdaBootstrap(_testFunction.BaseHandlerThrowsAsync, null))
+ using (var bootstrap = new LambdaBootstrap(_testFunction.BaseHandlerThrowsAsync, null, null, _environmentVariables))
{
bootstrap.Client = _testRuntimeApiClient;
Assert.Null(_environmentVariables.GetEnvironmentVariable(LambdaEnvironment.EnvVarTraceId));
@@ -183,7 +183,7 @@ public async Task HandlerInputAndOutputWork()
{
const string testInput = "a MiXeD cAsE sTrInG";
- using (var bootstrap = new LambdaBootstrap(_testFunction.BaseHandlerToUpperAsync, null))
+ using (var bootstrap = new LambdaBootstrap(_testFunction.BaseHandlerToUpperAsync, null, null, _environmentVariables))
{
_testRuntimeApiClient.FunctionInput = Encoding.UTF8.GetBytes(testInput);
bootstrap.Client = _testRuntimeApiClient;
@@ -201,7 +201,7 @@ public async Task HandlerInputAndOutputWork()
[Fact]
public async Task HandlerReturnsNull()
{
- using (var bootstrap = new LambdaBootstrap(_testFunction.BaseHandlerReturnsNullAsync, null))
+ using (var bootstrap = new LambdaBootstrap(_testFunction.BaseHandlerReturnsNullAsync, null, null, _environmentVariables))
{
_testRuntimeApiClient.FunctionInput = new byte[0];
bootstrap.Client = _testRuntimeApiClient;
diff --git a/README.md b/README.md
index 405e952a5..37f6a1d3e 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# AWS Lambda for .NET
+# AWS Lambda for .NET (Draft)
Repository for the AWS NuGet packages and Blueprints to support writing AWS Lambda functions using .NET Core.
diff --git a/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.IntegrationTests/BaseApiGatewayTest.cs b/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.IntegrationTests/BaseApiGatewayTest.cs
index f277ffa2a..c9998141c 100644
--- a/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.IntegrationTests/BaseApiGatewayTest.cs
+++ b/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.IntegrationTests/BaseApiGatewayTest.cs
@@ -48,6 +48,7 @@ protected async Task CleanupAsync()
CancellationTokenSource.Dispose();
CancellationTokenSource = new CancellationTokenSource();
}
+ Environment.SetEnvironmentVariable("APIGATEWAY_EMULATOR_ROUTE_CONFIG", null);
}
protected async Task StartTestToolProcessAsync(ApiGatewayEmulatorMode apiGatewayMode, string routeName, int lambdaPort, int apiGatewayPort, CancellationTokenSource cancellationTokenSource, string httpMethod = "POST")
diff --git a/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.IntegrationTests/SQSEventSourceTests.cs b/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.IntegrationTests/SQSEventSourceTests.cs
index fc4aa1882..f02ee3abe 100644
--- a/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.IntegrationTests/SQSEventSourceTests.cs
+++ b/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.IntegrationTests/SQSEventSourceTests.cs
@@ -183,7 +183,7 @@ public async Task ProcessMessagesFromMultipleEventSources()
await sqsClient.SendMessageAsync(queueUrl2, "MessageFromQueue2");
var startTime = DateTime.UtcNow;
- while (listOfProcessedMessages.Count == 0 && DateTime.UtcNow < startTime.AddMinutes(2))
+ while (listOfProcessedMessages.Count < 2 && DateTime.UtcNow < startTime.AddMinutes(2))
{
Assert.False(lambdaTask.IsFaulted, "Lambda function failed: " + lambdaTask.Exception?.ToString());
await Task.Delay(500);
diff --git a/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.Tests.Common/Helpers/TestHelpers.cs b/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.Tests.Common/Helpers/TestHelpers.cs
index 79c618d48..9def24fe2 100644
--- a/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.Tests.Common/Helpers/TestHelpers.cs
+++ b/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.Tests.Common/Helpers/TestHelpers.cs
@@ -1,6 +1,9 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
+using System.Net;
+using System.Net.Sockets;
+
namespace Amazon.Lambda.TestTool.Tests.Common.Helpers;
public static class TestHelpers
@@ -39,16 +42,22 @@ public static async Task SendRequest(string url)
}
}
- private static int _maxLambdaRuntimePort = 6000;
- private static int _maxApiGatewayPort = 9000;
+ private static int GetFreePort()
+ {
+ var listener = new TcpListener(IPAddress.Loopback, 0);
+ listener.Start();
+ var port = ((IPEndPoint)listener.LocalEndpoint).Port;
+ listener.Stop();
+ return port;
+ }
public static int GetNextLambdaRuntimePort()
{
- return Interlocked.Increment(ref _maxLambdaRuntimePort);
+ return GetFreePort();
}
public static int GetNextApiGatewayPort()
{
- return Interlocked.Increment(ref _maxApiGatewayPort);
+ return GetFreePort();
}
}
diff --git a/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.UnitTests/RuntimeApiTests.cs b/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.UnitTests/RuntimeApiTests.cs
index 998460411..cb2afa01a 100644
--- a/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.UnitTests/RuntimeApiTests.cs
+++ b/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.UnitTests/RuntimeApiTests.cs
@@ -39,6 +39,8 @@ public async Task AddEventToDataStore()
var testToolProcess = TestToolProcess.Startup(options, cancellationTokenSource.Token);
try
{
+ Assert.True(await TestHelpers.WaitForApiToStartAsync($"{testToolProcess.ServiceUrl}/lambda-runtime-api/healthcheck"));
+
var lambdaClient = ConstructLambdaServiceClient(testToolProcess.ServiceUrl);
var invokeFunction = new InvokeRequest
{
@@ -92,6 +94,8 @@ public async Task InvokeRequestResponse()
var testToolProcess = TestToolProcess.Startup(options, cancellationTokenSource.Token);
try
{
+ Assert.True(await TestHelpers.WaitForApiToStartAsync($"{testToolProcess.ServiceUrl}/lambda-runtime-api/healthcheck"));
+
var handler = (string input, ILambdaContext context) =>
{
Thread.Sleep(1000); // Add a sleep to prove the LambdaRuntimeApi waited for the completion.
diff --git a/Tools/LambdaTestTool/src/Amazon.Lambda.TestTool/TestToolStartup.cs b/Tools/LambdaTestTool/src/Amazon.Lambda.TestTool/TestToolStartup.cs
index 9693d64e4..87353be34 100644
--- a/Tools/LambdaTestTool/src/Amazon.Lambda.TestTool/TestToolStartup.cs
+++ b/Tools/LambdaTestTool/src/Amazon.Lambda.TestTool/TestToolStartup.cs
@@ -10,7 +10,6 @@ namespace Amazon.Lambda.TestTool
{
public class TestToolStartup
{
- private static bool shouldDisableLogs;
public class RunConfiguration
{
@@ -37,7 +36,7 @@ public static void Startup(string productName, Action
try
{
var commandOptions = CommandLineOptions.Parse(args);
- shouldDisableLogs = Utils.ShouldDisableLogs(commandOptions);
+ var shouldDisableLogs = Utils.ShouldDisableLogs(commandOptions);
if (!shouldDisableLogs) Utils.PrintToolTitle(productName);
@@ -76,7 +75,7 @@ public static void Startup(string productName, Action
if (commandOptions.NoUI)
{
- ExecuteWithNoUi(localLambdaOptions, commandOptions, lambdaAssemblyDirectory, runConfiguration);
+ ExecuteWithNoUi(localLambdaOptions, commandOptions, lambdaAssemblyDirectory, runConfiguration, shouldDisableLogs);
}
else
{
@@ -118,16 +117,16 @@ public static void Startup(string productName, Action
}
- public static void ExecuteWithNoUi(LocalLambdaOptions localLambdaOptions, CommandLineOptions commandOptions, string lambdaAssemblyDirectory, RunConfiguration runConfiguration)
+ public static void ExecuteWithNoUi(LocalLambdaOptions localLambdaOptions, CommandLineOptions commandOptions, string lambdaAssemblyDirectory, RunConfiguration runConfiguration, bool shouldDisableLogs)
{
if (!shouldDisableLogs) runConfiguration.OutputWriter.WriteLine("Executing Lambda function without web interface");
var lambdaProjectDirectory = Utils.FindLambdaProjectDirectory(lambdaAssemblyDirectory);
- string configFile = DetermineConfigFile(commandOptions, lambdaAssemblyDirectory: lambdaAssemblyDirectory, lambdaProjectDirectory: lambdaProjectDirectory);
- LambdaConfigInfo configInfo = LoadLambdaConfigInfo(configFile, commandOptions, lambdaAssemblyDirectory: lambdaAssemblyDirectory, lambdaProjectDirectory: lambdaProjectDirectory, runConfiguration);
- LambdaFunction lambdaFunction = LoadLambdaFunction(configInfo, localLambdaOptions, commandOptions, lambdaAssemblyDirectory: lambdaAssemblyDirectory, lambdaProjectDirectory: lambdaProjectDirectory, runConfiguration);
+ string configFile = DetermineConfigFile(commandOptions, lambdaAssemblyDirectory: lambdaAssemblyDirectory, lambdaProjectDirectory: lambdaProjectDirectory, shouldDisableLogs: shouldDisableLogs);
+ LambdaConfigInfo configInfo = LoadLambdaConfigInfo(configFile, commandOptions, lambdaAssemblyDirectory: lambdaAssemblyDirectory, lambdaProjectDirectory: lambdaProjectDirectory, runConfiguration, shouldDisableLogs: shouldDisableLogs);
+ LambdaFunction lambdaFunction = LoadLambdaFunction(configInfo, localLambdaOptions, commandOptions, lambdaAssemblyDirectory: lambdaAssemblyDirectory, lambdaProjectDirectory: lambdaProjectDirectory, runConfiguration, shouldDisableLogs: shouldDisableLogs);
- string payload = DeterminePayload(localLambdaOptions, commandOptions, lambdaAssemblyDirectory: lambdaAssemblyDirectory, lambdaProjectDirectory: lambdaProjectDirectory, runConfiguration);
+ string payload = DeterminePayload(localLambdaOptions, commandOptions, lambdaAssemblyDirectory: lambdaAssemblyDirectory, lambdaProjectDirectory: lambdaProjectDirectory, runConfiguration, shouldDisableLogs: shouldDisableLogs);
var awsProfile = commandOptions.AWSProfile ?? configInfo.AWSProfile;
if (!string.IsNullOrEmpty(awsProfile))
@@ -166,7 +165,7 @@ public static void ExecuteWithNoUi(LocalLambdaOptions localLambdaOptions, Comman
Function = lambdaFunction
};
- ExecuteRequest(request, localLambdaOptions, runConfiguration);
+ ExecuteRequest(request, localLambdaOptions, runConfiguration, shouldDisableLogs);
if (runConfiguration.Mode == RunConfiguration.RunMode.Normal && commandOptions.PauseExit)
@@ -176,7 +175,7 @@ public static void ExecuteWithNoUi(LocalLambdaOptions localLambdaOptions, Comman
}
}
- private static string DetermineConfigFile(CommandLineOptions commandOptions, string lambdaAssemblyDirectory, string lambdaProjectDirectory)
+ private static string DetermineConfigFile(CommandLineOptions commandOptions, string lambdaAssemblyDirectory, string lambdaProjectDirectory, bool shouldDisableLogs)
{
string configFile = null;
if (string.IsNullOrEmpty(commandOptions.ConfigFile))
@@ -199,7 +198,7 @@ private static string DetermineConfigFile(CommandLineOptions commandOptions, str
return configFile;
}
- private static LambdaConfigInfo LoadLambdaConfigInfo(string configFile, CommandLineOptions commandOptions, string lambdaAssemblyDirectory, string lambdaProjectDirectory, RunConfiguration runConfiguration)
+ private static LambdaConfigInfo LoadLambdaConfigInfo(string configFile, CommandLineOptions commandOptions, string lambdaAssemblyDirectory, string lambdaProjectDirectory, RunConfiguration runConfiguration, bool shouldDisableLogs)
{
LambdaConfigInfo configInfo;
if (configFile != null)
@@ -226,7 +225,7 @@ private static LambdaConfigInfo LoadLambdaConfigInfo(string configFile, CommandL
return configInfo;
}
- private static LambdaFunction LoadLambdaFunction(LambdaConfigInfo configInfo, LocalLambdaOptions localLambdaOptions, CommandLineOptions commandOptions, string lambdaAssemblyDirectory, string lambdaProjectDirectory, RunConfiguration runConfiguration)
+ private static LambdaFunction LoadLambdaFunction(LambdaConfigInfo configInfo, LocalLambdaOptions localLambdaOptions, CommandLineOptions commandOptions, string lambdaAssemblyDirectory, string lambdaProjectDirectory, RunConfiguration runConfiguration, bool shouldDisableLogs)
{
// If no function handler was explicitly set and there is only one function defined in the config file then assume the user wants to debug that function.
var functionHandler = commandOptions.FunctionHandler;
@@ -264,7 +263,7 @@ private static LambdaFunction LoadLambdaFunction(LambdaConfigInfo configInfo, Lo
return lambdaFunction;
}
- private static string DeterminePayload(LocalLambdaOptions localLambdaOptions, CommandLineOptions commandOptions, string lambdaAssemblyDirectory, string lambdaProjectDirectory, RunConfiguration runConfiguration)
+ private static string DeterminePayload(LocalLambdaOptions localLambdaOptions, CommandLineOptions commandOptions, string lambdaAssemblyDirectory, string lambdaProjectDirectory, RunConfiguration runConfiguration, bool shouldDisableLogs)
{
var payload = commandOptions.Payload;
@@ -346,7 +345,7 @@ private static string DeterminePayload(LocalLambdaOptions localLambdaOptions, Co
return payload;
}
- private static void ExecuteRequest(ExecutionRequest request, LocalLambdaOptions localLambdaOptions, RunConfiguration runConfiguration)
+ private static void ExecuteRequest(ExecutionRequest request, LocalLambdaOptions localLambdaOptions, RunConfiguration runConfiguration, bool shouldDisableLogs)
{
try
{