From dee28937940acad7ce06b66d197b051e1fc5702b Mon Sep 17 00:00:00 2001 From: Karri Balk Date: Tue, 30 Mar 2021 00:43:44 -0400 Subject: [PATCH] Create InvokeFunctionWithParamsE - Restore InvokeFunction so it once again calls InvokeFunctionE version InvokeFunctionWithParams - Use functionName as an argument and not a field of the LambdaOptions struct. --- modules/aws/lambda.go | 54 ++++++++++------------- test/terraform_aws_lambda_example_test.go | 41 ++++++++--------- 2 files changed, 44 insertions(+), 51 deletions(-) diff --git a/modules/aws/lambda.go b/modules/aws/lambda.go index 7dc270f92e..574f5bc2a1 100644 --- a/modules/aws/lambda.go +++ b/modules/aws/lambda.go @@ -13,16 +13,13 @@ import ( // LambdaOptions contains additional parameters for InvokeFunctionWithParams(). // It contains a subset of the fields found in the lambda.InvokeInput struct. type LambdaOptions struct { - // FunctionName is a required field containing the lambda function name. - FunctionName *string - - // InvocationType can be one of "RequestResponse" or "DryRun". - // * RequestResponse (default) - Invoke the function synchronously. - // Keep the connection open until the function returns a response - // or times out. - // - // * DryRun - Validate parameter values and verify that the user or - // role has permission to invoke the function. + // InvocationType can be one of lambda.InvocationTypeRequestResponse + // or lambda.InvocationTypeDryRun. + // * InvocationTypeRequestResponse (default) - Invoke the function + // synchronously. Keep the connection open until the function + // returns a response or times out. + // * InvocationTypeDryRun - Validate parameter values and verify + // that the user or role has permission to invoke the function. InvocationType *string // Lambda function input; will be converted to JSON. @@ -48,22 +45,15 @@ type LambdaOutput struct { // InvokeFunction invokes a lambda function. func InvokeFunction(t testing.TestingT, region, functionName string, payload interface{}) []byte { - input := &LambdaOptions{ - FunctionName: &functionName, - Payload: &payload, - } - out, err := InvokeFunctionWithParams(t, region, input) + out, err := InvokeFunctionE(t, region, functionName, payload) require.NoError(t, err) - return out.Payload + return out } // InvokeFunctionE invokes a lambda function. func InvokeFunctionE(t testing.TestingT, region, functionName string, payload interface{}) ([]byte, error) { - input := &LambdaOptions{ - FunctionName: &functionName, - Payload: &payload, - } - out, err := InvokeFunctionWithParams(t, region, input) + input := &LambdaOptions{Payload: &payload} + out, err := InvokeFunctionWithParamsE(t, region, functionName, input) if err != nil { return nil, err } @@ -77,20 +67,22 @@ func InvokeFunctionE(t testing.TestingT, region, functionName string, payload in // InvokeFunctionWithParams invokes a lambda function using parameters // supplied in the LambdaOptions struct and returns values in a LambdaOutput -// struct. -func InvokeFunctionWithParams(t testing.TestingT, region string, input *LambdaOptions) (*LambdaOutput, error) { +// struct. Checks for failure using "require". +func InvokeFunctionWithParams(t testing.TestingT, region, functionName string, input *LambdaOptions) *LambdaOutput { + out, err := InvokeFunctionWithParamsE(t, region, functionName, input) + require.NoError(t, err) + return out +} + +// InvokeFunctionWithParamsE invokes a lambda function using parameters +// supplied in the LambdaOptions struct and returns values in a LambdaOutput +// struct and the error. +func InvokeFunctionWithParamsE(t testing.TestingT, region, functionName string, input *LambdaOptions) (*LambdaOutput, error) { lambdaClient, err := NewLambdaClientE(t, region) if err != nil { return nil, err } - // The function name is a required field in LambdaOptions. If missing, - // report the error. - if input.FunctionName == nil { - msg := "LambdaOptions.FunctionName is a required field" - return &LambdaOutput{FunctionError: &msg}, errors.New(msg) - } - // Verify the InvocationType is one of the allowed values and report // an error if its not. By default the InvocationType will be // "RequestResponse". @@ -110,7 +102,7 @@ func InvokeFunctionWithParams(t testing.TestingT, region string, input *LambdaOp } invokeInput := &lambda.InvokeInput{ - FunctionName: input.FunctionName, + FunctionName: &functionName, InvocationType: &invocationType, } diff --git a/test/terraform_aws_lambda_example_test.go b/test/terraform_aws_lambda_example_test.go index b905a5b76c..683583aae1 100644 --- a/test/terraform_aws_lambda_example_test.go +++ b/test/terraform_aws_lambda_example_test.go @@ -4,6 +4,7 @@ import ( "fmt" "testing" + "github.com/aws/aws-sdk-go/service/lambda" "github.com/gruntwork-io/terratest/modules/aws" "github.com/gruntwork-io/terratest/modules/random" "github.com/gruntwork-io/terratest/modules/terraform" @@ -101,41 +102,41 @@ func TestTerraformAwsLambdaWithParamsExample(t *testing.T) { // Call InvokeFunctionWithParms with an InvocationType of "DryRun". // A "DryRun" invocation does not execute the function, so the example // test function will not be checking the payload. - invocationType := "DryRun" - input := &aws.LambdaOptions{ - FunctionName: &functionName, - InvocationType: &invocationType, - } - out, err := aws.InvokeFunctionWithParams(t, awsRegion, input) + invocationType := lambda.InvocationTypeDryRun + input := &aws.LambdaOptions{InvocationType: &invocationType} + out := aws.InvokeFunctionWithParams(t, awsRegion, functionName, input) // With "DryRun", there's no message in the output, but there is // a status code which will have a value of 204 for a successful // invocation. - require.Nil(t, err) assert.Equal(t, int(*out.StatusCode), 204) - // Call InvokeFunctionWithParams with a LambdaOptions struct that's - // missing a function name. The function should fail. + // Invoke the function, this time causing the Lambda to error and + // capturing the error. + invocationType = lambda.InvocationTypeRequestResponse input = &aws.LambdaOptions{ - Payload: ExampleFunctionPayload{ShouldFail: false, Echo: "hi!"}, + InvocationType: &invocationType, + Payload: ExampleFunctionPayload{ShouldFail: true, Echo: "hi!"}, } - out, err = aws.InvokeFunctionWithParams(t, awsRegion, input) - require.NotNil(t, err) - msg := "LambdaOptions.FunctionName is a required field" - assert.Contains(t, err.Error(), msg) - assert.Contains(t, *out.FunctionError, msg) + out, err := aws.InvokeFunctionWithParamsE(t, awsRegion, functionName, input) + + // No error in the invocation as Lambda was found and executed. + require.Nil(t, err) + assert.Equal(t, int(*out.StatusCode), 200) + + // Make sure the function-specific error comes back + assert.Contains(t, string(out.Payload), "Failed to handle") - // Call InvokeFunctionWithParams with a LambdaOptions struct with an - // unsupported InvocationType. The function should fail. + // Call InvokeFunctionWithParamsE with a LambdaOptions struct that has + // an unsupported InvocationType. The function should fail. invocationType = "Event" input = &aws.LambdaOptions{ - FunctionName: &functionName, InvocationType: &invocationType, Payload: ExampleFunctionPayload{ShouldFail: false, Echo: "hi!"}, } - out, err = aws.InvokeFunctionWithParams(t, awsRegion, input) + out, err = aws.InvokeFunctionWithParamsE(t, awsRegion, functionName, input) require.NotNil(t, err) - msg = "LambdaOptions.InvocationType, if specified, must either be \"RequestResponse\" or \"DryRun\"" + msg := "LambdaOptions.InvocationType, if specified, must either be \"RequestResponse\" or \"DryRun\"" assert.Contains(t, err.Error(), msg) assert.Contains(t, *out.FunctionError, msg) }