I'm trying to wrap my head around writing some unit tests for the first time ever, and I'm doing it in golang for a side project utilising aws lambda.
Below are two files.
main.go takes an event containing an email address, and creates the user in a cognito user pool.
main_test.go is supposed to mock the createUser function in main.go, but I'm getting an error when I try to run the test.
I've just switched my code from instantiating the client globally to using pointer receiver methods on the aws sdk interfaces after watching this youtube video.
main.go
package main
import (
"fmt"
"log"
"os"
"github.com/aws/aws-lambda-go/events"
"github.com/aws/aws-lambda-go/lambda"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/session"
cidp "github.com/aws/aws-sdk-go/service/cognitoidentityprovider"
cidpif "github.com/aws/aws-sdk-go/service/cognitoidentityprovider/cognitoidentityprovideriface"
lib "github.com/sean/repo/lib"
)
type createUserEvent struct {
EmailAddress string `json:"email_address"`
}
type awsService struct {
cidpif.CognitoIdentityProviderAPI
}
func (c *awsService) createUser(e createUserEvent) error {
input := &cidp.AdminCreateUserInput{
UserPoolId: aws.String(os.Getenv("USER_POOL_ID")),
Username: aws.String(e.EmailAddress),
DesiredDeliveryMediums: []*string{aws.String("EMAIL")},
ForceAliasCreation: aws.Bool(true),
UserAttributes: []*cidp.AttributeType{
{
Name: aws.String("email"),
Value: aws.String(e.EmailAddress),
},
},
}
_, err := c.AdminCreateUser(input)
if err != nil {
if aerr, ok := err.(awserr.Error); ok {
switch aerr.Code() {
case cidp.ErrCodeResourceNotFoundException:
log.Printf("[ERROR] %v, %v", cidp.ErrCodeResourceNotFoundException, aerr.Error())
case cidp.ErrCodeInvalidParameterException:
log.Printf("[ERROR] %v, %v", cidp.ErrCodeInvalidParameterException, aerr.Error())
case cidp.ErrCodeUserNotFoundException:
log.Printf("[ERROR] %v, %v", cidp.ErrCodeUserNotFoundException, aerr.Error())
case cidp.ErrCodeUsernameExistsException:
log.Printf("[ERROR] %v, %v", cidp.ErrCodeUsernameExistsException, aerr.Error())
case cidp.ErrCodeInvalidPasswordException:
log.Printf("[ERROR] %v, %v", cidp.ErrCodeInvalidPasswordException, aerr.Error())
case cidp.ErrCodeCodeDeliveryFailureException:
log.Printf("[ERROR] %v, %v", cidp.ErrCodeCodeDeliveryFailureException, aerr.Error())
case cidp.ErrCodeUnexpectedLambdaException:
log.Printf("[ERROR] %v, %v", cidp.ErrCodeUnexpectedLambdaException, aerr.Error())
case cidp.ErrCodeUserLambdaValidationException:
log.Printf("[ERROR] %v, %v", cidp.ErrCodeUserLambdaValidationException, aerr.Error())
case cidp.ErrCodeInvalidLambdaResponseException:
log.Printf("[ERROR] %v, %v", cidp.ErrCodeInvalidLambdaResponseException, aerr.Error())
case cidp.ErrCodePreconditionNotMetException:
log.Printf("[ERROR] %v, %v", cidp.ErrCodePreconditionNotMetException, aerr.Error())
case cidp.ErrCodeInvalidSmsRoleAccessPolicyException:
log.Printf("[ERROR] %v, %v", cidp.ErrCodeInvalidSmsRoleAccessPolicyException, aerr.Error())
case cidp.ErrCodeInvalidSmsRoleTrustRelationshipException:
log.Printf("[ERROR] %v, %v", cidp.ErrCodeInvalidSmsRoleTrustRelationshipException, aerr.Error())
case cidp.ErrCodeTooManyRequestsException:
log.Printf("[ERROR] %v, %v", cidp.ErrCodeTooManyRequestsException, aerr.Error())
case cidp.ErrCodeNotAuthorizedException:
log.Printf("[ERROR] %v, %v", cidp.ErrCodeNotAuthorizedException, aerr.Error())
case cidp.ErrCodeUnsupportedUserStateException:
log.Printf("[ERROR] %v, %v", cidp.ErrCodeUnsupportedUserStateException, aerr.Error())
case cidp.ErrCodeInternalErrorException:
log.Printf("[ERROR] %v, %v", cidp.ErrCodeInternalErrorException, aerr.Error())
default:
log.Printf("[ERROR] %v", err.Error())
}
} else {
log.Printf("[ERROR] %v", err.Error())
}
return err
}
log.Printf("[INFO] Created new user %v successfully", e.EmailAddress)
return nil
}
func (c *awsService) handler(e createUserEvent) (events.APIGatewayProxyResponse, error) {
headers := map[string]string{"Content-Type": "application/json"}
err := c.createUser(e)
if err != nil {
resp := lib.GenerateResponseBody(fmt.Sprintf("Error creating user %v", e.EmailAddress), 404, err, headers)
return resp, nil
}
resp := lib.GenerateResponseBody(fmt.Sprintf("Created new user %v", e.EmailAddress), 200, nil, headers)
return resp, nil
}
func main() {
c := awsService{cidp.New(session.New())}
lambda.Start(c.handler)
}
main_test.go
package main
import (
"os"
"testing"
cidp "github.com/aws/aws-sdk-go/service/cognitoidentityprovider"
cidpif "github.com/aws/aws-sdk-go/service/cognitoidentityprovider/cognitoidentityprovideriface"
)
type mockCreateUser struct {
cidpif.CognitoIdentityProviderAPI
Response cidp.AdminCreateUserOutput
}
func (d mockCreateUser) CreateUser(e createUserEvent) error {
return nil
}
func TestCreateUser(t *testing.T) {
t.Run("Successfully create user", func(t *testing.T) {
m := mockCreateUser{Response: cidp.AdminCreateUserOutput{}}
c := awsService{m}
err := os.Setenv("USER_POOL_ID", "ap-southeast-2_ovum4dzAL")
if err != nil {
t.Fatal(err)
}
err = c.createUser(createUserEvent{EmailAddress: "user@example.com"})
if err != nil {
t.Fatal("User should have been created")
}
})
}
the error
Running tool: /usr/local/go/bin/go test -timeout 30s -run ^TestCreateUser$ github.com/sean/repo/src/create_user
--- FAIL: TestCreateUser (0.00s)
--- FAIL: TestCreateUser/Successfully_create_user (0.00s)
panic: runtime error: invalid memory address or nil pointer dereference [recovered]
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x60 pc=0x137c2f2]
goroutine 6 [running]:
testing.tRunner.func1.1(0x13e00c0, 0x173fd70)
/usr/local/go/src/testing/testing.go:1072 +0x30d
testing.tRunner.func1(0xc000001b00)
/usr/local/go/src/testing/testing.go:1075 +0x41a
panic(0x13e00c0, 0x173fd70)
/usr/local/go/src/runtime/panic.go:969 +0x1b9
github.com/sean/repo/src/create_user.(*mockCreateUser).AdminCreateUser(0xc00000ee40, 0xc00006a200, 0xc00001e39d, 0x18, 0xc0000b24b0)
<autogenerated>:1 +0x32
github.com/sean/repo/src/create_user.(*awsService).createUser(0xc000030738, 0x145bbca, 0x10, 0x18, 0x0)
/Users/sean/code/github/sean/repo/src/create_user/main.go:39 +0x2b7
github.com/sean/repo/src/create_user.TestCreateUser.func1(0xc000001b00)
/Users/sean/code/github/sean/repo/src/create_user/main_test.go:30 +0x10c
testing.tRunner(0xc000001b00, 0x1476718)
/usr/local/go/src/testing/testing.go:1123 +0xef
created by testing.(*T).Run
/usr/local/go/src/testing/testing.go:1168 +0x2b3
FAIL github.com/sean/repo/src/create_user 0.543s
FAIL