Add unit tests for bucket handlers

This commit is contained in:
Lena Fuhrimann 2017-04-02 17:10:36 +02:00
parent 74fc4819fd
commit 6273ee201c
12 changed files with 235 additions and 32 deletions

View file

@ -4,26 +4,27 @@ import (
"encoding/json"
"net/http"
"github.com/mastertinner/s3-manager/web"
"github.com/mastertinner/s3-manager/datasources"
"github.com/mastertinner/s3-manager/utils"
minio "github.com/minio/minio-go"
)
// CreateHandler creates a new bucket
func CreateHandler(s3 *minio.Client) http.Handler {
func CreateHandler(s3 datasources.S3Client) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var bucket minio.BucketInfo
err := json.NewDecoder(r.Body).Decode(&bucket)
if err != nil {
msg := "error decoding json"
web.HandleHTTPError(w, msg, err, http.StatusUnprocessableEntity)
utils.HandleHTTPError(w, msg, err, http.StatusUnprocessableEntity)
return
}
err = s3.MakeBucket(bucket.Name, "")
if err != nil {
msg := "error making bucket"
web.HandleHTTPError(w, msg, err, http.StatusInternalServerError)
utils.HandleHTTPError(w, msg, err, http.StatusInternalServerError)
return
}
@ -33,7 +34,7 @@ func CreateHandler(s3 *minio.Client) http.Handler {
err = json.NewEncoder(w).Encode(bucket)
if err != nil {
msg := "error encoding json"
web.HandleHTTPError(w, msg, err, http.StatusInternalServerError)
utils.HandleHTTPError(w, msg, err, http.StatusInternalServerError)
return
}
})

View file

@ -0,0 +1,69 @@
package buckets_test
import (
"bytes"
"errors"
"net/http"
"net/http/httptest"
"testing"
"github.com/mastertinner/s3-manager/buckets"
"github.com/mastertinner/s3-manager/mock"
"github.com/stretchr/testify/assert"
)
func TestCreateHandler(t *testing.T) {
assert := assert.New(t)
tests := []struct {
description string
s3Client *mock.S3Client
body string
expectedStatusCode int
expectedBody string
}{
{
description: "success",
s3Client: &mock.S3Client{},
body: "{\"name\":\"myBucket\"}",
expectedStatusCode: http.StatusCreated,
expectedBody: "{\"name\":\"myBucket\",\"creationDate\":\"0001-01-01T00:00:00Z\"}\n",
},
{
description: "empty request",
s3Client: &mock.S3Client{},
body: "",
expectedStatusCode: http.StatusUnprocessableEntity,
expectedBody: "error decoding json\n",
},
{
description: "malformed request",
s3Client: &mock.S3Client{},
body: "}",
expectedStatusCode: http.StatusUnprocessableEntity,
expectedBody: "error decoding json\n",
},
{
description: "s3 error",
s3Client: &mock.S3Client{
Err: errors.New("internal S3 error"),
},
body: "{\"name\":\"myBucket\"}",
expectedStatusCode: http.StatusInternalServerError,
expectedBody: "error making bucket\n",
},
}
for _, tc := range tests {
req, err := http.NewRequest("POST", "/api/buckets", bytes.NewBufferString(tc.body))
assert.NoError(err)
rr := httptest.NewRecorder()
handler := buckets.CreateHandler(tc.s3Client)
handler.ServeHTTP(rr, req)
assert.Equal(tc.expectedStatusCode, rr.Code, tc.description)
assert.Equal(tc.expectedBody, rr.Body.String(), tc.description)
}
}

View file

