/* * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"). * You may not use this file except in compliance with the License. * A copy of the License is located at * * http://aws.amazon.com/apache2.0 * * or in the "license" file accompanying this file. This file is distributed * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either * express or implied. See the License for the specific language governing * permissions and limitations under the License. */ using System; using System.Collections.Generic; using System.Linq; using System.Net.Http; using System.Text; using System.Threading.Tasks; using Xunit; using Amazon.Lambda.RuntimeSupport.Bootstrap; using static Amazon.Lambda.RuntimeSupport.Bootstrap.Constants; namespace Amazon.Lambda.RuntimeSupport.UnitTests { /// /// Tests to test LambdaBootstrap when it's constructed using its actual constructor. /// Tests of the static GetLambdaBootstrap methods can be found in LambdaBootstrapWrapperTests. /// public class LambdaBootstrapTests { TestHandler _testFunction; TestInitializer _testInitializer; TestRuntimeApiClient _testRuntimeApiClient; TestEnvironmentVariables _environmentVariables; HandlerWrapper _testWrapper; public LambdaBootstrapTests() { _environmentVariables = new TestEnvironmentVariables(); var headers = new Dictionary> { { RuntimeApiHeaders.HeaderAwsRequestId, new List {"request_id"} }, { RuntimeApiHeaders.HeaderInvokedFunctionArn, new List {"invoked_function_arn"} } }; _testRuntimeApiClient = new TestRuntimeApiClient(_environmentVariables, headers); _testInitializer = new TestInitializer(); _testFunction = new TestHandler(); _testWrapper = HandlerWrapper.GetHandlerWrapper(_testFunction.HandlerVoidVoidSync); } [Fact] public void ThrowsExceptionForNullHandler() { Assert.Throws("handler", () => { new LambdaBootstrap((LambdaBootstrapHandler)null); }); } [Fact] public void ThrowsExceptionForNullHttpClient() { Assert.Throws("httpClient", () => { new LambdaBootstrap((HttpClient)null, _testFunction.BaseHandlerAsync); }); Assert.Throws("httpClient", () => { new LambdaBootstrap((HttpClient)null, _testWrapper); }); } [Fact] public async Task NoInitializer() { _testFunction.CancellationSource.Cancel(); using (var bootstrap = new LambdaBootstrap(_testFunction.BaseHandlerAsync, null)) { bootstrap.Client = _testRuntimeApiClient; await bootstrap.RunAsync(_testFunction.CancellationSource.Token); } Assert.False(_testInitializer.InitializerWasCalled); Assert.False(_testFunction.HandlerWasCalled); } [Fact] public async Task InitializerThrowsException() { using (var bootstrap = new LambdaBootstrap(_testFunction.BaseHandlerAsync, _testInitializer.InitializeThrowAsync)) { bootstrap.Client = _testRuntimeApiClient; var exception = await Assert.ThrowsAsync(async () => { await bootstrap.RunAsync(); }); Assert.Equal(TestInitializer.InitializeExceptionMessage, exception.Message); } Assert.True(_testRuntimeApiClient.ReportInitializationErrorAsyncExceptionCalled); Assert.True(_testInitializer.InitializerWasCalled); Assert.False(_testFunction.HandlerWasCalled); } [Fact] public async Task InitializerReturnsFalse() { using (var bootstrap = new LambdaBootstrap(_testFunction.BaseHandlerAsync, _testInitializer.InitializeFalseAsync)) { await bootstrap.RunAsync(); } Assert.True(_testInitializer.InitializerWasCalled); Assert.False(_testFunction.HandlerWasCalled); } [Fact] public async Task InitializerReturnsTrueAndHandlerLoopRuns() { using (var bootstrap = new LambdaBootstrap(_testFunction.BaseHandlerAsync, _testInitializer.InitializeTrueAsync)) { bootstrap.Client = _testRuntimeApiClient; await bootstrap.RunAsync(_testFunction.CancellationSource.Token); } Assert.True(_testInitializer.InitializerWasCalled); Assert.True(_testFunction.HandlerWasCalled); } [Fact] public async Task TraceIdEnvironmentVariableIsSet() { using (var bootstrap = new LambdaBootstrap(_testFunction.BaseHandlerAsync, null)) { bootstrap.Client = _testRuntimeApiClient; Assert.Null(_environmentVariables.GetEnvironmentVariable(LambdaEnvironment.EnvVarTraceId)); await bootstrap.InvokeOnceAsync(); Assert.NotNull(_testRuntimeApiClient.LastTraceId); Assert.Equal(_testRuntimeApiClient.LastTraceId, _environmentVariables.GetEnvironmentVariable(LambdaEnvironment.EnvVarTraceId)); } Assert.False(_testInitializer.InitializerWasCalled); Assert.True(_testFunction.HandlerWasCalled); } [Fact] public async Task HandlerThrowsException() { using (var bootstrap = new LambdaBootstrap(_testFunction.BaseHandlerThrowsAsync, null)) { bootstrap.Client = _testRuntimeApiClient; Assert.Null(_environmentVariables.GetEnvironmentVariable(LambdaEnvironment.EnvVarTraceId)); await bootstrap.InvokeOnceAsync(); } Assert.True(_testRuntimeApiClient.ReportInvocationErrorAsyncExceptionCalled); Assert.False(_testInitializer.InitializerWasCalled); Assert.True(_testFunction.HandlerWasCalled); } [Fact] public async Task HandlerInputAndOutputWork() { const string testInput = "a MiXeD cAsE sTrInG"; using (var bootstrap = new LambdaBootstrap(_testFunction.BaseHandlerToUpperAsync, null)) { _testRuntimeApiClient.FunctionInput = Encoding.UTF8.GetBytes(testInput); bootstrap.Client = _testRuntimeApiClient; Assert.Null(_environmentVariables.GetEnvironmentVariable(LambdaEnvironment.EnvVarTraceId)); await bootstrap.InvokeOnceAsync(); } _testRuntimeApiClient.VerifyOutput(testInput.ToUpper()); Assert.False(_testInitializer.InitializerWasCalled); Assert.True(_testFunction.HandlerWasCalled); } [Fact] public async Task HandlerReturnsNull() { using (var bootstrap = new LambdaBootstrap(_testFunction.BaseHandlerReturnsNullAsync, null)) { _testRuntimeApiClient.FunctionInput = new byte[0]; bootstrap.Client = _testRuntimeApiClient; Assert.Null(_environmentVariables.GetEnvironmentVariable(LambdaEnvironment.EnvVarTraceId)); await bootstrap.InvokeOnceAsync(); } _testRuntimeApiClient.VerifyOutput((byte[])null); Assert.False(_testInitializer.InitializerWasCalled); Assert.True(_testFunction.HandlerWasCalled); } [Fact] public void VerifyUserAgentStringSet() { var client = LambdaBootstrap.ConstructHttpClient(); var values = client.DefaultRequestHeaders.GetValues("User-Agent"); Assert.Single(values); var userAgent = values.First(); Assert.StartsWith("aws-lambda-dotnet", userAgent); var topLevelTokens = userAgent.Split('/'); Assert.Equal(2, topLevelTokens.Length); var versions = topLevelTokens[1].Split('-'); Assert.Equal(2, versions.Length); var dotnetVersion = Version.Parse(versions[0]); Assert.True(Version.Parse("2.0.0") < dotnetVersion); var runtimeLambdaSupportVersion = Version.Parse(versions[1]); Assert.True(Version.Parse("1.0.0") <= runtimeLambdaSupportVersion); } [Fact] public void IsCallPreJitTest() { Environment.SetEnvironmentVariable(ENVIRONMENT_VARIABLE_AWS_LAMBDA_DOTNET_PREJIT, "ProvisionedConcurrency"); Environment.SetEnvironmentVariable(ENVIRONMENT_VARIABLE_AWS_LAMBDA_INITIALIZATION_TYPE, AWS_LAMBDA_INITIALIZATION_TYPE_PC); Assert.True(UserCodeInit.IsCallPreJit()); Environment.SetEnvironmentVariable(ENVIRONMENT_VARIABLE_AWS_LAMBDA_DOTNET_PREJIT, "ProvisionedConcurrency"); Environment.SetEnvironmentVariable(ENVIRONMENT_VARIABLE_AWS_LAMBDA_INITIALIZATION_TYPE, AWS_LAMBDA_INITIALIZATION_TYPE_ON_DEMAND); Assert.False(UserCodeInit.IsCallPreJit()); Environment.SetEnvironmentVariable(ENVIRONMENT_VARIABLE_AWS_LAMBDA_DOTNET_PREJIT, "ProvisionedConcurrency"); Environment.SetEnvironmentVariable(ENVIRONMENT_VARIABLE_AWS_LAMBDA_INITIALIZATION_TYPE, null); Assert.False(UserCodeInit.IsCallPreJit()); Environment.SetEnvironmentVariable(ENVIRONMENT_VARIABLE_AWS_LAMBDA_DOTNET_PREJIT, "Always"); Environment.SetEnvironmentVariable(ENVIRONMENT_VARIABLE_AWS_LAMBDA_INITIALIZATION_TYPE, null); Assert.True(UserCodeInit.IsCallPreJit()); Environment.SetEnvironmentVariable(ENVIRONMENT_VARIABLE_AWS_LAMBDA_DOTNET_PREJIT, "Never"); Environment.SetEnvironmentVariable(ENVIRONMENT_VARIABLE_AWS_LAMBDA_INITIALIZATION_TYPE, null); Assert.False(UserCodeInit.IsCallPreJit()); Environment.SetEnvironmentVariable(ENVIRONMENT_VARIABLE_AWS_LAMBDA_DOTNET_PREJIT, null); Environment.SetEnvironmentVariable(ENVIRONMENT_VARIABLE_AWS_LAMBDA_INITIALIZATION_TYPE, null); Assert.False(UserCodeInit.IsCallPreJit()); Environment.SetEnvironmentVariable(ENVIRONMENT_VARIABLE_AWS_LAMBDA_DOTNET_PREJIT, null); Environment.SetEnvironmentVariable(ENVIRONMENT_VARIABLE_AWS_LAMBDA_INITIALIZATION_TYPE, AWS_LAMBDA_INITIALIZATION_TYPE_ON_DEMAND); Assert.False(UserCodeInit.IsCallPreJit()); Environment.SetEnvironmentVariable(ENVIRONMENT_VARIABLE_AWS_LAMBDA_DOTNET_PREJIT, "Never"); Environment.SetEnvironmentVariable(ENVIRONMENT_VARIABLE_AWS_LAMBDA_INITIALIZATION_TYPE, null); Assert.False(UserCodeInit.IsCallPreJit()); Environment.SetEnvironmentVariable(ENVIRONMENT_VARIABLE_AWS_LAMBDA_DOTNET_PREJIT, null); Environment.SetEnvironmentVariable(ENVIRONMENT_VARIABLE_AWS_LAMBDA_INITIALIZATION_TYPE, AWS_LAMBDA_INITIALIZATION_TYPE_PC); Assert.True(UserCodeInit.IsCallPreJit()); } } }