diff --git a/README.md b/README.md index 1cefe076..c55e3f82 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,6 @@ Here's an example of how to do this with a simple Lambda function that takes an ```csharp using System.Linq; using System.Net.Http; -using System.Reflection; using System.Threading; using System.Threading.Tasks; using Amazon.Lambda.RuntimeSupport; @@ -51,17 +50,7 @@ namespace MyFunctions var serializer = new JsonSerializer(); using var handlerWrapper = HandlerWrapper.GetHandlerWrapper(ReverseAsync, serializer); - using var bootstrap = new LambdaBootstrap(handlerWrapper); - - if (httpClient != null) - { - // Use reflection to assign the HttpClient to the LambdaBootstrap instance - var client = new RuntimeApiClient(httpClient); - var type = bootstrap.GetType(); - var property = type.GetProperty("Client", BindingFlags.Instance | BindingFlags.NonPublic); - - property.SetValue(bootstrap, client); - } + using var bootstrap = new LambdaBootstrap(httpClient ?? new HttpClient(), handlerWrapper); await bootstrap.RunAsync(cancellationToken); } @@ -74,10 +63,6 @@ namespace MyFunctions } ``` -Notice the use of reflection to set a new `RuntimeApiClient` instance using the specified `HttpClient` value onto the created instance of `LambdaBootstrap`. At the time of writing, this is the only way to configure things to use the Lambda test server to process requests. - -> I've reached out to the AWS Lambda .NET team with a suggestion to provide a supported way to specify a custom `HttpClient` in a future version of the NuGet package here: https://github.com/aws/aws-lambda-dotnet/pull/540 - Once you've done that, you can use `LambdaTestServer` in your tests with your function to verify how it processes requests. Here's an example using xunit to verify that `ReverseFunction` works as intended: @@ -340,7 +325,7 @@ Test Name: Function_Reverses_Numbers_With_Logging Test Outcome: Passed Result StandardOutput: [2019-11-04 15:21:06Z] info: Microsoft.AspNetCore.Hosting.Diagnostics[1] - Request starting HTTP/1.1 GET http://localhost/2018-06-01/runtime/invocation/next + Request starting HTTP/1.1 GET http://localhost/2018-06-01/runtime/invocation/next [2019-11-04 15:21:06Z] info: Microsoft.AspNetCore.Routing.EndpointMiddleware[0] Executing endpoint '/{LambdaVersion}/runtime/invocation/next HTTP: GET' [2019-11-04 15:21:06Z] info: MartinCostello.Testing.AwsLambdaTestServer.RuntimeHandler[0] @@ -352,7 +337,7 @@ Result StandardOutput: [2019-11-04 15:21:06Z] info: Microsoft.AspNetCore.Hosting.Diagnostics[2] Request finished in 71.9334ms 200 application/json [2019-11-04 15:21:06Z] info: Microsoft.AspNetCore.Hosting.Diagnostics[1] - Request starting HTTP/1.1 POST http://localhost/2018-06-01/runtime/invocation/7e1a283d-6268-4401-921c-0d0d67da1da4/response application/json + Request starting HTTP/1.1 POST http://localhost/2018-06-01/runtime/invocation/7e1a283d-6268-4401-921c-0d0d67da1da4/response application/json [2019-11-04 15:21:06Z] info: Microsoft.AspNetCore.Routing.EndpointMiddleware[0] Executing endpoint '/{LambdaVersion}/runtime/invocation/{AwsRequestId}/response HTTP: POST' [2019-11-04 15:21:06Z] info: MartinCostello.Testing.AwsLambdaTestServer.RuntimeHandler[0] @@ -362,7 +347,7 @@ Result StandardOutput: [2019-11-04 15:21:06Z] info: Microsoft.AspNetCore.Routing.EndpointMiddleware[1] Executed endpoint '/{LambdaVersion}/runtime/invocation/{AwsRequestId}/response HTTP: POST' [2019-11-04 15:21:06Z] info: Microsoft.AspNetCore.Hosting.Diagnostics[2] - Request finished in 26.6306ms 204 + Request finished in 26.6306ms 204 ``` ## Feedback diff --git a/src/AwsLambdaTestServer/RuntimeHandler.cs b/src/AwsLambdaTestServer/RuntimeHandler.cs index e5013194..56e314dc 100644 --- a/src/AwsLambdaTestServer/RuntimeHandler.cs +++ b/src/AwsLambdaTestServer/RuntimeHandler.cs @@ -151,11 +151,9 @@ internal async Task HandleNextAsync(HttpContext httpContext) "Stopped listening for additional requests for Lambda function with ARN {FunctionArn}.", _options.FunctionArn); - // Send a dummy response to prevent the listen loop from erroring - request = new LambdaTestRequest(new[] { (byte)'{', (byte)'}' }, "xx-lambda-test-server-stopped-xx"); - - // This dummy request wasn't enqueued, so it needs manually adding - _responses.GetOrAdd(request.AwsRequestId, (_) => new ResponseContext(Channel.CreateBounded(1))); + // Throw back into LambdaBootstrap, which will then stop processing. + // See https://github.com/aws/aws-lambda-dotnet/pull/540 for details of the change. + throw; } // Write the response for the Lambda runtime to pass to the function to invoke diff --git a/tests/AwsLambdaTestServer.Tests/FunctionRunner.cs b/tests/AwsLambdaTestServer.Tests/FunctionRunner.cs index b4e1fee9..2a71dcbd 100644 --- a/tests/AwsLambdaTestServer.Tests/FunctionRunner.cs +++ b/tests/AwsLambdaTestServer.Tests/FunctionRunner.cs @@ -2,7 +2,6 @@ // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. using System.Net.Http; -using System.Reflection; using System.Threading; using System.Threading.Tasks; using Amazon.Lambda.RuntimeSupport; @@ -19,17 +18,7 @@ internal static async Task RunAsync(HttpClient httpClient, CancellationToken var serializer = new JsonSerializer(); using var handlerWrapper = HandlerWrapper.GetHandlerWrapper(handler.SumAsync, serializer); - using var bootstrap = new LambdaBootstrap(handlerWrapper, handler.InitializeAsync); - - if (httpClient != null) - { - // Replace the internal runtime API client with one using the specified HttpClient. - // See https://github.com/aws/aws-lambda-dotnet/blob/4f9142b95b376bd238bce6be43f4e1ec1f983592/Libraries/src/Amazon.Lambda.RuntimeSupport/Bootstrap/LambdaBootstrap.cs#L41 - var client = new RuntimeApiClient(httpClient); - - var property = typeof(LambdaBootstrap).GetProperty("Client", BindingFlags.Instance | BindingFlags.NonPublic); - property.SetValue(bootstrap, client); - } + using var bootstrap = new LambdaBootstrap(httpClient, handlerWrapper, handler.InitializeAsync); await bootstrap.RunAsync(cancellationToken); } diff --git a/tests/AwsLambdaTestServer.Tests/LambdaTestServerTests.cs b/tests/AwsLambdaTestServer.Tests/LambdaTestServerTests.cs index 132e01cb..2eddad0c 100644 --- a/tests/AwsLambdaTestServer.Tests/LambdaTestServerTests.cs +++ b/tests/AwsLambdaTestServer.Tests/LambdaTestServerTests.cs @@ -7,7 +7,6 @@ using System.IO; using System.Linq; using System.Net.Http; -using System.Reflection; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -392,9 +391,11 @@ void Configure(IServiceCollection services) public void Finalizer_Does_Not_Throw() { #pragma warning disable CA2000 +#pragma warning disable IDE0067 // Act (no Assert) _ = new LambdaTestServer(); #pragma warning restore CA2000 +#pragma warning restore IDE0067 } [Fact] @@ -474,17 +475,7 @@ private static class CustomFunction internal static async Task RunAsync(HttpClient httpClient, CancellationToken cancellationToken) { var handler = new CustomHandler(); - using var bootstrap = new LambdaBootstrap(handler.InvokeAsync); - - if (httpClient != null) - { - // Replace the internal runtime API client with one using the specified HttpClient. - // See https://github.com/aws/aws-lambda-dotnet/blob/4f9142b95b376bd238bce6be43f4e1ec1f983592/Libraries/src/Amazon.Lambda.RuntimeSupport/Bootstrap/LambdaBootstrap.cs#L41 - var client = new RuntimeApiClient(httpClient); - - var property = typeof(LambdaBootstrap).GetProperty("Client", BindingFlags.Instance | BindingFlags.NonPublic); - property.SetValue(bootstrap, client); - } + using var bootstrap = new LambdaBootstrap(httpClient, handler.InvokeAsync); await bootstrap.RunAsync(cancellationToken); } diff --git a/tests/AwsLambdaTestServer.Tests/ReverseFunction.cs b/tests/AwsLambdaTestServer.Tests/ReverseFunction.cs index 1dddb13d..0e76b608 100644 --- a/tests/AwsLambdaTestServer.Tests/ReverseFunction.cs +++ b/tests/AwsLambdaTestServer.Tests/ReverseFunction.cs @@ -3,7 +3,6 @@ using System.Linq; using System.Net.Http; -using System.Reflection; using System.Threading; using System.Threading.Tasks; using Amazon.Lambda.RuntimeSupport; @@ -23,17 +22,7 @@ public static async Task RunAsync( var serializer = new JsonSerializer(); using var handlerWrapper = HandlerWrapper.GetHandlerWrapper(ReverseAsync, serializer); - using var bootstrap = new LambdaBootstrap(handlerWrapper); - - if (httpClient != null) - { - // Use reflection to assign the HttpClient to the LambdaBootstrap instance - var client = new RuntimeApiClient(httpClient); - var type = bootstrap.GetType(); - var property = type.GetProperty("Client", BindingFlags.Instance | BindingFlags.NonPublic); - - property.SetValue(bootstrap, client); - } + using var bootstrap = new LambdaBootstrap(httpClient ?? new HttpClient(), handlerWrapper); await bootstrap.RunAsync(cancellationToken); }