@ -4,19 +4,19 @@ import (
"net/http"
"github.com/gorilla/mux"
"github.com/mastertinner/s3-manager/web"
minio "github.com/minio/minio-go"
"github.com/mastertinner/s3-manager/datasources"
"github.com/mastertinner/s3-manager/utils"
)
// DeleteHandler deletes a bucket
func DeleteHandler(s3 *minio.Client) http.Handler {
func DeleteHandler(s3 datasources.S3Client) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
err := s3.RemoveBucket(vars["bucketName"])
if err != nil {
msg := "error removing bucket"
web.HandleHTTPError(w, msg, err, http.StatusInternalServerError)
utils.HandleHTTPError(w, msg, err, http.StatusInternalServerError)
return
}

View file

@ -0,0 +1,51 @@
package buckets_test
import (
"errors"
"net/http"
"net/http/httptest"
"testing"
"github.com/mastertinner/s3-manager/buckets"
"github.com/mastertinner/s3-manager/mock"
"github.com/stretchr/testify/assert"
)
func TestDeleteHandler(t *testing.T) {
assert := assert.New(t)
tests := []struct {
description string
s3Client *mock.S3Client
expectedStatusCode int
expectedBody string
}{
{
description: "success",
s3Client: &mock.S3Client{},
expectedStatusCode: http.StatusNoContent,
expectedBody: "",
},
{
description: "s3 error",
s3Client: &mock.S3Client{
Err: errors.New("internal S3 error"),
},
expectedStatusCode: http.StatusInternalServerError,
expectedBody: "error removing bucket\n",
},
}
for _, tc := range tests {
req, err := http.NewRequest("DELETE", "/api/buckets/bucketName", nil)
assert.NoError(err)
rr := httptest.NewRecorder()
handler := buckets.DeleteHandler(tc.s3Client)
handler.ServeHTTP(rr, req)
assert.Equal(tc.expectedStatusCode, rr.Code, tc.description)
assert.Equal(tc.expectedBody, rr.Body.String(), tc.description)
}
}

19
datasources/s3-client.go Normal file
View file

@ -0,0 +1,19 @@
package datasources
import (
"io"
minio "github.com/minio/minio-go"
)
// S3Client is a client to interact with S3 storage
type S3Client interface {
CopyObject(string, string, string, minio.CopyConditions) error
GetObject(string, string) (*minio.Object, error)
ListBuckets() ([]minio.BucketInfo, error)
ListObjectsV2(string, string, bool, <-chan struct{}) <-chan minio.ObjectInfo
MakeBucket(string, string) error
PutObject(string, string, io.Reader, string) (int64, error)
RemoveBucket(string) error
RemoveObject(string, string) error
}

20
glide.lock generated
View file

@ -1,8 +1,8 @@
hash: 7dca8ea81fe671d950fb6be894196f33ffd39619039913b4fe573cd6c6f8d720
updated: 2017-03-30T15:17:43.230828675+02:00
hash: 5af937afdf2e2b202f0394765f6fa07af14098dd77047df4705611751b70fc16
updated: 2017-04-02T17:09:45.925326395+02:00
imports:
- name: github.com/gorilla/context
version: 1ea25387ff6f684839d82767c1733ff4d4d15d0a
version: 08b5f424b9271eedf6f9f0ce86cb9396ed337a42
- name: github.com/gorilla/mux
version: 392c28fe23e1c45ddba891b0320b3b5df220beea
- name: github.com/minio/minio-go
@ -12,4 +12,16 @@ imports:
- pkg/s3signer
- pkg/s3utils
- pkg/set
testImports: []
- name: github.com/stretchr/testify
version: 69483b4bd14f5845b5a1e55bca19e954e827f1d0
subpackages:
- assert
testImports:
- name: github.com/davecgh/go-spew
version: 6d212800a42e8ab5c146b8ace3490ee17e5225f9
subpackages:
- spew
- name: github.com/pmezard/go-difflib
version: d8ed2627bdf02c080bf22230dbb337003b7aba2d
subpackages:
- difflib

View file

@ -4,3 +4,7 @@ import:
version: ^2.0.2
- package: github.com/gorilla/mux
version: ^1.1.0
- package: github.com/stretchr/testify
version: ^1.1.4
subpackages:
- assert

46
mock/s3-client.go Normal file
View file

@ -0,0 +1,46 @@
package mock
import (
"io"
minio "github.com/minio/minio-go"
)
type S3Client struct {
Buckets []minio.BucketInfo
ObjectInfos []minio.ObjectInfo
Objects []minio.Object
Err error
}
func (s S3Client) CopyObject(string, string, string, minio.CopyConditions) error {
return s.Err
}
func (s S3Client) GetObject(string, string) (*minio.Object, error) {
return &s.Objects[0], s.Err
}
func (s S3Client) ListBuckets() ([]minio.BucketInfo, error) {
return s.Buckets, s.Err
}
func (s S3Client) ListObjectsV2(string, string, bool, <-chan struct{}) <-chan minio.ObjectInfo {
return make(<-chan minio.ObjectInfo)
}
func (s S3Client) MakeBucket(string, string) error {
return s.Err
}
func (s S3Client) PutObject(string, string, io.Reader, string) (int64, error) {
return 0, s.Err
}
func (s S3Client) RemoveBucket(string) error {
return s.Err
}
func (s S3Client) RemoveObject(string, string) error {
return s.Err
}

View file

@ -6,7 +6,8 @@ import (
"net/http"
"github.com/gorilla/mux"
"github.com/mastertinner/s3-manager/web"
"github.com/mastertinner/s3-manager/datasources"
"github.com/mastertinner/s3-manager/utils"
minio "github.com/minio/minio-go"
)
@ -19,7 +20,7 @@ type CopyObjectInfo struct {
}
// CreateHandler allows to upload a new object
func CreateHandler(s3 *minio.Client) http.Handler {
func CreateHandler(s3 datasources.S3Client) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
@ -29,16 +30,16 @@ func CreateHandler(s3 *minio.Client) http.Handler {
err := json.NewDecoder(r.Body).Decode(&copy)
if err != nil {
msg := "error decoding json"
web.HandleHTTPError(w, msg, err, http.StatusUnprocessableEntity)
utils.HandleHTTPError(w, msg, err, http.StatusUnprocessableEntity)
return
}
var copyConds = minio.NewCopyConditions()
copyConds := minio.NewCopyConditions()
objectSource := fmt.Sprintf("/%s/%s", copy.SourceBucketName, copy.SourceObjectName)
err = s3.CopyObject(copy.BucketName, copy.ObjectName, objectSource, copyConds)
if err != nil {
msg := "error copying object"
web.HandleHTTPError(w, msg, err, http.StatusInternalServerError)
utils.HandleHTTPError(w, msg, err, http.StatusInternalServerError)
return
}
@ -48,21 +49,21 @@ func CreateHandler(s3 *minio.Client) http.Handler {
err = json.NewEncoder(w).Encode(copy)
if err != nil {
msg := "error encoding json"
web.HandleHTTPError(w, msg, err, http.StatusInternalServerError)
utils.HandleHTTPError(w, msg, err, http.StatusInternalServerError)
return
}
} else {
err := r.ParseMultipartForm(32 << 20)
if err != nil {
msg := "error parsing form"
web.HandleHTTPError(w, msg, err, http.StatusUnprocessableEntity)
utils.HandleHTTPError(w, msg, err, http.StatusUnprocessableEntity)
return
}
file, handler, err := r.FormFile("file")
if err != nil {
msg := "error getting form file"
web.HandleHTTPError(w, msg, err, http.StatusInternalServerError)
utils.HandleHTTPError(w, msg, err, http.StatusInternalServerError)
return
}
defer file.Close()
@ -70,7 +71,7 @@ func CreateHandler(s3 *minio.Client) http.Handler {
_, err = s3.PutObject(vars["bucketName"], handler.Filename, file, "application/octet-stream")
if err != nil {
msg := "error putting object"
web.HandleHTTPError(w, msg, err, http.StatusInternalServerError)
utils.HandleHTTPError(w, msg, err, http.StatusInternalServerError)
return
}

View file

@ -4,19 +4,19 @@ import (
"net/http"
"github.com/gorilla/mux"
"github.com/mastertinner/s3-manager/web"
minio "github.com/minio/minio-go"
"github.com/mastertinner/s3-manager/datasources"
"github.com/mastertinner/s3-manager/utils"
)
// DeleteHandler deletes an object
func DeleteHandler(s3 *minio.Client) http.Handler {
func DeleteHandler(s3 datasources.S3Client) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
err := s3.RemoveObject(vars["bucketName"], vars["objectName"])
if err != nil {
msg := "error removing object"
web.HandleHTTPError(w, msg, err, http.StatusInternalServerError)
utils.HandleHTTPError(w, msg, err, http.StatusInternalServerError)
return
}

View file

@ -6,12 +6,12 @@ import (
"net/http"
"github.com/gorilla/mux"
"github.com/mastertinner/s3-manager/web"
minio "github.com/minio/minio-go"
"github.com/mastertinner/s3-manager/datasources"
"github.com/mastertinner/s3-manager/utils"
)
// GetHandler downloads an object to the client
func GetHandler(s3 *minio.Client) http.Handler {
func GetHandler(s3 datasources.S3Client) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
objectName := vars["objectName"]
@ -19,7 +19,7 @@ func GetHandler(s3 *minio.Client) http.Handler {
object, err := s3.GetObject(vars["bucketName"], objectName)
if err != nil {
msg := "error getting object"
web.HandleHTTPError(w, msg, err, http.StatusInternalServerError)
utils.HandleHTTPError(w, msg, err, http.StatusInternalServerError)
return
}
@ -29,7 +29,7 @@ func GetHandler(s3 *minio.Client) http.Handler {
_, err = io.Copy(w, object)
if err != nil {
msg := "error copying object"
web.HandleHTTPError(w, msg, err, http.StatusInternalServerError)
utils.HandleHTTPError(w, msg, err, http.StatusInternalServerError)
return
}
})

View file

@ -1,4 +1,4 @@
package web
package utils
import (
"log"