diff --git a/.editorconfig b/.editorconfig
index 6e89449c1..c1f291525 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -202,7 +202,7 @@ dotnet_code_quality.ca2208.api_surface=public
dotnet_diagnostic.ca1822.severity=none
# License header
-file_header_template= Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\r\nSPDX-License-Identifier: Apache-2.0
+file_header_template= Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\nSPDX-License-Identifier: Apache-2.0
# ReSharper properties
resharper_braces_for_for=required
diff --git a/Tools/LambdaTestTool-v2/src/Amazon.Lambda.TestTool/Extensions/ResultExtensions.cs b/Tools/LambdaTestTool-v2/src/Amazon.Lambda.TestTool/Extensions/ResultExtensions.cs
new file mode 100644
index 000000000..ab9e416ad
--- /dev/null
+++ b/Tools/LambdaTestTool-v2/src/Amazon.Lambda.TestTool/Extensions/ResultExtensions.cs
@@ -0,0 +1,33 @@
+// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+using Amazon.Lambda.TestTool.Models;
+
+namespace Amazon.Lambda.TestTool.Extensions;
+
+///
+/// A class for common API Gateway responses.
+///
+public static class ApiGatewayResults
+{
+ ///
+ /// Returns a 'Not Found' for HTTP API Gateway mode and 'Missing Authentication Token' for Rest.
+ ///
+ /// The to update.
+ /// The API Gateway Emulator mode.
+ ///
+ public static IResult RouteNotFound(HttpContext context, ApiGatewayEmulatorMode emulatorMode)
+ {
+ if (emulatorMode == ApiGatewayEmulatorMode.Rest)
+ {
+ context.Response.StatusCode = StatusCodes.Status403Forbidden;
+ context.Response.Headers.Append("x-amzn-errortype", "MissingAuthenticationTokenException");
+ return Results.Json(new { message = "Missing Authentication Token" });
+ }
+ else
+ {
+ context.Response.StatusCode = StatusCodes.Status404NotFound;
+ return Results.Json(new { message = "Not Found" });
+ }
+ }
+}
diff --git a/Tools/LambdaTestTool-v2/src/Amazon.Lambda.TestTool/Models/Exceptions.cs b/Tools/LambdaTestTool-v2/src/Amazon.Lambda.TestTool/Models/Exceptions.cs
index 4ad1b75f2..1e2d31af1 100644
--- a/Tools/LambdaTestTool-v2/src/Amazon.Lambda.TestTool/Models/Exceptions.cs
+++ b/Tools/LambdaTestTool-v2/src/Amazon.Lambda.TestTool/Models/Exceptions.cs
@@ -6,7 +6,15 @@ namespace Amazon.Lambda.TestTool.Models;
///
/// Represents a base exception that is thrown by the test tool.
///
-///
-///
+/// The message used in the exception.
+/// The inner exception, if any.
public abstract class TestToolException(string message, Exception? innerException = null)
: Exception(message, innerException);
+
+///
+/// Thrown if the API Gateway Emulator mode was not provided,
+///
+/// The message used in the exception.
+/// The inner exception, if any.
+public class InvalidApiGatewayModeException(string message, Exception? innerException = null)
+ : TestToolException(message, innerException);
diff --git a/Tools/LambdaTestTool-v2/src/Amazon.Lambda.TestTool/Processes/ApiGatewayEmulatorProcess.cs b/Tools/LambdaTestTool-v2/src/Amazon.Lambda.TestTool/Processes/ApiGatewayEmulatorProcess.cs
index 3fa3eeef8..5a1e1d1a3 100644
--- a/Tools/LambdaTestTool-v2/src/Amazon.Lambda.TestTool/Processes/ApiGatewayEmulatorProcess.cs
+++ b/Tools/LambdaTestTool-v2/src/Amazon.Lambda.TestTool/Processes/ApiGatewayEmulatorProcess.cs
@@ -33,6 +33,11 @@ public class ApiGatewayEmulatorProcess
///
public static ApiGatewayEmulatorProcess Startup(RunCommandSettings settings, CancellationToken cancellationToken = default)
{
+ if (settings.ApiGatewayEmulatorMode is null)
+ {
+ throw new InvalidApiGatewayModeException("The API Gateway emulator mode was not provided.");
+ }
+
var builder = WebApplication.CreateBuilder();
builder.Services.AddApiGatewayEmulatorServices();
@@ -61,9 +66,7 @@ public static ApiGatewayEmulatorProcess Startup(RunCommandSettings settings, Can
{
app.Logger.LogInformation("Unable to find a configured Lambda route for the specified method and path: {Method} {Path}",
context.Request.Method, context.Request.Path);
- context.Response.StatusCode = StatusCodes.Status403Forbidden;
- context.Response.Headers.Append("x-amzn-errortype", "MissingAuthenticationTokenException");
- return Results.Json(new { message = "Missing Authentication Token" });
+ return ApiGatewayResults.RouteNotFound(context, (ApiGatewayEmulatorMode) settings.ApiGatewayEmulatorMode);
}
if (settings.ApiGatewayEmulatorMode.Equals(ApiGatewayEmulatorMode.HttpV2))
diff --git a/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.UnitTests/Helpers/TestHelpers.cs b/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.UnitTests/Helpers/TestHelpers.cs
index 578379453..deba2f4fa 100644
--- a/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.UnitTests/Helpers/TestHelpers.cs
+++ b/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.UnitTests/Helpers/TestHelpers.cs
@@ -31,6 +31,14 @@ internal static async Task WaitForApiToStartAsync(string url, int maxRetri
}
}
+ internal static async Task SendRequest(string url)
+ {
+ using (var client = new HttpClient())
+ {
+ return await client.GetAsync(url);
+ }
+ }
+
internal static async Task CancelAndWaitAsync(Task executeTask)
{
await Task.Delay(1000);
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
new file mode 100644
index 000000000..55cb7a6ef
--- /dev/null
+++ b/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.UnitTests/Processes/ApiGatewayEmulatorProcessTests.cs
@@ -0,0 +1,38 @@
+// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+using System.Net;
+using Amazon.Lambda.TestTool.Commands.Settings;
+using Amazon.Lambda.TestTool.Models;
+using Amazon.Lambda.TestTool.Processes;
+using Amazon.Lambda.TestTool.UnitTests.Helpers;
+
+namespace Amazon.Lambda.TestTool.UnitTests.Processes;
+
+public class ApiGatewayEmulatorProcessTests
+{
+ [Theory]
+ [InlineData(ApiGatewayEmulatorMode.Rest, HttpStatusCode.Forbidden, "{\"message\":\"Missing Authentication Token\"}")]
+ [InlineData(ApiGatewayEmulatorMode.HttpV1, HttpStatusCode.NotFound, "{\"message\":\"Not Found\"}")]
+ [InlineData(ApiGatewayEmulatorMode.HttpV2, HttpStatusCode.NotFound, "{\"message\":\"Not Found\"}")]
+ public async Task RouteNotFound(ApiGatewayEmulatorMode mode, HttpStatusCode statusCode, string body)
+ {
+ // Arrange
+ var cancellationSource = new CancellationTokenSource();
+ cancellationSource.CancelAfter(5000);
+ var settings = new RunCommandSettings { ApiGatewayEmulatorPort = 9003, ApiGatewayEmulatorMode = mode, NoLaunchWindow = true};
+ var apiUrl = $"http://{settings.Host}:{settings.ApiGatewayEmulatorPort}/__lambda_test_tool_apigateway_health__";
+
+ // Act
+ var process = ApiGatewayEmulatorProcess.Startup(settings, cancellationSource.Token);
+ var isApiRunning = await TestHelpers.WaitForApiToStartAsync(apiUrl);
+ var response = await TestHelpers.SendRequest($"{process.ServiceUrl}/invalid");
+ await cancellationSource.CancelAsync();
+
+ // Assert
+ await process.RunningTask;
+ Assert.True(isApiRunning);
+ Assert.Equal(statusCode, response.StatusCode);
+ Assert.Equal(body, await response.Content.ReadAsStringAsync());
+ }
+}