Test API endpoints with AWS SDK integration

Viewed 218

I'm trying to test my API endpoint that list files from an AWS S3 Bucket:

func listFiles(w http.ResponseWriter, _ *http.Request) {
    client := GetAWSClient()
    bucket := aws.String(BUCKETNAME)

    input := &s3.ListObjectsV2Input{
        Bucket: bucket,
    }

    resp, err := GetObjects(context.TODO(), client, input)
    if err != nil {
        ...
    }

    msg, _ := json.Marshal(resp.Contents)
    w.WriteHeader(200)
    w.Write(msg)
    return
}
...

func handleRequest() {
    myRouter := mux.NewRouter().StrictSlash(true)
    myRouter.HandleFunc("/listFiles", listFiles).Methods("GET")
    c := cors.Default()
    handler := c.Handler(myRouter)
    log.Fatal(http.ListenAndServe(":8080", handler))
}

I see from AWS SDK documentation that to mock AWS client functions you can use it interface so in my main_test.go I created these:

//Testing /listFiles endpoint

type mockListObjectsAPI func(ctx context.Context, params *s3.ListObjectsV2Input, optFns ...func(*s3.Options)) (*s3.ListObjectsV2Output, error)

func (m mockListObjectsAPI) ListObjectsV2(ctx context.Context, params *s3.ListObjectsV2Input, optFns ...func(*s3.Options)) (*s3.ListObjectsV2Output, error) {
    return m(ctx, params, optFns...)
}

func TestGetObjectFromS3(t *testing.T) {
    cases := []struct {
        client func(t *testing.T) S3ListObjectsAPI
        bucket string
        key    string
        expect []byte
    }{
        {
            client: func(t *testing.T) S3ListObjectsAPI {
                return mockListObjectsAPI(func(ctx context.Context, params *s3.ListObjectsV2Input, optFns ...func(*s3.Options)) (*s3.ListObjectsV2Output, error) {
                    t.Helper()
                    if params.Bucket == nil {
                        t.Fatal("expect bucket to not be nil")
                    }
                    if e, a := "fooBucket", *params.Bucket; e != a {
                        t.Errorf("expect %v, got %v", e, a)
                    }
                    return &s3.ListObjectsV2Output{
                        Name: aws.String("fooBucket"),
                    }, nil
                })
            },
            bucket: "fooBucket",
            key:    "barKey",
            expect: []byte("this is the body foo bar baz"),
        },
        //Add more test cases here if needed
    }

    for i, tt := range cases {
        t.Run(strconv.Itoa(i), func(t *testing.T) {
           //Here I should compare API returned value with expected in the test cases
        })
    }
}

My question is, how could I test my API calling it from the test but without calling AWS but instead using the values I mocked?

If I use httptest to call the endpoint it will call the real endpoint calling AWS.

0 Answers
Related