Skip to content

Commit

Permalink
Create InvokeFunctionWithParamsE
Browse files Browse the repository at this point in the history
- Restore InvokeFunction so it once again calls InvokeFunctionE
  version InvokeFunctionWithParams
- Use functionName as an argument and not a field of the
  LambdaOptions struct.
  • Loading branch information
kbalk committed Mar 30, 2021
1 parent be649ef commit dee2893
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 51 deletions.
54 changes: 23 additions & 31 deletions modules/aws/lambda.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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
}
Expand All @@ -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".
Expand All @@ -110,7 +102,7 @@ func InvokeFunctionWithParams(t testing.TestingT, region string, input *LambdaOp
}

invokeInput := &lambda.InvokeInput{
FunctionName: input.FunctionName,
FunctionName: &functionName,
InvocationType: &invocationType,
}

Expand Down
41 changes: 21 additions & 20 deletions test/terraform_aws_lambda_example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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)
}
Expand Down

0 comments on commit dee2893

Please sign in to comment.