diff --git a/LambdaRuntimeDockerfiles/Images/net6/amd64/Dockerfile b/LambdaRuntimeDockerfiles/Images/net6/amd64/Dockerfile
index 2e552da90..3d317c5e3 100644
--- a/LambdaRuntimeDockerfiles/Images/net6/amd64/Dockerfile
+++ b/LambdaRuntimeDockerfiles/Images/net6/amd64/Dockerfile
@@ -18,7 +18,7 @@ WORKDIR /dotnet
RUN yum install tar gzip --assumeyes
# Install the ASP.NET Core shared framework
-RUN curl -SL --output aspnetcore.tar.gz https://dotnetcli.azureedge.net/dotnet/aspnetcore/Runtime/$ASPNET_VERSION/aspnetcore-runtime-$ASPNET_VERSION-linux-x64.tar.gz \
+RUN curl -SL --output aspnetcore.tar.gz https://builds.dotnet.microsoft.com/dotnet/aspnetcore/Runtime/$ASPNET_VERSION/aspnetcore-runtime-$ASPNET_VERSION-linux-x64.tar.gz \
&& aspnetcore_sha512=$ASPNET_SHA512 \
&& echo "$aspnetcore_sha512 aspnetcore.tar.gz" | sha512sum -c - \
&& tar -ozxf aspnetcore.tar.gz -C /dotnet \
diff --git a/LambdaRuntimeDockerfiles/Images/net6/arm64/Dockerfile b/LambdaRuntimeDockerfiles/Images/net6/arm64/Dockerfile
index f7464267c..2f7db39e3 100644
--- a/LambdaRuntimeDockerfiles/Images/net6/arm64/Dockerfile
+++ b/LambdaRuntimeDockerfiles/Images/net6/arm64/Dockerfile
@@ -48,7 +48,7 @@ WORKDIR /dotnet
RUN yum install tar gzip --assumeyes
# Install the ASP.NET Core shared framework
-RUN curl -SL --output aspnetcore.tar.gz https://dotnetcli.azureedge.net/dotnet/aspnetcore/Runtime/$ASPNET_VERSION/aspnetcore-runtime-$ASPNET_VERSION-linux-arm64.tar.gz \
+RUN curl -SL --output aspnetcore.tar.gz https://builds.dotnet.microsoft.com/dotnet/aspnetcore/Runtime/$ASPNET_VERSION/aspnetcore-runtime-$ASPNET_VERSION-linux-arm64.tar.gz \
&& aspnetcore_sha512=$ASPNET_SHA512 \
&& echo "$aspnetcore_sha512 aspnetcore.tar.gz" | sha512sum -c - \
&& tar -ozxf aspnetcore.tar.gz -C /dotnet \
diff --git a/LambdaRuntimeDockerfiles/Images/net8/amd64/Dockerfile b/LambdaRuntimeDockerfiles/Images/net8/amd64/Dockerfile
index b6e283d05..fd606b142 100644
--- a/LambdaRuntimeDockerfiles/Images/net8/amd64/Dockerfile
+++ b/LambdaRuntimeDockerfiles/Images/net8/amd64/Dockerfile
@@ -20,7 +20,7 @@ WORKDIR /dotnet
RUN dnf install tar gzip --assumeyes
# Install the ASP.NET Core shared framework
-RUN curl -SL --output aspnetcore.tar.gz https://dotnetcli.azureedge.net/dotnet/aspnetcore/Runtime/$ASPNET_VERSION/aspnetcore-runtime-$ASPNET_VERSION-linux-x64.tar.gz \
+RUN curl -SL --output aspnetcore.tar.gz https://builds.dotnet.microsoft.com/dotnet/aspnetcore/Runtime/$ASPNET_VERSION/aspnetcore-runtime-$ASPNET_VERSION-linux-x64.tar.gz \
&& aspnetcore_sha512=$ASPNET_SHA512 \
&& echo "$aspnetcore_sha512 aspnetcore.tar.gz" | sha512sum -c - \
&& tar -ozxf aspnetcore.tar.gz -C /dotnet \
diff --git a/LambdaRuntimeDockerfiles/Images/net8/arm64/Dockerfile b/LambdaRuntimeDockerfiles/Images/net8/arm64/Dockerfile
index 17e4131e1..6e21e15ac 100644
--- a/LambdaRuntimeDockerfiles/Images/net8/arm64/Dockerfile
+++ b/LambdaRuntimeDockerfiles/Images/net8/arm64/Dockerfile
@@ -20,7 +20,7 @@ WORKDIR /dotnet
RUN dnf install tar gzip --assumeyes
# Install the ASP.NET Core shared framework
-RUN curl -SL --output aspnetcore.tar.gz https://dotnetcli.azureedge.net/dotnet/aspnetcore/Runtime/$ASPNET_VERSION/aspnetcore-runtime-$ASPNET_VERSION-linux-arm64.tar.gz \
+RUN curl -SL --output aspnetcore.tar.gz https://builds.dotnet.microsoft.com/dotnet/aspnetcore/Runtime/$ASPNET_VERSION/aspnetcore-runtime-$ASPNET_VERSION-linux-arm64.tar.gz \
&& aspnetcore_sha512=$ASPNET_SHA512 \
&& echo "$aspnetcore_sha512 aspnetcore.tar.gz" | sha512sum -c - \
&& tar -ozxf aspnetcore.tar.gz -C /dotnet \
diff --git a/LambdaRuntimeDockerfiles/Images/net9/amd64/Dockerfile b/LambdaRuntimeDockerfiles/Images/net9/amd64/Dockerfile
index 4db7e77f3..a4f33f45b 100644
--- a/LambdaRuntimeDockerfiles/Images/net9/amd64/Dockerfile
+++ b/LambdaRuntimeDockerfiles/Images/net9/amd64/Dockerfile
@@ -20,7 +20,7 @@ WORKDIR /dotnet
RUN dnf install tar gzip --assumeyes
# Install the ASP.NET Core shared framework
-RUN curl -SL --output aspnetcore.tar.gz https://dotnetcli.azureedge.net/dotnet/aspnetcore/Runtime/$ASPNET_VERSION/aspnetcore-runtime-$ASPNET_VERSION-linux-x64.tar.gz \
+RUN curl -SL --output aspnetcore.tar.gz https://builds.dotnet.microsoft.com/dotnet/aspnetcore/Runtime/$ASPNET_VERSION/aspnetcore-runtime-$ASPNET_VERSION-linux-x64.tar.gz \
&& aspnetcore_sha512=$ASPNET_SHA512 \
&& echo "$aspnetcore_sha512 aspnetcore.tar.gz" | sha512sum -c - \
&& tar -ozxf aspnetcore.tar.gz -C /dotnet \
diff --git a/LambdaRuntimeDockerfiles/Images/net9/arm64/Dockerfile b/LambdaRuntimeDockerfiles/Images/net9/arm64/Dockerfile
index a1af81dd7..e37e53352 100644
--- a/LambdaRuntimeDockerfiles/Images/net9/arm64/Dockerfile
+++ b/LambdaRuntimeDockerfiles/Images/net9/arm64/Dockerfile
@@ -20,7 +20,7 @@ WORKDIR /dotnet
RUN dnf install tar gzip --assumeyes
# Install the ASP.NET Core shared framework
-RUN curl -SL --output aspnetcore.tar.gz https://dotnetcli.azureedge.net/dotnet/aspnetcore/Runtime/$ASPNET_VERSION/aspnetcore-runtime-$ASPNET_VERSION-linux-arm64.tar.gz \
+RUN curl -SL --output aspnetcore.tar.gz https://builds.dotnet.microsoft.com/dotnet/aspnetcore/Runtime/$ASPNET_VERSION/aspnetcore-runtime-$ASPNET_VERSION-linux-arm64.tar.gz \
&& aspnetcore_sha512=$ASPNET_SHA512 \
&& echo "$aspnetcore_sha512 aspnetcore.tar.gz" | sha512sum -c - \
&& tar -ozxf aspnetcore.tar.gz -C /dotnet \
diff --git a/Libraries/src/Amazon.Lambda.RuntimeSupport/Amazon.Lambda.RuntimeSupport.csproj b/Libraries/src/Amazon.Lambda.RuntimeSupport/Amazon.Lambda.RuntimeSupport.csproj
index d052fce7b..04405a680 100644
--- a/Libraries/src/Amazon.Lambda.RuntimeSupport/Amazon.Lambda.RuntimeSupport.csproj
+++ b/Libraries/src/Amazon.Lambda.RuntimeSupport/Amazon.Lambda.RuntimeSupport.csproj
@@ -18,6 +18,7 @@
Exe
+ $(DefineConstants);ExecutableOutputType
diff --git a/Libraries/src/Amazon.Lambda.RuntimeSupport/Bootstrap/InvokeDelegateBuilder.cs b/Libraries/src/Amazon.Lambda.RuntimeSupport/Bootstrap/InvokeDelegateBuilder.cs
index cab84397f..0cbbe1829 100644
--- a/Libraries/src/Amazon.Lambda.RuntimeSupport/Bootstrap/InvokeDelegateBuilder.cs
+++ b/Libraries/src/Amazon.Lambda.RuntimeSupport/Bootstrap/InvokeDelegateBuilder.cs
@@ -29,6 +29,9 @@ namespace Amazon.Lambda.RuntimeSupport.Bootstrap
///
/// Builds user delegate from the handler information.
///
+#if NET8_0_OR_GREATER
+ [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("InvokeDelegateBuilder does not support trimming and is meant to be used in class library based Lambda functions.")]
+#endif
internal class InvokeDelegateBuilder
{
private readonly InternalLogger _logger;
diff --git a/Libraries/src/Amazon.Lambda.RuntimeSupport/Program.cs b/Libraries/src/Amazon.Lambda.RuntimeSupport/Program.cs
index b3c7f8d91..8f87eb354 100644
--- a/Libraries/src/Amazon.Lambda.RuntimeSupport/Program.cs
+++ b/Libraries/src/Amazon.Lambda.RuntimeSupport/Program.cs
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
@@ -23,6 +23,8 @@ namespace Amazon.Lambda.RuntimeSupport
{
class Program
{
+
+#if ExecutableOutputType
#if NET8_0_OR_GREATER
[System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode(
"The Main entry point is used in the managed runtime which loads Lambda functions as a class library. " +
@@ -42,6 +44,7 @@ private static async Task Main(string[] args)
RuntimeSupportInitializer runtimeSupportInitializer = new RuntimeSupportInitializer(handler);
await runtimeSupportInitializer.RunLambdaBootstrap();
}
+#endif
#if NET8_0_OR_GREATER
[System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("This code is only exercised in the class library programming model. Native AOT will not use this code path.")]
diff --git a/Tools/LambdaTestTool-v2/Amazon.Lambda.TestTool.sln b/Tools/LambdaTestTool-v2/Amazon.Lambda.TestTool.sln
index da704cc02..e330a0ce2 100644
--- a/Tools/LambdaTestTool-v2/Amazon.Lambda.TestTool.sln
+++ b/Tools/LambdaTestTool-v2/Amazon.Lambda.TestTool.sln
@@ -6,21 +6,11 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Amazon.Lambda.TestTool", "s
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{0AB3BF05-4346-4AA6-1389-037BE0695223}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Amazon.Lambda.TestTool.Tests.Common", "tests\Amazon.Lambda.TestTool.Tests.Common\Amazon.Lambda.TestTool.Tests.Common.csproj", "{E4D6D10C-C65F-E5E7-F865-FA931477FBCC}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Amazon.Lambda.TestTool.UnitTests", "tests\Amazon.Lambda.TestTool.UnitTests\Amazon.Lambda.TestTool.UnitTests.csproj", "{80A4F809-28B7-61EC-6539-DF3C7A0733FD}"
-EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Amazon.Lambda.TestTool.IntegrationTests", "tests\Amazon.Lambda.TestTool.IntegrationTests\Amazon.Lambda.TestTool.IntegrationTests.csproj", "{F7B6DF0E-EEB2-4B3F-47B7-49B188A2A216}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LambdaTestFunctionV2", "testapps\LambdaTestFunctionV2\LambdaTestFunctionV2.csproj", "{803C76E6-8804-A4DF-8896-DDBC9FBEE8DD}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LambdaBinaryFunction", "testapps\LambdaBinaryFunction\LambdaBinaryFunction.csproj", "{F625BA55-B999-6F5D-4DA1-9D4C77996D6A}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LambdaReturnStringFunction", "testapps\LambdaReturnStringFunction\LambdaReturnStringFunction.csproj", "{54F64435-2082-3F4E-D3A8-B90BE58EF2EB}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LambdaTestFunctionV1", "testapps\LambdaTestFunctionV1\LambdaTestFunctionV1.csproj", "{B532EEC5-2AA9-88BA-8D0B-46ECC392791A}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Amazon.Lambda.TestTool.Tests.Common", "tests\Amazon.Lambda.TestTool.Tests.Common\Amazon.Lambda.TestTool.Tests.Common.csproj", "{E4D6D10C-C65F-E5E7-F865-FA931477FBCC}"
EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "testapps", "testapps", "{4553EF99-1D3C-14C7-0D22-5364D18C373B}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Amazon.Lambda.TestTool.UnitTests", "tests\Amazon.Lambda.TestTool.UnitTests\Amazon.Lambda.TestTool.UnitTests.csproj", "{80A4F809-28B7-61EC-6539-DF3C7A0733FD}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -32,6 +22,10 @@ Global
{97EE2E8A-D1F4-CB11-B664-B99B036E9F7B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{97EE2E8A-D1F4-CB11-B664-B99B036E9F7B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{97EE2E8A-D1F4-CB11-B664-B99B036E9F7B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F7B6DF0E-EEB2-4B3F-47B7-49B188A2A216}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F7B6DF0E-EEB2-4B3F-47B7-49B188A2A216}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F7B6DF0E-EEB2-4B3F-47B7-49B188A2A216}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F7B6DF0E-EEB2-4B3F-47B7-49B188A2A216}.Release|Any CPU.Build.0 = Release|Any CPU
{E4D6D10C-C65F-E5E7-F865-FA931477FBCC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E4D6D10C-C65F-E5E7-F865-FA931477FBCC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E4D6D10C-C65F-E5E7-F865-FA931477FBCC}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -40,33 +34,9 @@ Global
{80A4F809-28B7-61EC-6539-DF3C7A0733FD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{80A4F809-28B7-61EC-6539-DF3C7A0733FD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{80A4F809-28B7-61EC-6539-DF3C7A0733FD}.Release|Any CPU.Build.0 = Release|Any CPU
- {F7B6DF0E-EEB2-4B3F-47B7-49B188A2A216}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {F7B6DF0E-EEB2-4B3F-47B7-49B188A2A216}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {F7B6DF0E-EEB2-4B3F-47B7-49B188A2A216}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {F7B6DF0E-EEB2-4B3F-47B7-49B188A2A216}.Release|Any CPU.Build.0 = Release|Any CPU
- {803C76E6-8804-A4DF-8896-DDBC9FBEE8DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {803C76E6-8804-A4DF-8896-DDBC9FBEE8DD}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {803C76E6-8804-A4DF-8896-DDBC9FBEE8DD}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {803C76E6-8804-A4DF-8896-DDBC9FBEE8DD}.Release|Any CPU.Build.0 = Release|Any CPU
- {F625BA55-B999-6F5D-4DA1-9D4C77996D6A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {F625BA55-B999-6F5D-4DA1-9D4C77996D6A}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {F625BA55-B999-6F5D-4DA1-9D4C77996D6A}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {F625BA55-B999-6F5D-4DA1-9D4C77996D6A}.Release|Any CPU.Build.0 = Release|Any CPU
- {54F64435-2082-3F4E-D3A8-B90BE58EF2EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {54F64435-2082-3F4E-D3A8-B90BE58EF2EB}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {54F64435-2082-3F4E-D3A8-B90BE58EF2EB}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {54F64435-2082-3F4E-D3A8-B90BE58EF2EB}.Release|Any CPU.Build.0 = Release|Any CPU
- {B532EEC5-2AA9-88BA-8D0B-46ECC392791A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {B532EEC5-2AA9-88BA-8D0B-46ECC392791A}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {B532EEC5-2AA9-88BA-8D0B-46ECC392791A}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {B532EEC5-2AA9-88BA-8D0B-46ECC392791A}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{97EE2E8A-D1F4-CB11-B664-B99B036E9F7B} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
- {F625BA55-B999-6F5D-4DA1-9D4C77996D6A} = {4553EF99-1D3C-14C7-0D22-5364D18C373B}
- {54F64435-2082-3F4E-D3A8-B90BE58EF2EB} = {4553EF99-1D3C-14C7-0D22-5364D18C373B}
- {B532EEC5-2AA9-88BA-8D0B-46ECC392791A} = {4553EF99-1D3C-14C7-0D22-5364D18C373B}
- {803C76E6-8804-A4DF-8896-DDBC9FBEE8DD} = {4553EF99-1D3C-14C7-0D22-5364D18C373B}
{F7B6DF0E-EEB2-4B3F-47B7-49B188A2A216} = {0AB3BF05-4346-4AA6-1389-037BE0695223}
{E4D6D10C-C65F-E5E7-F865-FA931477FBCC} = {0AB3BF05-4346-4AA6-1389-037BE0695223}
{80A4F809-28B7-61EC-6539-DF3C7A0733FD} = {0AB3BF05-4346-4AA6-1389-037BE0695223}
diff --git a/Tools/LambdaTestTool-v2/Amazon.Lambda.TestTool.slnx b/Tools/LambdaTestTool-v2/Amazon.Lambda.TestTool.slnx
index 5db12de26..825c06bd2 100644
--- a/Tools/LambdaTestTool-v2/Amazon.Lambda.TestTool.slnx
+++ b/Tools/LambdaTestTool-v2/Amazon.Lambda.TestTool.slnx
@@ -2,12 +2,6 @@
-
-
-
-
-
-
diff --git a/Tools/LambdaTestTool-v2/src/Amazon.Lambda.TestTool/Amazon.Lambda.TestTool.csproj b/Tools/LambdaTestTool-v2/src/Amazon.Lambda.TestTool/Amazon.Lambda.TestTool.csproj
index 697bab855..269a796ce 100644
--- a/Tools/LambdaTestTool-v2/src/Amazon.Lambda.TestTool/Amazon.Lambda.TestTool.csproj
+++ b/Tools/LambdaTestTool-v2/src/Amazon.Lambda.TestTool/Amazon.Lambda.TestTool.csproj
@@ -1,4 +1,4 @@
-
+
A tool to help debug and test your .NET AWS Lambda functions locally.
@@ -34,17 +34,18 @@
-
-
-
+
-
+
+
+
+
true
diff --git a/Tools/LambdaTestTool-v2/testapps/LambdaBinaryFunction/Function.cs b/Tools/LambdaTestTool-v2/testapps/LambdaBinaryFunction/Function.cs
deleted file mode 100644
index 8aa5a121b..000000000
--- a/Tools/LambdaTestTool-v2/testapps/LambdaBinaryFunction/Function.cs
+++ /dev/null
@@ -1,29 +0,0 @@
-using Amazon.Lambda.APIGatewayEvents;
-using Amazon.Lambda.Core;
-using Amazon.Lambda.RuntimeSupport;
-using Amazon.Lambda.Serialization.SystemTextJson;
-
-var GenerateBinary = (APIGatewayHttpApiV2ProxyRequest request, ILambdaContext context) =>
-{
- // Create a simple binary pattern (for example, counting bytes from 0 to 255)
- byte[] binaryData = new byte[256];
- for (int i = 0; i < 256; i++)
- {
- binaryData[i] = (byte)i;
- }
-
- return new APIGatewayHttpApiV2ProxyResponse
- {
- StatusCode = 200,
- Body = Convert.ToBase64String(binaryData),
- IsBase64Encoded = true,
- Headers = new Dictionary
- {
- { "Content-Type", "application/octet-stream" }
- }
- };
-};
-
-await LambdaBootstrapBuilder.Create(GenerateBinary, new CamelCaseLambdaJsonSerializer())
- .Build()
- .RunAsync();
diff --git a/Tools/LambdaTestTool-v2/testapps/LambdaBinaryFunction/LambdaBinaryFunction.csproj b/Tools/LambdaTestTool-v2/testapps/LambdaBinaryFunction/LambdaBinaryFunction.csproj
deleted file mode 100644
index 3fc64eafd..000000000
--- a/Tools/LambdaTestTool-v2/testapps/LambdaBinaryFunction/LambdaBinaryFunction.csproj
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
- Exe
- net8.0
- enable
- enable
- true
- Lambda
-
- true
-
- true
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Tools/LambdaTestTool-v2/testapps/LambdaBinaryFunction/aws-lambda-tools-defaults.json b/Tools/LambdaTestTool-v2/testapps/LambdaBinaryFunction/aws-lambda-tools-defaults.json
deleted file mode 100644
index f852b483b..000000000
--- a/Tools/LambdaTestTool-v2/testapps/LambdaBinaryFunction/aws-lambda-tools-defaults.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "Information": [
- "This file provides default values for the deployment wizard inside Visual Studio and the AWS Lambda commands added to the .NET Core CLI.",
- "To learn more about the Lambda commands with the .NET Core CLI execute the following command at the command line in the project root directory.",
- "dotnet lambda help",
- "All the command line options for the Lambda command can be specified in this file."
- ],
- "profile": "",
- "region": "",
- "configuration": "Release",
- "function-runtime": "dotnet8",
- "function-memory-size": 512,
- "function-timeout": 30,
- "function-handler": "LambdaBinaryFunction"
-}
\ No newline at end of file
diff --git a/Tools/LambdaTestTool-v2/testapps/LambdaReturnStringFunction/Function.cs b/Tools/LambdaTestTool-v2/testapps/LambdaReturnStringFunction/Function.cs
deleted file mode 100644
index 4b00804e4..000000000
--- a/Tools/LambdaTestTool-v2/testapps/LambdaReturnStringFunction/Function.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-using Amazon.Lambda.APIGatewayEvents;
-using Amazon.Lambda.Core;
-using Amazon.Lambda.RuntimeSupport;
-using Amazon.Lambda.Serialization.SystemTextJson;
-
-var ToUpper = (APIGatewayHttpApiV2ProxyRequest request, ILambdaContext context) =>
-{
- return request.Body.ToUpper();
-};
-
-await LambdaBootstrapBuilder.Create(ToUpper, new CamelCaseLambdaJsonSerializer())
- .Build()
- .RunAsync();
diff --git a/Tools/LambdaTestTool-v2/testapps/LambdaReturnStringFunction/LambdaReturnStringFunction.csproj b/Tools/LambdaTestTool-v2/testapps/LambdaReturnStringFunction/LambdaReturnStringFunction.csproj
deleted file mode 100644
index ca9ce679b..000000000
--- a/Tools/LambdaTestTool-v2/testapps/LambdaReturnStringFunction/LambdaReturnStringFunction.csproj
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
- Exe
- net8.0
- enable
- enable
- true
- Lambda
-
- true
-
- true
- LambdaReturnString
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Tools/LambdaTestTool-v2/testapps/LambdaReturnStringFunction/aws-lambda-tools-defaults.json b/Tools/LambdaTestTool-v2/testapps/LambdaReturnStringFunction/aws-lambda-tools-defaults.json
deleted file mode 100644
index 188e71395..000000000
--- a/Tools/LambdaTestTool-v2/testapps/LambdaReturnStringFunction/aws-lambda-tools-defaults.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "Information": [
- "This file provides default values for the deployment wizard inside Visual Studio and the AWS Lambda commands added to the .NET Core CLI.",
- "To learn more about the Lambda commands with the .NET Core CLI execute the following command at the command line in the project root directory.",
- "dotnet lambda help",
- "All the command line options for the Lambda command can be specified in this file."
- ],
- "profile": "",
- "region": "",
- "configuration": "Release",
- "function-runtime": "dotnet8",
- "function-memory-size": 512,
- "function-timeout": 30,
- "function-handler": "ToUpper"
-}
diff --git a/Tools/LambdaTestTool-v2/testapps/LambdaTestFunctionV1/Function.cs b/Tools/LambdaTestTool-v2/testapps/LambdaTestFunctionV1/Function.cs
deleted file mode 100644
index 380a2e70c..000000000
--- a/Tools/LambdaTestTool-v2/testapps/LambdaTestFunctionV1/Function.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-using Amazon.Lambda.APIGatewayEvents;
-using Amazon.Lambda.Core;
-using Amazon.Lambda.RuntimeSupport;
-using Amazon.Lambda.Serialization.SystemTextJson;
-
-var ToUpper = (APIGatewayProxyRequest request, ILambdaContext context) =>
-{
- return new APIGatewayProxyResponse()
- {
- StatusCode = 200,
- Body = request.Body.ToUpper(),
- IsBase64Encoded = false,
- };
-};
-
-await LambdaBootstrapBuilder.Create(ToUpper, new CamelCaseLambdaJsonSerializer())
- .Build()
- .RunAsync();
diff --git a/Tools/LambdaTestTool-v2/testapps/LambdaTestFunctionV1/LambdaTestFunctionV1.csproj b/Tools/LambdaTestTool-v2/testapps/LambdaTestFunctionV1/LambdaTestFunctionV1.csproj
deleted file mode 100644
index 3fc64eafd..000000000
--- a/Tools/LambdaTestTool-v2/testapps/LambdaTestFunctionV1/LambdaTestFunctionV1.csproj
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
- Exe
- net8.0
- enable
- enable
- true
- Lambda
-
- true
-
- true
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Tools/LambdaTestTool-v2/testapps/LambdaTestFunctionV1/aws-lambda-tools-defaults.json b/Tools/LambdaTestTool-v2/testapps/LambdaTestFunctionV1/aws-lambda-tools-defaults.json
deleted file mode 100644
index d7c2eb348..000000000
--- a/Tools/LambdaTestTool-v2/testapps/LambdaTestFunctionV1/aws-lambda-tools-defaults.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "Information": [
- "This file provides default values for the deployment wizard inside Visual Studio and the AWS Lambda commands added to the .NET Core CLI.",
- "To learn more about the Lambda commands with the .NET Core CLI execute the following command at the command line in the project root directory.",
- "dotnet lambda help",
- "All the command line options for the Lambda command can be specified in this file."
- ],
- "profile": "",
- "region": "",
- "configuration": "Release",
- "function-runtime": "dotnet8",
- "function-memory-size": 512,
- "function-timeout": 30,
- "function-handler": "LambdaTestFunctionV1"
-}
\ No newline at end of file
diff --git a/Tools/LambdaTestTool-v2/testapps/LambdaTestFunctionV2/Function.cs b/Tools/LambdaTestTool-v2/testapps/LambdaTestFunctionV2/Function.cs
deleted file mode 100644
index 835fd0e8a..000000000
--- a/Tools/LambdaTestTool-v2/testapps/LambdaTestFunctionV2/Function.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-using Amazon.Lambda.APIGatewayEvents;
-using Amazon.Lambda.Core;
-using Amazon.Lambda.RuntimeSupport;
-using Amazon.Lambda.Serialization.SystemTextJson;
-
-var ToUpper = (APIGatewayHttpApiV2ProxyRequest request, ILambdaContext context) =>
-{
- return new APIGatewayHttpApiV2ProxyResponse
- {
- StatusCode = 200,
- Body = request.Body.ToUpper()
- };
-};
-
-await LambdaBootstrapBuilder.Create(ToUpper, new CamelCaseLambdaJsonSerializer())
- .Build()
- .RunAsync();
diff --git a/Tools/LambdaTestTool-v2/testapps/LambdaTestFunctionV2/LambdaTestFunctionV2.csproj b/Tools/LambdaTestTool-v2/testapps/LambdaTestFunctionV2/LambdaTestFunctionV2.csproj
deleted file mode 100644
index b35be1ec5..000000000
--- a/Tools/LambdaTestTool-v2/testapps/LambdaTestFunctionV2/LambdaTestFunctionV2.csproj
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
- net8.0
- enable
- enable
- true
- Lambda
-
- true
-
- true
- Exe
- LambdaTestFunction
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Tools/LambdaTestTool-v2/testapps/LambdaTestFunctionV2/aws-lambda-tools-defaults.json b/Tools/LambdaTestTool-v2/testapps/LambdaTestFunctionV2/aws-lambda-tools-defaults.json
deleted file mode 100644
index 55632b432..000000000
--- a/Tools/LambdaTestTool-v2/testapps/LambdaTestFunctionV2/aws-lambda-tools-defaults.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "Information": [
- "This file provides default values for the deployment wizard inside Visual Studio and the AWS Lambda commands added to the .NET Core CLI.",
- "To learn more about the Lambda commands with the .NET Core CLI execute the following command at the command line in the project root directory.",
- "dotnet lambda help",
- "All the command line options for the Lambda command can be specified in this file."
- ],
- "profile": "default",
- "region": "us-west-2",
- "configuration": "Release",
- "function-runtime": "dotnet8",
- "function-memory-size": 512,
- "function-timeout": 30,
- "function-handler": "ToUpper"
-}
diff --git a/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.IntegrationTests/Amazon.Lambda.TestTool.IntegrationTests.csproj b/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.IntegrationTests/Amazon.Lambda.TestTool.IntegrationTests.csproj
index bd9f4df17..00f962109 100644
--- a/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.IntegrationTests/Amazon.Lambda.TestTool.IntegrationTests.csproj
+++ b/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.IntegrationTests/Amazon.Lambda.TestTool.IntegrationTests.csproj
@@ -10,6 +10,9 @@
+
+
+
diff --git a/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.IntegrationTests/ApiGatewayEmulatorProcessTests.cs b/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.IntegrationTests/ApiGatewayEmulatorProcessTests.cs
index a31dde0fb..275d28f6a 100644
--- a/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.IntegrationTests/ApiGatewayEmulatorProcessTests.cs
+++ b/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.IntegrationTests/ApiGatewayEmulatorProcessTests.cs
@@ -1,11 +1,13 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
-using System.Collections.Concurrent;
-using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using System.Text;
+using Amazon.Lambda.APIGatewayEvents;
+using Amazon.Lambda.Core;
+using Amazon.Lambda.RuntimeSupport;
+using Amazon.Lambda.Serialization.SystemTextJson;
using Amazon.Lambda.TestTool.Commands;
using Amazon.Lambda.TestTool.Commands.Settings;
using Amazon.Lambda.TestTool.Models;
@@ -15,52 +17,46 @@
using Spectre.Console.Cli;
using Xunit;
using Xunit.Abstractions;
+using Amazon.Lambda.TestTool.Tests.Common.Retries;
namespace Amazon.Lambda.TestTool.IntegrationTests;
-public class ApiGatewayEmulatorProcessTests : IAsyncDisposable
+public class ApiGatewayEmulatorProcessTests(ITestOutputHelper testOutputHelper)
{
- private readonly Mock _mockEnvironmentManager = new Mock();
- private readonly Mock _mockInteractiveService = new Mock();
- private readonly Mock _mockRemainingArgs = new Mock();
- private readonly ITestOutputHelper _testOutputHelper;
- private readonly ConcurrentQueue _logMessages = new ConcurrentQueue();
- private readonly SemaphoreSlim _logSemaphore = new SemaphoreSlim(1, 1);
- private Process? _lambdaProcess;
-
- public ApiGatewayEmulatorProcessTests(ITestOutputHelper testOutputHelper)
- {
- _testOutputHelper = testOutputHelper;
- }
+ private readonly Mock _mockEnvironmentManager = new();
+ private readonly Mock _mockInteractiveService = new();
+ private readonly Mock _mockRemainingArgs = new();
+ private CancellationTokenSource _cancellationTokenSource = new();
-#if DEBUG
- [Fact]
-#else
- [Fact(Skip = "Skipping this test as it is not working properly.")]
-#endif
+ [RetryFact]
public async Task TestLambdaToUpperV2()
{
var (lambdaPort, apiGatewayPort) = await GetFreePorts();
-
- var testProjectDir = Path.GetFullPath("../../../../../testapps");
- var config = new TestConfig
- {
- TestToolPath = Path.GetFullPath(Path.Combine(testProjectDir, "../src/Amazon.Lambda.TestTool")),
- LambdaPath = Path.GetFullPath(Path.Combine(testProjectDir, "LambdaTestFunctionV2")),
- FunctionName = "LambdaTestFunctionV2",
- RouteName = "testfunction",
- HttpMethod = "Post"
- };
-
- var cancellationTokenSource = new CancellationTokenSource();
-
+ _cancellationTokenSource = new CancellationTokenSource();
+ _cancellationTokenSource.CancelAfter(TimeSpan.FromSeconds(120));
+ var consoleError = Console.Error;
try
{
- StartTestToolProcess(ApiGatewayEmulatorMode.HttpV2, config, lambdaPort, apiGatewayPort, cancellationTokenSource);
+ Console.SetError(TextWriter.Null);
+ await StartTestToolProcessAsync(ApiGatewayEmulatorMode.HttpV2, "testfunction", lambdaPort, apiGatewayPort, _cancellationTokenSource);
await WaitForGatewayHealthCheck(apiGatewayPort);
- await StartLambdaProcess(config, lambdaPort);
+ var handler = (APIGatewayHttpApiV2ProxyRequest request, ILambdaContext context) =>
+ {
+ var env = Environment.GetEnvironmentVariable("AWS_LAMBDA_RUNTIME_API");
+ testOutputHelper.WriteLine($"TestLambdaToUpperV2: {env}");
+ return new APIGatewayHttpApiV2ProxyResponse
+ {
+ StatusCode = 200,
+ Body = request.Body.ToUpper()
+ };
+ };
+
+ Environment.SetEnvironmentVariable("AWS_LAMBDA_RUNTIME_API", $"localhost:{lambdaPort}/testfunction");
+ _ = LambdaBootstrapBuilder.Create(handler, new DefaultLambdaJsonSerializer())
+ .Build()
+ .RunAsync(_cancellationTokenSource.Token);
- var response = await TestEndpoint(config, apiGatewayPort);
+ var response = await TestEndpoint("testfunction", apiGatewayPort);
var responseContent = await response.Content.ReadAsStringAsync();
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
@@ -68,38 +64,41 @@ public async Task TestLambdaToUpperV2()
}
finally
{
- await cancellationTokenSource.CancelAsync();
+ await _cancellationTokenSource.CancelAsync();
+ Console.SetError(consoleError);
}
}
-#if DEBUG
- [Fact]
-#else
- [Fact(Skip = "Skipping this test as it is not working properly.")]
-#endif
+ [RetryFact]
public async Task TestLambdaToUpperRest()
{
var (lambdaPort, apiGatewayPort) = await GetFreePorts();
-
- var testProjectDir = Path.GetFullPath("../../../../../testapps");
- var config = new TestConfig
- {
- TestToolPath = Path.GetFullPath(Path.Combine(testProjectDir, "../src/Amazon.Lambda.TestTool")),
- LambdaPath = Path.GetFullPath(Path.Combine(testProjectDir, "LambdaTestFunctionV1")),
- FunctionName = "LambdaTestFunctionV1",
- RouteName = "testfunction",
- HttpMethod = "Post"
- };
-
- var cancellationTokenSource = new CancellationTokenSource();
-
+ _cancellationTokenSource = new CancellationTokenSource();
+ _cancellationTokenSource.CancelAfter(TimeSpan.FromSeconds(120));
+ var consoleError = Console.Error;
try
{
- StartTestToolProcess(ApiGatewayEmulatorMode.Rest, config, lambdaPort, apiGatewayPort, cancellationTokenSource);
+ Console.SetError(TextWriter.Null);
+ await StartTestToolProcessAsync(ApiGatewayEmulatorMode.Rest, "testfunction", lambdaPort, apiGatewayPort, _cancellationTokenSource);
await WaitForGatewayHealthCheck(apiGatewayPort);
- await StartLambdaProcess(config, lambdaPort);
-
- var response = await TestEndpoint(config, apiGatewayPort);
+ var handler = (APIGatewayProxyRequest request, ILambdaContext context) =>
+ {
+ var env = Environment.GetEnvironmentVariable("AWS_LAMBDA_RUNTIME_API");
+ testOutputHelper.WriteLine($"TestLambdaToUpperRest: {env}");
+ return new APIGatewayProxyResponse()
+ {
+ StatusCode = 200,
+ Body = request.Body.ToUpper(),
+ IsBase64Encoded = false,
+ };
+ };
+
+ Environment.SetEnvironmentVariable("AWS_LAMBDA_RUNTIME_API", $"localhost:{lambdaPort}/testfunction");
+ _ = LambdaBootstrapBuilder.Create(handler, new DefaultLambdaJsonSerializer())
+ .Build()
+ .RunAsync(_cancellationTokenSource.Token);
+
+ var response = await TestEndpoint("testfunction", apiGatewayPort);
var responseContent = await response.Content.ReadAsStringAsync();
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
@@ -107,39 +106,41 @@ public async Task TestLambdaToUpperRest()
}
finally
{
- await cancellationTokenSource.CancelAsync();
+ await _cancellationTokenSource.CancelAsync();
+ Console.SetError(consoleError);
}
}
-#if DEBUG
- [Fact]
-#else
- [Fact(Skip = "Skipping this test as it is not working properly.")]
-#endif
+ [RetryFact]
public async Task TestLambdaToUpperV1()
{
var (lambdaPort, apiGatewayPort) = await GetFreePorts();
-
-
- var testProjectDir = Path.GetFullPath("../../../../../testapps");
- var config = new TestConfig
- {
- TestToolPath = Path.GetFullPath(Path.Combine(testProjectDir, "../src/Amazon.Lambda.TestTool")),
- LambdaPath = Path.GetFullPath(Path.Combine(testProjectDir, "LambdaTestFunctionV1")),
- FunctionName = "LambdaTestFunctionV1",
- RouteName = "testfunction",
- HttpMethod = "Post"
- };
-
- var cancellationTokenSource = new CancellationTokenSource();
-
+ _cancellationTokenSource = new CancellationTokenSource();
+ _cancellationTokenSource.CancelAfter(TimeSpan.FromSeconds(120));
+ var consoleError = Console.Error;
try
{
- StartTestToolProcess(ApiGatewayEmulatorMode.HttpV1, config, lambdaPort, apiGatewayPort, cancellationTokenSource);
+ Console.SetError(TextWriter.Null);
+ await StartTestToolProcessAsync(ApiGatewayEmulatorMode.HttpV1, "testfunction", lambdaPort, apiGatewayPort, _cancellationTokenSource);
await WaitForGatewayHealthCheck(apiGatewayPort);
- await StartLambdaProcess(config, lambdaPort);
-
- var response = await TestEndpoint(config, apiGatewayPort);
+ var handler = (APIGatewayProxyRequest request, ILambdaContext context) =>
+ {
+ var env = Environment.GetEnvironmentVariable("AWS_LAMBDA_RUNTIME_API");
+ testOutputHelper.WriteLine($"TestLambdaToUpperV1: {env}");
+ return new APIGatewayProxyResponse()
+ {
+ StatusCode = 200,
+ Body = request.Body.ToUpper(),
+ IsBase64Encoded = false,
+ };
+ };
+
+ Environment.SetEnvironmentVariable("AWS_LAMBDA_RUNTIME_API", $"localhost:{lambdaPort}/testfunction");
+ _ = LambdaBootstrapBuilder.Create(handler, new DefaultLambdaJsonSerializer())
+ .Build()
+ .RunAsync(_cancellationTokenSource.Token);
+
+ var response = await TestEndpoint("testfunction", apiGatewayPort);
var responseContent = await response.Content.ReadAsStringAsync();
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
@@ -147,39 +148,52 @@ public async Task TestLambdaToUpperV1()
}
finally
{
- await cancellationTokenSource.CancelAsync();
+ await _cancellationTokenSource.CancelAsync();
+ Console.SetError(consoleError);
}
}
-#if DEBUG
- [Fact]
-#else
- [Fact(Skip = "Skipping this test as it is not working properly.")]
-#endif
+ [RetryFact]
public async Task TestLambdaBinaryResponse()
{
var (lambdaPort, apiGatewayPort) = await GetFreePorts();
-
-
- var testProjectDir = Path.GetFullPath("../../../../../testapps");
- var config = new TestConfig
- {
- TestToolPath = Path.GetFullPath(Path.Combine(testProjectDir, "../src/Amazon.Lambda.TestTool")),
- LambdaPath = Path.GetFullPath(Path.Combine(testProjectDir, "LambdaBinaryFunction")),
- FunctionName = "LambdaBinaryFunction",
- RouteName = "binaryfunction",
- HttpMethod = "Get"
- };
-
- var cancellationTokenSource = new CancellationTokenSource();
-
+ _cancellationTokenSource = new CancellationTokenSource();
+ _cancellationTokenSource.CancelAfter(TimeSpan.FromSeconds(120));
+ var consoleError = Console.Error;
try
{
- StartTestToolProcess(ApiGatewayEmulatorMode.HttpV2, config, lambdaPort, apiGatewayPort, cancellationTokenSource);
+ Console.SetError(TextWriter.Null);
+ await StartTestToolProcessAsync(ApiGatewayEmulatorMode.HttpV2, "binaryfunction", lambdaPort, apiGatewayPort, _cancellationTokenSource);
await WaitForGatewayHealthCheck(apiGatewayPort);
- await StartLambdaProcess(config, lambdaPort);
+ var handler = (APIGatewayHttpApiV2ProxyRequest request, ILambdaContext context) =>
+ {
+ var env = Environment.GetEnvironmentVariable("AWS_LAMBDA_RUNTIME_API");
+ testOutputHelper.WriteLine($"TestLambdaBinaryResponse: {env}");
+ // Create a simple binary pattern (for example, counting bytes from 0 to 255)
+ byte[] binaryData = new byte[256];
+ for (int i = 0; i < 256; i++)
+ {
+ binaryData[i] = (byte)i;
+ }
- var response = await TestEndpoint(config, apiGatewayPort);
+ return new APIGatewayHttpApiV2ProxyResponse
+ {
+ StatusCode = 200,
+ Body = Convert.ToBase64String(binaryData),
+ IsBase64Encoded = true,
+ Headers = new Dictionary
+ {
+ { "Content-Type", "application/octet-stream" }
+ }
+ };
+ };
+
+ Environment.SetEnvironmentVariable("AWS_LAMBDA_RUNTIME_API", $"localhost:{lambdaPort}/binaryfunction");
+ _ = LambdaBootstrapBuilder.Create(handler, new DefaultLambdaJsonSerializer())
+ .Build()
+ .RunAsync(_cancellationTokenSource.Token);
+
+ var response = await TestEndpoint("binaryfunction", apiGatewayPort, httpMethod: "POST");
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.Equal("application/octet-stream", response.Content.Headers.ContentType?.MediaType);
@@ -193,38 +207,36 @@ public async Task TestLambdaBinaryResponse()
}
finally
{
- await cancellationTokenSource.CancelAsync();
+ await _cancellationTokenSource.CancelAsync();
+ Console.SetError(consoleError);
}
}
-#if DEBUG
- [Fact]
-#else
- [Fact(Skip = "Skipping this test as it is not working properly.")]
-#endif
+ [RetryFact]
public async Task TestLambdaReturnString()
{
var (lambdaPort, apiGatewayPort) = await GetFreePorts();
-
- var testProjectDir = Path.GetFullPath("../../../../../testapps");
- var config = new TestConfig
- {
- TestToolPath = Path.GetFullPath(Path.Combine(testProjectDir, "../src/Amazon.Lambda.TestTool")),
- LambdaPath = Path.GetFullPath(Path.Combine(testProjectDir, "LambdaReturnStringFunction")),
- FunctionName = "LambdaReturnStringFunction",
- RouteName = "stringfunction",
- HttpMethod = "Post"
- };
-
- var cancellationTokenSource = new CancellationTokenSource();
-
+ _cancellationTokenSource = new CancellationTokenSource();
+ _cancellationTokenSource.CancelAfter(TimeSpan.FromSeconds(120));
+ var consoleError = Console.Error;
try
{
- StartTestToolProcess(ApiGatewayEmulatorMode.HttpV2, config, lambdaPort, apiGatewayPort, cancellationTokenSource);
+ Console.SetError(TextWriter.Null);
+ await StartTestToolProcessAsync(ApiGatewayEmulatorMode.HttpV2, "stringfunction", lambdaPort, apiGatewayPort, _cancellationTokenSource);
await WaitForGatewayHealthCheck(apiGatewayPort);
- await StartLambdaProcess(config, lambdaPort);
+ var handler = (APIGatewayHttpApiV2ProxyRequest request, ILambdaContext context) =>
+ {
+ var env = Environment.GetEnvironmentVariable("AWS_LAMBDA_RUNTIME_API");
+ testOutputHelper.WriteLine($"TestLambdaReturnString: {env}");
+ return request.Body.ToUpper();
+ };
- var response = await TestEndpoint(config, apiGatewayPort);
+ Environment.SetEnvironmentVariable("AWS_LAMBDA_RUNTIME_API", $"localhost:{lambdaPort}/stringfunction");
+ _ = LambdaBootstrapBuilder.Create(handler, new DefaultLambdaJsonSerializer())
+ .Build()
+ .RunAsync(_cancellationTokenSource.Token);
+
+ var response = await TestEndpoint("stringfunction", apiGatewayPort);
var responseContent = await response.Content.ReadAsStringAsync();
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
@@ -232,38 +244,40 @@ public async Task TestLambdaReturnString()
}
finally
{
- await cancellationTokenSource.CancelAsync();
+ await _cancellationTokenSource.CancelAsync();
+ Console.SetError(consoleError);
}
}
-#if DEBUG
- [Fact]
-#else
- [Fact(Skip = "Skipping this test as it is not working properly.")]
-#endif
+ [RetryFact]
public async Task TestLambdaWithNullEndpoint()
{
- var testProjectDir = Path.GetFullPath("../../../../../testapps");
- var config = new TestConfig
- {
- TestToolPath = Path.GetFullPath(Path.Combine(testProjectDir, "../src/Amazon.Lambda.TestTool")),
- LambdaPath = Path.GetFullPath(Path.Combine(testProjectDir, "LambdaTestFunctionV2")),
- FunctionName = "LambdaTestFunctionV2",
- RouteName = "testfunction",
- HttpMethod = "Post"
- };
-
- var cancellationTokenSource = new CancellationTokenSource();
-
+ var (lambdaPort, apiGatewayPort) = await GetFreePorts();
+ _cancellationTokenSource = new CancellationTokenSource();
+ _cancellationTokenSource.CancelAfter(TimeSpan.FromSeconds(120));
+ var consoleError = Console.Error;
try
{
- var (lambdaPort, apiGatewayPort) = await GetFreePorts();
-
- StartTestToolProcessWithNullEndpoint(ApiGatewayEmulatorMode.HttpV2, lambdaPort, apiGatewayPort, config, cancellationTokenSource);
+ Console.SetError(TextWriter.Null);
+ await StartTestToolProcessWithNullEndpoint(ApiGatewayEmulatorMode.HttpV2, "testfunction", lambdaPort, apiGatewayPort, _cancellationTokenSource);
await WaitForGatewayHealthCheck(apiGatewayPort);
- await StartLambdaProcess(config, lambdaPort);
+ var handler = (APIGatewayHttpApiV2ProxyRequest request, ILambdaContext context) =>
+ {
+ var env = Environment.GetEnvironmentVariable("AWS_LAMBDA_RUNTIME_API");
+ testOutputHelper.WriteLine($"TestLambdaWithNullEndpoint: {env}");
+ return new APIGatewayHttpApiV2ProxyResponse
+ {
+ StatusCode = 200,
+ Body = request.Body.ToUpper()
+ };
+ };
+
+ Environment.SetEnvironmentVariable("AWS_LAMBDA_RUNTIME_API", $"localhost:{lambdaPort}/testfunction");
+ _ = LambdaBootstrapBuilder.Create(handler, new DefaultLambdaJsonSerializer())
+ .Build()
+ .RunAsync(_cancellationTokenSource.Token);
- var response = await TestEndpoint(config, apiGatewayPort);
+ var response = await TestEndpoint("testfunction", apiGatewayPort);
var responseContent = await response.Content.ReadAsStringAsync();
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
@@ -271,70 +285,135 @@ public async Task TestLambdaWithNullEndpoint()
}
finally
{
- await cancellationTokenSource.CancelAsync();
+ await _cancellationTokenSource.CancelAsync();
+ Console.SetError(consoleError);
}
}
- private record TestConfig
- {
- public required string TestToolPath { get; init; }
- public required string LambdaPath { get; init; }
- public required string FunctionName { get; init; }
- public required string RouteName { get; init; }
- public required string HttpMethod { get; init; }
- }
-
- private async Task TestEndpoint(TestConfig config, int apiGatewayPort, HttpContent? content = null)
+ private async Task TestEndpoint(string routeName, int apiGatewayPort, string httpMethod = "POST")
{
- using var client = new HttpClient();
- return config.HttpMethod.ToUpper() switch
+ testOutputHelper.WriteLine($"Testing endpoint: http://localhost:{apiGatewayPort}/{routeName}");
+ using (var client = new HttpClient())
{
- "POST" => await client.PostAsync($"http://localhost:{apiGatewayPort}/{config.RouteName}",
- content ?? new StringContent("hello world", Encoding.UTF8, "text/plain")),
- "GET" => await client.GetAsync($"http://localhost:{apiGatewayPort}/{config.RouteName}"),
- _ => throw new ArgumentException($"Unsupported HTTP method: {config.HttpMethod}")
- };
+ client.Timeout = TimeSpan.FromSeconds(2);
+
+ var startTime = DateTime.UtcNow;
+ var timeout = TimeSpan.FromSeconds(45);
+ Exception? lastException = null;
+
+ while (DateTime.UtcNow - startTime < timeout)
+ {
+ await Task.Delay(1_000);
+
+ try
+ {
+ return httpMethod.ToUpper() switch
+ {
+ "POST" => await client.PostAsync(
+ $"http://localhost:{apiGatewayPort}/{routeName}",
+ new StringContent("hello world", Encoding.UTF8, "text/plain")),
+ "GET" => await client.GetAsync($"http://localhost:{apiGatewayPort}/{routeName}"),
+ _ => throw new ArgumentException($"Unsupported HTTP method: {httpMethod}")
+ };
+ }
+ catch (Exception ex)
+ {
+ lastException = ex;
+ testOutputHelper.WriteLine($"Request attempt failed - Message: {ex.Message}");
+ testOutputHelper.WriteLine($"Request attempt failed - Stack Trace: {ex.StackTrace}");
+ await Task.Delay(500);
+ }
+ }
+
+ throw new TimeoutException($"Failed to complete request within timeout period: z{lastException?.Message}", lastException);
+ }
}
- private void StartTestToolProcessWithNullEndpoint(ApiGatewayEmulatorMode apiGatewayMode, int lambdaPort, int apiGatewayPort, TestConfig config, CancellationTokenSource cancellationTokenSource)
+ private async Task StartTestToolProcessAsync(ApiGatewayEmulatorMode apiGatewayMode, string routeName, int lambdaPort, int apiGatewayPort, CancellationTokenSource cancellationTokenSource, string httpMethod = "POST")
{
Environment.SetEnvironmentVariable("ASPNETCORE_ENVIRONMENT", "Development");
Environment.SetEnvironmentVariable("APIGATEWAY_EMULATOR_ROUTE_CONFIG", $@"{{
- ""LambdaResourceName"": ""{config.RouteName}"",
- ""HttpMethod"": ""{config.HttpMethod}"",
- ""Path"": ""/{config.RouteName}""
+ ""LambdaResourceName"": ""{routeName}"",
+ ""Endpoint"": ""http://localhost:{lambdaPort}"",
+ ""HttpMethod"": ""{httpMethod}"",
+ ""Path"": ""/{routeName}""
}}");
- cancellationTokenSource.CancelAfter(TimeSpan.FromSeconds(60));
- var settings = new RunCommandSettings { NoLaunchWindow = true, ApiGatewayEmulatorMode = apiGatewayMode, ApiGatewayEmulatorPort = apiGatewayPort, LambdaEmulatorPort = lambdaPort};
+ var settings = new RunCommandSettings
+ {
+ LambdaEmulatorPort = lambdaPort,
+ NoLaunchWindow = true,
+ ApiGatewayEmulatorMode = apiGatewayMode,
+ ApiGatewayEmulatorPort = apiGatewayPort
+ };
var command = new RunCommand(_mockInteractiveService.Object, _mockEnvironmentManager.Object);
var context = new CommandContext(new List(), _mockRemainingArgs.Object, "run", null);
-
_ = command.ExecuteAsync(context, settings, cancellationTokenSource);
+
+ // Give the process time to start
+ await Task.Delay(2000, cancellationTokenSource.Token);
}
- private void StartTestToolProcess(ApiGatewayEmulatorMode apiGatewayMode, TestConfig config, int lambdaPort, int apiGatewayPort, CancellationTokenSource cancellationTokenSource)
+ private async Task StartTestToolProcessWithNullEndpoint(ApiGatewayEmulatorMode apiGatewayMode, string routeName, int lambdaPort, int apiGatewayPort, CancellationTokenSource cancellationTokenSource)
{
Environment.SetEnvironmentVariable("ASPNETCORE_ENVIRONMENT", "Development");
Environment.SetEnvironmentVariable("APIGATEWAY_EMULATOR_ROUTE_CONFIG", $@"{{
- ""LambdaResourceName"": ""{config.RouteName}"",
- ""Endpoint"": ""http://localhost:{lambdaPort}"",
- ""HttpMethod"": ""{config.HttpMethod}"",
- ""Path"": ""/{config.RouteName}""
+ ""LambdaResourceName"": ""{routeName}"",
+ ""HttpMethod"": ""POST"",
+ ""Path"": ""/{routeName}""
}}");
- cancellationTokenSource.CancelAfter(TimeSpan.FromSeconds(60));
- var settings = new RunCommandSettings { LambdaEmulatorPort = lambdaPort, NoLaunchWindow = true, ApiGatewayEmulatorMode = apiGatewayMode,ApiGatewayEmulatorPort = apiGatewayPort};
+
+ var settings = new RunCommandSettings
+ {
+ LambdaEmulatorPort = lambdaPort,
+ NoLaunchWindow = true,
+ ApiGatewayEmulatorMode = apiGatewayMode,
+ ApiGatewayEmulatorPort = apiGatewayPort
+ };
+
var command = new RunCommand(_mockInteractiveService.Object, _mockEnvironmentManager.Object);
var context = new CommandContext(new List(), _mockRemainingArgs.Object, "run", null);
-
- // Act
_ = command.ExecuteAsync(context, settings, cancellationTokenSource);
+
+ // Give the process time to start
+ await Task.Delay(2000, cancellationTokenSource.Token);
+ }
+
+ private async Task WaitForGatewayHealthCheck(int apiGatewayPort)
+ {
+ using (var client = new HttpClient())
+ {
+ client.Timeout = TimeSpan.FromSeconds(5);
+ var startTime = DateTime.UtcNow;
+ var timeout = TimeSpan.FromSeconds(30);
+ var healthUrl = $"http://localhost:{apiGatewayPort}/__lambda_test_tool_apigateway_health__";
+
+ while (DateTime.UtcNow - startTime < timeout)
+ {
+ try
+ {
+ var response = await client.GetAsync(healthUrl);
+ if (response.IsSuccessStatusCode)
+ {
+ testOutputHelper.WriteLine("API Gateway health check succeeded");
+ // Add additional delay after successful health check
+ await Task.Delay(1000);
+ return;
+ }
+ }
+ catch (Exception ex)
+ {
+ testOutputHelper.WriteLine($"Health check attempt failed: {ex.Message}");
+ await Task.Delay(500);
+ }
+ }
+ throw new TimeoutException("API Gateway failed to start within timeout period");
+ }
}
private async Task<(int lambdaPort, int apiGatewayPort)> GetFreePorts()
{
- // Get two different ports
var lambdaPort = GetFreePort();
int apiGatewayPort;
do
@@ -359,155 +438,4 @@ private int GetFreePort()
listener.Stop();
}
}
-
- private async Task StartLambdaProcess(TestConfig config, int lambdaPort)
- {
- // Build the project
- var buildResult = await RunProcess("dotnet", "publish -c Release", config.LambdaPath);
- if (buildResult.ExitCode != 0)
- {
- throw new Exception($"Build failed: {buildResult.Output}\n{buildResult.Error}");
- }
-
- var publishFolder = Path.Combine(config.LambdaPath, "bin", "Release", "net8.0");
- var archFolders = Directory.GetDirectories(publishFolder, "*");
- var archFolder = Assert.Single(archFolders);
-
- var startInfo = new ProcessStartInfo
- {
- FileName = "dotnet",
- Arguments = Path.Combine(archFolder, "publish", $"{config.FunctionName}.dll"),
- WorkingDirectory = config.LambdaPath,
- UseShellExecute = false,
- RedirectStandardOutput = true,
- RedirectStandardError = true,
- CreateNoWindow = true
- };
-
- startInfo.EnvironmentVariables["AWS_LAMBDA_RUNTIME_API"] = $"localhost:{lambdaPort}/{config.RouteName}";
- startInfo.EnvironmentVariables["LAMBDA_TASK_ROOT"] = config.LambdaPath;
- startInfo.EnvironmentVariables["AWS_LAMBDA_FUNCTION_MEMORY_SIZE"] = "256";
- startInfo.EnvironmentVariables["AWS_LAMBDA_FUNCTION_TIMEOUT"] = "30";
- startInfo.EnvironmentVariables["AWS_LAMBDA_FUNCTION_NAME"] = config.FunctionName;
- startInfo.EnvironmentVariables["AWS_LAMBDA_FUNCTION_VERSION"] = "$LATEST";
-
- _lambdaProcess = Process.Start(startInfo) ?? throw new Exception("Failed to start Lambda process");
- ConfigureProcessLogging(_lambdaProcess, "Lambda");
- }
-
- private void ConfigureProcessLogging(Process process, string prefix)
- {
- process.OutputDataReceived += async (_, e) =>
- {
- if (e.Data != null) await LogMessage($"{prefix}: {e.Data}");
- };
- process.ErrorDataReceived += async (_, e) =>
- {
- if (e.Data != null) await LogMessage($"{prefix} Error: {e.Data}");
- };
- process.BeginOutputReadLine();
- process.BeginErrorReadLine();
- }
-
- private async Task<(int ExitCode, string Output, string Error)> RunProcess(string fileName, string arguments, string? workingDirectory = null)
- {
- using var process = new Process
- {
- StartInfo = new ProcessStartInfo
- {
- FileName = fileName,
- Arguments = arguments,
- WorkingDirectory = workingDirectory ?? Directory.GetCurrentDirectory(),
- UseShellExecute = false,
- RedirectStandardOutput = true,
- RedirectStandardError = true,
- CreateNoWindow = true
- }
- };
-
- var output = new StringBuilder();
- var error = new StringBuilder();
- process.OutputDataReceived += (_, e) => { if (e.Data != null) output.AppendLine(e.Data); };
- process.ErrorDataReceived += (_, e) => { if (e.Data != null) error.AppendLine(e.Data); };
-
- process.Start();
- process.BeginOutputReadLine();
- process.BeginErrorReadLine();
- await process.WaitForExitAsync();
-
- return (process.ExitCode, output.ToString(), error.ToString());
- }
-
- private async Task WaitForGatewayHealthCheck(int apiGatewayPort)
- {
- using var client = new HttpClient();
- var startTime = DateTime.UtcNow;
- var timeout = TimeSpan.FromSeconds(10);
- var healthUrl = $"http://localhost:{apiGatewayPort}/__lambda_test_tool_apigateway_health__";
-
- while (DateTime.UtcNow - startTime < timeout)
- {
- try
- {
- var response = await client.GetAsync(healthUrl);
- if (response.IsSuccessStatusCode)
- {
- LogMessage("API Gateway health check succeeded");
- return;
- }
- }
- catch
- {
- await Task.Delay(100);
- }
- }
- throw new TimeoutException("API Gateway failed to start within timeout period");
- }
-
- private async Task LogMessage(string message)
- {
- await _logSemaphore.WaitAsync();
- try
- {
- Console.WriteLine(message); // Still write to console for debugging
- _logMessages.Enqueue(message);
- }
- finally
- {
- _logSemaphore.Release();
- }
- }
-
- private async Task CleanupProcesses()
- {
- var processes = new[] { _lambdaProcess };
- foreach (var process in processes.Where(p => p != null && !p.HasExited))
- {
- try
- {
- process!.Kill(entireProcessTree: true);
- await Task.Delay(100);
- }
- catch (Exception ex)
- {
- LogMessage($"Error killing process: {ex.Message}");
- }
- finally
- {
- process!.Dispose();
- }
- }
- }
-
- public async ValueTask DisposeAsync()
- {
- // Write all queued messages before disposing
- while (_logMessages.TryDequeue(out var message))
- {
- _testOutputHelper.WriteLine(message);
- }
-
- await CleanupProcesses();
- _logSemaphore.Dispose();
- }
}
diff --git a/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.IntegrationTests/Properties/AssemblyInfo.cs b/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.IntegrationTests/Properties/AssemblyInfo.cs
new file mode 100644
index 000000000..3195e5a2a
--- /dev/null
+++ b/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.IntegrationTests/Properties/AssemblyInfo.cs
@@ -0,0 +1,6 @@
+// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+using Xunit;
+
+[assembly: CollectionBehavior(DisableTestParallelization = true)]
diff --git a/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.Tests.Common/Amazon.Lambda.TestTool.Tests.Common.csproj b/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.Tests.Common/Amazon.Lambda.TestTool.Tests.Common.csproj
index c270fa02b..21b4d7eb1 100644
--- a/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.Tests.Common/Amazon.Lambda.TestTool.Tests.Common.csproj
+++ b/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.Tests.Common/Amazon.Lambda.TestTool.Tests.Common.csproj
@@ -8,6 +8,7 @@
+
diff --git a/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.UnitTests/Helpers/TestHelpers.cs b/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.Tests.Common/Helpers/TestHelpers.cs
similarity index 71%
rename from Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.UnitTests/Helpers/TestHelpers.cs
rename to Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.Tests.Common/Helpers/TestHelpers.cs
index 1ab304195..79c618d48 100644
--- a/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.UnitTests/Helpers/TestHelpers.cs
+++ b/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.Tests.Common/Helpers/TestHelpers.cs
@@ -1,13 +1,11 @@
-// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
-using System.Collections.Concurrent;
+namespace Amazon.Lambda.TestTool.Tests.Common.Helpers;
-namespace Amazon.Lambda.TestTool.UnitTests.Helpers;
-
-internal static class TestHelpers
+public static class TestHelpers
{
- internal static async Task WaitForApiToStartAsync(string url, int maxRetries = 5, int delayMilliseconds = 1000)
+ public static async Task WaitForApiToStartAsync(string url, int maxRetries = 5, int delayMilliseconds = 1000)
{
using (var client = new HttpClient())
{
@@ -33,7 +31,7 @@ internal static async Task WaitForApiToStartAsync(string url, int maxRetri
}
}
- internal static async Task SendRequest(string url)
+ public static async Task SendRequest(string url)
{
using (var client = new HttpClient())
{
diff --git a/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.Tests.Common/Retries/RetryFactAttribute.cs b/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.Tests.Common/Retries/RetryFactAttribute.cs
new file mode 100644
index 000000000..7d5b74bd2
--- /dev/null
+++ b/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.Tests.Common/Retries/RetryFactAttribute.cs
@@ -0,0 +1,18 @@
+// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+using Xunit;
+using Xunit.Sdk;
+
+namespace Amazon.Lambda.TestTool.Tests.Common.Retries;
+
+[XunitTestCaseDiscoverer("Amazon.Lambda.TestTool.Tests.Common.Retries.RetryFactDiscoverer", "Amazon.Lambda.TestTool.Tests.Common")]
+public class RetryFactAttribute : FactAttribute
+{
+ ///
+ /// Number of additional attempts (not counting the initial try)
+ ///
+ public int MaxRetries { get; set; } = 3;
+
+ public RetryFactAttribute() { }
+}
diff --git a/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.Tests.Common/Retries/RetryFactDiscoverer.cs b/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.Tests.Common/Retries/RetryFactDiscoverer.cs
new file mode 100644
index 000000000..2723dab0e
--- /dev/null
+++ b/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.Tests.Common/Retries/RetryFactDiscoverer.cs
@@ -0,0 +1,31 @@
+// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+using Xunit.Abstractions;
+using Xunit.Sdk;
+
+namespace Amazon.Lambda.TestTool.Tests.Common.Retries;
+
+public class RetryFactDiscoverer : IXunitTestCaseDiscoverer
+{
+ readonly IMessageSink diagnosticMessageSink;
+
+ public RetryFactDiscoverer(IMessageSink diagnosticMessageSink)
+ {
+ this.diagnosticMessageSink = diagnosticMessageSink;
+ }
+
+ public IEnumerable Discover(ITestFrameworkDiscoveryOptions discoveryOptions,
+ ITestMethod testMethod,
+ IAttributeInfo factAttribute)
+ {
+ // Read the MaxRetries property from the attribute.
+ int maxRetries = factAttribute.GetNamedArgument("MaxRetries");
+
+ yield return new RetryTestCase(diagnosticMessageSink,
+ discoveryOptions.MethodDisplayOrDefault(),
+ discoveryOptions.MethodDisplayOptionsOrDefault(),
+ testMethod,
+ maxRetries);
+ }
+}
diff --git a/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.Tests.Common/Retries/RetryTestCase.cs b/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.Tests.Common/Retries/RetryTestCase.cs
new file mode 100644
index 000000000..0794d19f1
--- /dev/null
+++ b/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.Tests.Common/Retries/RetryTestCase.cs
@@ -0,0 +1,76 @@
+// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+using Xunit.Abstractions;
+using Xunit.Sdk;
+
+namespace Amazon.Lambda.TestTool.Tests.Common.Retries;
+
+public class RetryTestCase : XunitTestCase
+{
+ int _maxRetries;
+
+ public RetryTestCase(IMessageSink diagnosticMessageSink,
+ TestMethodDisplay defaultMethodDisplay,
+ TestMethodDisplayOptions defaultMethodDisplayOptions,
+ ITestMethod testMethod,
+ int maxRetries)
+ : base(diagnosticMessageSink, defaultMethodDisplay, defaultMethodDisplayOptions, testMethod)
+ {
+ _maxRetries = maxRetries;
+ }
+
+ // Parameterless constructor needed for de-serialization
+ [Obsolete("Called by the de-serializer", true)]
+ public RetryTestCase() { }
+
+ public override async Task RunAsync(IMessageSink diagnosticMessageSink,
+ IMessageBus messageBus,
+ object[] constructorArguments,
+ ExceptionAggregator aggregator,
+ CancellationTokenSource cancellationTokenSource)
+ {
+ RunSummary? finalSummary = null;
+
+ for (int attempt = 0; attempt <= _maxRetries; attempt++)
+ {
+ // Create a fresh aggregator for each attempt
+ var attemptAggregator = new ExceptionAggregator();
+
+ // Run the test (each attempt returns its own summary)
+ var currentSummary = await base.RunAsync(diagnosticMessageSink,
+ messageBus,
+ constructorArguments,
+ attemptAggregator,
+ cancellationTokenSource);
+
+ if (currentSummary.Failed == 0)
+ {
+ // If the test passed, log a message and return the current summary
+ if (attempt > 0)
+ {
+ diagnosticMessageSink.OnMessage(new DiagnosticMessage($"Test passed on attempt {attempt + 1}"));
+ }
+ return currentSummary;
+ }
+
+ diagnosticMessageSink.OnMessage(new DiagnosticMessage($"Test failed on attempt {attempt + 1}, retrying..."));
+ finalSummary = currentSummary;
+ }
+
+ // If none of the attempts passed, return the summary of the final attempt.
+ return finalSummary;
+ }
+
+ public override void Serialize(IXunitSerializationInfo data)
+ {
+ base.Serialize(data);
+ data.AddValue("MaxRetries", _maxRetries);
+ }
+
+ public override void Deserialize(IXunitSerializationInfo data)
+ {
+ base.Deserialize(data);
+ _maxRetries = data.GetValue("MaxRetries");
+ }
+}
diff --git a/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.UnitTests/Commands/RunCommandTests.cs b/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.UnitTests/Commands/RunCommandTests.cs
index f716a6473..5dcdf7934 100644
--- a/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.UnitTests/Commands/RunCommandTests.cs
+++ b/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.UnitTests/Commands/RunCommandTests.cs
@@ -7,9 +7,9 @@
using Amazon.Lambda.TestTool.Services;
using Spectre.Console.Cli;
using Moq;
-using Amazon.Lambda.TestTool.UnitTests.Helpers;
using Xunit;
using Amazon.Lambda.TestTool.Services.IO;
+using Amazon.Lambda.TestTool.Tests.Common.Helpers;
using Amazon.Lambda.TestTool.Utilities;
using System.Text.Json.Nodes;
@@ -21,11 +21,7 @@ public class RunCommandTests
private readonly Mock _mockInteractiveService = new Mock();
private readonly Mock _mockRemainingArgs = new Mock();
-#if DEBUG
[Fact]
-#else
- [Fact(Skip = "Skipping this test as it is not working properly.")]
-#endif
public async Task ExecuteAsync_LambdaRuntimeApi_SuccessfulLaunch()
{
// Arrange
@@ -49,11 +45,7 @@ public async Task ExecuteAsync_LambdaRuntimeApi_SuccessfulLaunch()
Assert.True(isApiRunning);
}
-#if DEBUG
[Fact]
-#else
- [Fact(Skip = "Skipping this test as it is not working properly.")]
-#endif
public async Task ExecuteAsync_ApiGatewayEmulator_SuccessfulLaunch()
{
// Arrange
@@ -78,11 +70,7 @@ public async Task ExecuteAsync_ApiGatewayEmulator_SuccessfulLaunch()
Assert.True(isApiRunning);
}
-#if DEBUG
[Fact]
-#else
- [Fact(Skip = "Skipping this test as it is not working properly.")]
-#endif
public async Task ExecuteAsync_EnvPorts_SuccessfulLaunch()
{
var lambdaPort = TestHelpers.GetNextLambdaRuntimePort();
diff --git a/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.UnitTests/PackagingTests.cs b/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.UnitTests/PackagingTests.cs
index e5c68bd3b..7d47bf3ab 100644
--- a/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.UnitTests/PackagingTests.cs
+++ b/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.UnitTests/PackagingTests.cs
@@ -9,7 +9,6 @@ namespace Amazon.Lambda.TestTool.UnitTests;
public class PackagingTests : IDisposable
{
private readonly ITestOutputHelper _output;
- private readonly string[] _expectedFrameworks;
private readonly string _workingDirectory;
public PackagingTests(ITestOutputHelper output)
@@ -17,61 +16,20 @@ public PackagingTests(ITestOutputHelper output)
_output = output;
var solutionRoot = FindSolutionRoot();
_workingDirectory = DirectoryHelpers.GetTempTestAppDirectory(solutionRoot);
- _expectedFrameworks = GetRuntimeSupportTargetFrameworks()
- .Split([';'], StringSplitOptions.RemoveEmptyEntries)
- .Where(f => f != "netstandard2.0")
- .ToArray();
}
- private string GetRuntimeSupportTargetFrameworks()
- {
- Console.WriteLine("Getting the expected list of target frameworks...");
- var runtimeSupportPath = Path.Combine(_workingDirectory, "Libraries", "src", "Amazon.Lambda.RuntimeSupport", "Amazon.Lambda.RuntimeSupport.csproj");
-
- var process = new Process
- {
- StartInfo = new ProcessStartInfo
- {
- FileName = "dotnet",
- Arguments = $"msbuild {runtimeSupportPath} --getProperty:TargetFrameworks",
- RedirectStandardOutput = true,
- RedirectStandardError = true,
- UseShellExecute = false,
- CreateNoWindow = true,
- }
- };
-
- process.Start();
- var output = process.StandardOutput.ReadToEnd();
- var error = process.StandardError.ReadToEnd();
- process.WaitForExit(int.MaxValue);
-
- Console.WriteLine(output);
- Console.WriteLine(error);
- if (process.ExitCode != 0)
- {
- throw new Exception($"Failed to get TargetFrameworks: {error}");
- }
-
- return output.Trim();
- }
-
-#if DEBUG
[Fact]
-#else
- [Fact(Skip = "Skipping this test as it is not working properly.")]
-#endif
public void VerifyPackageContentsHasRuntimeSupport()
{
var projectPath = Path.Combine(_workingDirectory, "Tools", "LambdaTestTool-v2", "src", "Amazon.Lambda.TestTool", "Amazon.Lambda.TestTool.csproj");
-
- _output.WriteLine("\nPacking TestTool...");
+ var expectedFrameworks = new string[] { "net6.0", "net8.0", "net9.0" };
+ _output.WriteLine("Packing TestTool...");
var packProcess = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = "dotnet",
- Arguments = $"pack {projectPath} -c Release",
+ Arguments = $"pack -c Release --no-build --no-restore {projectPath}",
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
@@ -105,7 +63,7 @@ public void VerifyPackageContentsHasRuntimeSupport()
using var archive = ZipFile.OpenRead(packagePath);
// Verify each framework has its required files
- foreach (var framework in _expectedFrameworks)
+ foreach (var framework in expectedFrameworks)
{
_output.WriteLine($"\nChecking framework: {framework}");
@@ -146,14 +104,17 @@ private string FindSolutionRoot()
string? currentDirectory = Directory.GetCurrentDirectory();
while (currentDirectory != null)
{
- // Look for the aws-lambda-dotnet directory specifically
- if (Path.GetFileName(currentDirectory) == "aws-lambda-dotnet")
+ // Look for the "Tools" directory specifically and then go up one level to the root of the repository.
+ // The reason we do this is because the source directory "aws-lambda-dotnet" does not always exist in the CI.
+ // In CodeBuild, the contents of "aws-lambda-dotnet" get copied to a temp location,
+ // so the path does not contain the name "aws-lambda-dotnet".
+ if (Path.GetFileName(currentDirectory) == "Tools")
{
- return currentDirectory;
+ return Path.Combine(currentDirectory, "..");
}
currentDirectory = Directory.GetParent(currentDirectory)?.FullName;
}
- throw new Exception("Could not find the aws-lambda-dotnet root directory.");
+ throw new Exception("Could not find the 'Tools' root directory.");
}
public void Dispose()
diff --git a/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.UnitTests/Processes/ApiGatewayEmulatorProcessTests.cs b/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.UnitTests/Processes/ApiGatewayEmulatorProcessTests.cs
index e454cceef..f6d80d58b 100644
--- a/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.UnitTests/Processes/ApiGatewayEmulatorProcessTests.cs
+++ b/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.UnitTests/Processes/ApiGatewayEmulatorProcessTests.cs
@@ -5,7 +5,7 @@
using Amazon.Lambda.TestTool.Commands.Settings;
using Amazon.Lambda.TestTool.Models;
using Amazon.Lambda.TestTool.Processes;
-using Amazon.Lambda.TestTool.UnitTests.Helpers;
+using Amazon.Lambda.TestTool.Tests.Common.Helpers;
using Xunit;
namespace Amazon.Lambda.TestTool.UnitTests.Processes;
diff --git a/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.UnitTests/Properties/AssemblyInfo.cs b/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.UnitTests/Properties/AssemblyInfo.cs
index e69de29bb..3195e5a2a 100644
--- a/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.UnitTests/Properties/AssemblyInfo.cs
+++ b/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.UnitTests/Properties/AssemblyInfo.cs
@@ -0,0 +1,6 @@
+// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+using Xunit;
+
+[assembly: CollectionBehavior(DisableTestParallelization = true)]
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 25e0c656f..4194bde1f 100644
--- a/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.UnitTests/RuntimeApiTests.cs
+++ b/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.UnitTests/RuntimeApiTests.cs
@@ -9,7 +9,8 @@
using Amazon.Lambda.Core;
using Amazon.Lambda.TestTool.Processes;
using Amazon.Lambda.TestTool.Commands.Settings;
-using Amazon.Lambda.TestTool.UnitTests.Helpers;
+using Amazon.Lambda.TestTool.Tests.Common.Helpers;
+using Amazon.Lambda.TestTool.Tests.Common.Retries;
using Microsoft.Extensions.DependencyInjection;
using Xunit;
using Environment = System.Environment;
@@ -75,11 +76,7 @@ public async Task AddEventToDataStore()
}
}
-#if DEBUG
- [Fact]
-#else
- [Fact(Skip = "Skipping this test as it is not working properly.")]
-#endif
+ [RetryFact]
public async Task InvokeRequestResponse()
{
const string functionName = "FunctionFoo";
@@ -133,7 +130,6 @@ public async Task InvokeRequestResponse()
{
await cancellationTokenSource.CancelAsync();
}
-
}
private IAmazonLambda ConstructLambdaServiceClient(string url)
diff --git a/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.UnitTests/Services/LambdaRuntimeApiTests.cs b/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.UnitTests/Services/LambdaRuntimeApiTests.cs
index 26ebe7de4..3b6b8e297 100644
--- a/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.UnitTests/Services/LambdaRuntimeApiTests.cs
+++ b/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.UnitTests/Services/LambdaRuntimeApiTests.cs
@@ -151,8 +151,6 @@ public async Task PostEvent_RequestResponse_ErrorWithoutBody()
Assert.Empty(responseBody);
}
-
-
[Fact]
public async Task GetNextInvocation_Returns_Event()
{
@@ -190,75 +188,99 @@ public async Task GetNextInvocation_Returns_Event()
[Fact]
public void PostInitError_Logs_Error()
{
- // Arrange
- var functionName = "testFunction";
- var errorType = "InitializationError";
- var error = "Failed to initialize";
-
- // Act
- var result = new LambdaRuntimeApi(_app).PostInitError(functionName, errorType, error);
-
- // Assert
- Assert.NotNull(result);
- var statusResponse = Assert.IsType((result as IValueHttpResult)?.Value);
- Assert.Equal("success", statusResponse.Status);
+ var consoleError = Console.Error;
+ try
+ {
+ Console.SetError(TextWriter.Null);
+ // Arrange
+ var functionName = "testFunction";
+ var errorType = "InitializationError";
+ var error = "Failed to initialize";
+
+ // Act
+ var result = new LambdaRuntimeApi(_app).PostInitError(functionName, errorType, error);
+
+ // Assert
+ Assert.NotNull(result);
+ var statusResponse = Assert.IsType((result as IValueHttpResult)?.Value);
+ Assert.Equal("success", statusResponse.Status);
+ }
+ finally
+ {
+ Console.SetError(consoleError);
+ }
}
[Fact]
public async Task PostInvocationResponse_Reports_Success()
{
- // Arrange
- var functionName = "testFunction";
- var awsRequestId = "request123";
- var response = "{\"result\":\"success\"}";
+ var consoleError = Console.Error;
+ try
+ {
+ Console.SetError(TextWriter.Null);
+ // Arrange
+ var functionName = "testFunction";
+ var awsRequestId = "request123";
+ var response = "{\"result\":\"success\"}";
- var context = new DefaultHttpContext();
- context.Request.Body = new MemoryStream(Encoding.UTF8.GetBytes(response));
- context.Response.Body = new MemoryStream();
+ var context = new DefaultHttpContext();
+ context.Request.Body = new MemoryStream(Encoding.UTF8.GetBytes(response));
+ context.Response.Body = new MemoryStream();
- _mockRuntimeDataStore
- .Setup(x => x.ReportSuccess(awsRequestId, response));
+ _mockRuntimeDataStore
+ .Setup(x => x.ReportSuccess(awsRequestId, response));
- // Act
- var result = await new LambdaRuntimeApi(_app).PostInvocationResponse(context, functionName, awsRequestId);
+ // Act
+ var result = await new LambdaRuntimeApi(_app).PostInvocationResponse(context, functionName, awsRequestId);
- // Assert
- Assert.NotNull(result);
- var statusResponse = Assert.IsType((result as IValueHttpResult)?.Value);
- Assert.Equal("success", statusResponse.Status);
+ // Assert
+ Assert.NotNull(result);
+ var statusResponse = Assert.IsType((result as IValueHttpResult)?.Value);
+ Assert.Equal("success", statusResponse.Status);
- _mockRuntimeDataStore.Verify(x => x.ReportSuccess(awsRequestId, response), Times.Once);
+ _mockRuntimeDataStore.Verify(x => x.ReportSuccess(awsRequestId, response), Times.Once);
+ }
+ finally
+ {
+ Console.SetError(consoleError);
+ }
}
[Fact]
public async Task PostError_Reports_Error()
{
- // Arrange
- var functionName = "testFunction";
- var awsRequestId = "request123";
- var errorType = "HandlerError";
- var errorBody = "Function execution failed";
+ var consoleError = Console.Error;
+ try
+ {
+ Console.SetError(TextWriter.Null);
+ // Arrange
+ var functionName = "testFunction";
+ var awsRequestId = "request123";
+ var errorType = "HandlerError";
+ var errorBody = "Function execution failed";
- var context = new DefaultHttpContext();
- context.Request.Body = new MemoryStream(Encoding.UTF8.GetBytes(errorBody));
- context.Response.Body = new MemoryStream();
+ var context = new DefaultHttpContext();
+ context.Request.Body = new MemoryStream(Encoding.UTF8.GetBytes(errorBody));
+ context.Response.Body = new MemoryStream();
- _mockRuntimeDataStore
- .Setup(x => x.ReportError(awsRequestId, errorType, errorBody));
+ _mockRuntimeDataStore
+ .Setup(x => x.ReportError(awsRequestId, errorType, errorBody));
- // Act
- var result = await new LambdaRuntimeApi(_app).PostError(context, functionName, awsRequestId, errorType);
+ // Act
+ var result = await new LambdaRuntimeApi(_app).PostError(context, functionName, awsRequestId, errorType);
- // Assert
- Assert.NotNull(result);
- var statusResponse = Assert.IsType((result as IValueHttpResult)?.Value);
- Assert.Equal("success", statusResponse.Status);
+ // Assert
+ Assert.NotNull(result);
+ var statusResponse = Assert.IsType((result as IValueHttpResult)?.Value);
+ Assert.Equal("success", statusResponse.Status);
- _mockRuntimeDataStore.Verify(x => x.ReportError(awsRequestId, errorType, errorBody), Times.Once);
+ _mockRuntimeDataStore.Verify(x => x.ReportError(awsRequestId, errorType, errorBody), Times.Once);
+ }
+ finally
+ {
+ Console.SetError(consoleError);
+ }
}
-
-
-
}
// Helper class to prevent stream from being closed
diff --git a/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.UnitTests/Utilities/DirectoryHelpers.cs b/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.UnitTests/Utilities/DirectoryHelpers.cs
index 19d52cd10..6599cf13d 100644
--- a/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.UnitTests/Utilities/DirectoryHelpers.cs
+++ b/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.UnitTests/Utilities/DirectoryHelpers.cs
@@ -63,7 +63,7 @@ private static void CopyDirectory(DirectoryInfo dir, string destDirName)
File.SetAttributes(tempPath, FileAttributes.Normal);
}
- foreach (var subdir in dirs)
+ foreach (var subdir in dirs.Where(x => !x.Name.Equals(".git")))
{
var tempPath = Path.Combine(destDirName, subdir.Name);
var subDir = new DirectoryInfo(subdir.FullName);
diff --git a/buildtools/build.proj b/buildtools/build.proj
index bb9ac9a43..24afe9a00 100644
--- a/buildtools/build.proj
+++ b/buildtools/build.proj
@@ -193,6 +193,23 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/buildtools/ci.buildspec.yml b/buildtools/ci.buildspec.yml
index 15f532844..320930898 100644
--- a/buildtools/ci.buildspec.yml
+++ b/buildtools/ci.buildspec.yml
@@ -12,7 +12,6 @@ phases:
- curl -sSL https://dot.net/v1/dotnet-install.sh | bash /dev/stdin --channel 9.0
build:
commands:
- - dotnet test -c Release --logger "console;verbosity=detailed" ./Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.UnitTests/Amazon.Lambda.TestTool.UnitTests.csproj
- - dotnet test -c Release --logger "console;verbosity=detailed" ./Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.IntegrationTests/Amazon.Lambda.TestTool.IntegrationTests.csproj
+ - dotnet msbuild buildtools/build.proj /t:testtoolv2-tests /p:Cicd=true
- dotnet msbuild buildtools/build.proj /t:unit-tests /p:Cicd=true
- dotnet msbuild buildtools/build.proj /t:integ-tests /p:Cicd=true
\ No newline at end of file