From 932e4a93c374a67d4347afafb15f0d4afd0fd101 Mon Sep 17 00:00:00 2001 From: jonaustin09 Date: Mon, 22 May 2023 23:27:01 +0400 Subject: [PATCH] feat: Add unit tests for GetActions, ListActions, PutBucketActions, PutActions controllers --- s3api/controllers/base_test.go | 407 ++++++++++++++++++++++++++++++--- 1 file changed, 370 insertions(+), 37 deletions(-) diff --git a/s3api/controllers/base_test.go b/s3api/controllers/base_test.go index 50b58fe..a92f221 100644 --- a/s3api/controllers/base_test.go +++ b/s3api/controllers/base_test.go @@ -1,6 +1,9 @@ package controllers import ( + "io" + "net/http" + "net/http/httptest" "reflect" "testing" @@ -103,41 +106,209 @@ func TestS3ApiController_ListBuckets(t *testing.T) { func TestS3ApiController_GetActions(t *testing.T) { type args struct { - ctx *fiber.Ctx + req *http.Request } + + app := fiber.New() + s3ApiController := S3ApiController{be: &BackendMock{ + ListObjectPartsFunc: func(bucket, object, uploadID string, partNumberMarker int, maxParts int) (*s3.ListPartsOutput, error) { + return &s3.ListPartsOutput{}, nil + }, + GetObjectAclFunc: func(bucket, object string) (*s3.GetObjectAclOutput, error) { + return &s3.GetObjectAclOutput{}, nil + }, + GetObjectAttributesFunc: func(bucket, object string, attributes []string) (*s3.GetObjectAttributesOutput, error) { + return &s3.GetObjectAttributesOutput{}, nil + }, + GetObjectFunc: func(bucket, object string, startOffset, length int64, writer io.Writer, etag string) (*s3.GetObjectOutput, error) { + return &s3.GetObjectOutput{Metadata: nil}, nil + }, + }} + app.Get("/:bucket/:key/*", s3ApiController.GetActions) + + // GetObjectACL + getObjectACLReq := httptest.NewRequest(http.MethodGet, "/my-bucket/key", nil) + getObjectACLReq.Header.Set("X-Amz-Object-Attributes", "attrs") + + // GetObject error case + getObjectReq := httptest.NewRequest(http.MethodGet, "/my-bucket/key", nil) + getObjectReq.Header.Set("Range", "hello=") + + // GetObject success case + getObjectSuccessReq := httptest.NewRequest(http.MethodGet, "/my-bucket/key", nil) + getObjectReq.Header.Set("Range", "range=13-invalid") + tests := []struct { - name string - c S3ApiController - args args - wantErr bool + name string + app *fiber.App + args args + wantErr bool + statusCode int }{ - // TODO: Add test cases. + { + name: "Get-actions-invalid-max-parts", + app: app, + args: args{ + req: httptest.NewRequest(http.MethodGet, "/my-bucket/key?uploadId=hello&max-parts=InvalidMaxParts", nil), + }, + wantErr: false, + statusCode: 500, + }, + { + name: "Get-actions-invalid-part-number", + app: app, + args: args{ + req: httptest.NewRequest(http.MethodGet, "/my-bucket/key?uploadId=hello&max-parts=200&part-number-marker=InvalidPartNumber", nil), + }, + wantErr: false, + statusCode: 500, + }, + { + name: "Get-actions-list-object-parts-success", + app: app, + args: args{ + req: httptest.NewRequest(http.MethodGet, "/my-bucket/key?uploadId=hello&max-parts=200&part-number-marker=23", nil), + }, + wantErr: false, + statusCode: 200, + }, + { + name: "Get-actions-get-object-acl-success", + app: app, + args: args{ + req: getObjectACLReq, + }, + wantErr: false, + statusCode: 200, + }, + { + name: "Get-actions-invalid-range-header", + app: app, + args: args{ + req: getObjectReq, + }, + wantErr: false, + statusCode: 500, + }, + { + name: "Get-actions-get-object-error", + app: app, + args: args{ + req: getObjectSuccessReq, + }, + wantErr: false, + statusCode: 500, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if err := tt.c.GetActions(tt.args.ctx); (err != nil) != tt.wantErr { + resp, err := tt.app.Test(tt.args.req) + + if (err != nil) != tt.wantErr { t.Errorf("S3ApiController.GetActions() error = %v, wantErr %v", err, tt.wantErr) } + + if resp.StatusCode != tt.statusCode { + t.Errorf("S3ApiController.GetActions() statusCode = %v, wantStatusCode = %v", resp.StatusCode, tt.statusCode) + } }) } } func TestS3ApiController_ListActions(t *testing.T) { type args struct { - ctx *fiber.Ctx + req *http.Request } + + app := fiber.New() + s3ApiController := S3ApiController{be: &BackendMock{ + GetBucketAclFunc: func(bucket string) (*s3.GetBucketAclOutput, error) { + return &s3.GetBucketAclOutput{}, nil + }, + ListMultipartUploadsFunc: func(output *s3.ListMultipartUploadsInput) (*s3.ListMultipartUploadsOutput, error) { + return &s3.ListMultipartUploadsOutput{}, nil + }, + ListObjectsV2Func: func(bucket, prefix, marker, delim string, maxkeys int) (*s3.ListBucketsOutput, error) { + return &s3.ListBucketsOutput{}, nil + }, + ListObjectsFunc: func(bucket, prefix, marker, delim string, maxkeys int) (*s3.ListBucketsOutput, error) { + return &s3.ListBucketsOutput{}, nil + }, + }} + app.Get("/:bucket", s3ApiController.ListActions) + + //Error case + s3ApiControllerError := S3ApiController{be: &BackendMock{ + ListObjectsFunc: func(bucket, prefix, marker, delim string, maxkeys int) (*s3.ListBucketsOutput, error) { + return nil, s3err.GetAPIError(s3err.ErrNotImplemented) + }, + }} + appError := fiber.New() + appError.Get("/:bucket", s3ApiControllerError.ListActions) + tests := []struct { - name string - c S3ApiController - args args - wantErr bool + name string + app *fiber.App + args args + wantErr bool + statusCode int }{ - // TODO: Add test cases. + { + name: "Get-bucket-acl-success", + app: app, + args: args{ + req: httptest.NewRequest(http.MethodGet, "/my-bucket?acl=acl", nil), + }, + wantErr: false, + statusCode: 200, + }, + { + name: "List-Multipart-Upload-success", + app: app, + args: args{ + req: httptest.NewRequest(http.MethodGet, "/my-bucket?uploads=uploads", nil), + }, + wantErr: false, + statusCode: 200, + }, + { + name: "List-Objects-V2-success", + app: app, + args: args{ + req: httptest.NewRequest(http.MethodGet, "/my-bucket?list-type=2", nil), + }, + wantErr: false, + statusCode: 200, + }, + { + name: "List-Objects-V1-success", + app: app, + args: args{ + req: httptest.NewRequest(http.MethodGet, "/my-bucket", nil), + }, + wantErr: false, + statusCode: 200, + }, + { + name: "List-actions-error-case", + app: appError, + args: args{ + req: httptest.NewRequest(http.MethodGet, "/my-bucket", nil), + }, + wantErr: false, + statusCode: 501, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if err := tt.c.ListActions(tt.args.ctx); (err != nil) != tt.wantErr { - t.Errorf("S3ApiController.ListActions() error = %v, wantErr %v", err, tt.wantErr) + resp, err := tt.app.Test(tt.args.req) + + if (err != nil) != tt.wantErr { + t.Errorf("S3ApiController.GetActions() error = %v, wantErr %v", err, tt.wantErr) + } + + if resp.StatusCode != tt.statusCode { + t.Errorf("S3ApiController.GetActions() statusCode = %v, wantStatusCode = %v", resp.StatusCode, tt.statusCode) } }) } @@ -145,43 +316,205 @@ func TestS3ApiController_ListActions(t *testing.T) { func TestS3ApiController_PutBucketActions(t *testing.T) { type args struct { - ctx *fiber.Ctx + req *http.Request } + + app := fiber.New() + s3ApiController := S3ApiController{be: &BackendMock{ + PutBucketAclFunc: func(*s3.PutBucketAclInput) error { + return nil + }, + PutBucketFunc: func(bucket string) error { + return nil + }, + }} + app.Put("/:bucket", s3ApiController.PutBucketActions) + + // Error case + errorReq := httptest.NewRequest(http.MethodPut, "/my-bucket", nil) + errorReq.Header.Set("X-Amz-Acl", "restricted") + errorReq.Header.Set("X-Amz-Grant-Read", "read") + + // PutBucketAcl success + aclReq := httptest.NewRequest(http.MethodPut, "/my-bucket", nil) + errorReq.Header.Set("X-Amz-Acl", "full") + tests := []struct { - name string - c S3ApiController - args args - wantErr bool + name string + app *fiber.App + args args + wantErr bool + statusCode int }{ - // TODO: Add test cases. + { + name: "Put-bucket-acl-error", + app: app, + args: args{ + req: errorReq, + }, + wantErr: false, + statusCode: 500, + }, + { + name: "Put-object-acl-success", + app: app, + args: args{ + req: aclReq, + }, + wantErr: false, + statusCode: 200, + }, + { + name: "Put-bucket-success", + app: app, + args: args{ + req: httptest.NewRequest(http.MethodPut, "/my-bucket", nil), + }, + wantErr: false, + statusCode: 200, + }, } for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if err := tt.c.PutBucketActions(tt.args.ctx); (err != nil) != tt.wantErr { - t.Errorf("S3ApiController.PutBucketActions() error = %v, wantErr %v", err, tt.wantErr) - } - }) + resp, err := tt.app.Test(tt.args.req) + + if (err != nil) != tt.wantErr { + t.Errorf("S3ApiController.GetActions() error = %v, wantErr %v", err, tt.wantErr) + } + + if resp.StatusCode != tt.statusCode { + t.Errorf("S3ApiController.GetActions() statusCode = %v, wantStatusCode = %v", resp.StatusCode, tt.statusCode) + } } } func TestS3ApiController_PutActions(t *testing.T) { type args struct { - ctx *fiber.Ctx + req *http.Request } + + app := fiber.New() + s3ApiController := S3ApiController{be: &BackendMock{ + UploadPartCopyFunc: func(*s3.UploadPartCopyInput) (*s3.UploadPartCopyOutput, error) { + return &s3.UploadPartCopyOutput{}, nil + }, + UploadPartFunc: func(bucket, object, uploadId string, Body io.ReadSeeker) (*s3.UploadPartOutput, error) { + return &s3.UploadPartOutput{}, nil + }, + PutObjectAclFunc: func(*s3.PutObjectAclInput) error { + return nil + }, + CopyObjectFunc: func(srcBucket, srcObject, DstBucket, dstObject string) (*s3.CopyObjectOutput, error) { + return &s3.CopyObjectOutput{}, nil + }, + PutObjectFunc: func(bucket, object string, r io.Reader) (string, error) { + return "hello", nil + }, + }} + app.Put("/:bucket/:key/*", s3ApiController.PutActions) + + //PutObjectAcl error + aclReqErr := httptest.NewRequest(http.MethodPut, "/my-bucket/my-key", nil) + aclReqErr.Header.Set("X-Amz-Acl", "acl") + aclReqErr.Header.Set("X-Amz-Grant-Write", "write") + + //PutObjectAcl success + aclReq := httptest.NewRequest(http.MethodPut, "/my-bucket/my-key", nil) + aclReq.Header.Set("X-Amz-Acl", "acl") + + //CopyObject success + cpySrcReq := httptest.NewRequest(http.MethodPut, "/my-bucket/my-key", nil) + cpySrcReq.Header.Set("X-Amz-Copy-Source", "srcBucket/srcObject") + tests := []struct { - name string - c S3ApiController - args args - wantErr bool + name string + app *fiber.App + args args + wantErr bool + statusCode int }{ - // TODO: Add test cases. + { + name: "Upload-copy-part-error-case", + app: app, + args: args{ + req: httptest.NewRequest(http.MethodPut, "/my-bucket/my-key?partNumber=invalid", nil), + }, + wantErr: false, + statusCode: 500, + }, + { + name: "Upload-copy-part-success", + app: app, + args: args{ + req: httptest.NewRequest(http.MethodPut, "/my-bucket/my-key?partNumber=3", nil), + }, + wantErr: false, + statusCode: 200, + }, + { + name: "Upload-part-success", + app: app, + args: args{ + req: httptest.NewRequest(http.MethodPut, "/my-bucket/my-key?uploadId=234234", nil), + }, + wantErr: false, + statusCode: 200, + }, + { + name: "Put-object-acl-error", + app: app, + args: args{ + req: aclReqErr, + }, + wantErr: false, + statusCode: 500, + }, + { + name: "Put-object-acl-error", + app: app, + args: args{ + req: aclReqErr, + }, + wantErr: false, + statusCode: 500, + }, + { + name: "Put-object-acl-success", + app: app, + args: args{ + req: aclReq, + }, + wantErr: false, + statusCode: 200, + }, + { + name: "Copy-object-success", + app: app, + args: args{ + req: cpySrcReq, + }, + wantErr: false, + statusCode: 200, + }, + { + name: "Put-object-success", + app: app, + args: args{ + req: httptest.NewRequest(http.MethodPut, "/my-bucket/my-key", nil), + }, + wantErr: false, + statusCode: 200, + }, } for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if err := tt.c.PutActions(tt.args.ctx); (err != nil) != tt.wantErr { - t.Errorf("S3ApiController.PutActions() error = %v, wantErr %v", err, tt.wantErr) - } - }) + resp, err := tt.app.Test(tt.args.req) + + if (err != nil) != tt.wantErr { + t.Errorf("S3ApiController.GetActions() error = %v, wantErr %v", err, tt.wantErr) + } + + if resp.StatusCode != tt.statusCode { + t.Errorf("S3ApiController.GetActions() statusCode = %v, wantStatusCode = %v", resp.StatusCode, tt.statusCode) + } } }