diff --git a/bucket-view_test.go b/bucket-view_test.go index 1043010..fc9b389 100644 --- a/bucket-view_test.go +++ b/bucket-view_test.go @@ -37,7 +37,7 @@ func TestBucketViewHandler(t *testing.T) { Buckets: []minio.BucketInfo{ {Name: "testBucket"}, }, - ObjectInfos: []minio.ObjectInfo{ + Objects: []minio.ObjectInfo{ {Key: "testFile"}, }, }, @@ -50,7 +50,7 @@ func TestBucketViewHandler(t *testing.T) { Buckets: []minio.BucketInfo{ {Name: "testBucket"}, }, - ObjectInfos: []minio.ObjectInfo{ + Objects: []minio.ObjectInfo{ {Key: "archive.tar.gz"}, }, }, @@ -63,7 +63,7 @@ func TestBucketViewHandler(t *testing.T) { Buckets: []minio.BucketInfo{ {Name: "testBucket"}, }, - ObjectInfos: []minio.ObjectInfo{ + Objects: []minio.ObjectInfo{ {Key: "testImage.png"}, }, }, @@ -76,7 +76,7 @@ func TestBucketViewHandler(t *testing.T) { Buckets: []minio.BucketInfo{ {Name: "testBucket"}, }, - ObjectInfos: []minio.ObjectInfo{ + Objects: []minio.ObjectInfo{ {Key: "testSound.mp3"}, }, }, @@ -92,7 +92,7 @@ func TestBucketViewHandler(t *testing.T) { }, "s3 error": { s3: &S3ClientMock{ - Err: errors.New("internal S3 error"), + Err: errors.New("mocked S3 error"), }, bucketName: "testBucket", expectedStatusCode: http.StatusInternalServerError, diff --git a/buckets-view_test.go b/buckets-view_test.go index 33fe2f3..459474d 100644 --- a/buckets-view_test.go +++ b/buckets-view_test.go @@ -34,7 +34,7 @@ func TestBucketsViewHandler(t *testing.T) { }, "s3 error": { s3: &S3ClientMock{ - Err: errors.New("internal S3 error"), + Err: errors.New("mocked S3 error"), }, expectedStatusCode: http.StatusInternalServerError, expectedBodyContains: "error listing buckets\n", diff --git a/create-bucket_test.go b/create-bucket_test.go index 92753be..d7ef8db 100644 --- a/create-bucket_test.go +++ b/create-bucket_test.go @@ -39,7 +39,7 @@ func TestCreateBucketHandler(t *testing.T) { }, "s3 error": { s3: &S3ClientMock{ - Err: errors.New("internal S3 error"), + Err: errors.New("mocked S3 error"), }, body: "{\"name\":\"myBucket\"}", expectedStatusCode: http.StatusInternalServerError, diff --git a/delete-bucket_test.go b/delete-bucket_test.go index 49a8b4e..dc6a7b6 100644 --- a/delete-bucket_test.go +++ b/delete-bucket_test.go @@ -24,7 +24,7 @@ func TestDeleteBucketHandler(t *testing.T) { }, "s3 error": { s3: &S3ClientMock{ - Err: errors.New("internal S3 error"), + Err: errors.New("mocked S3 error"), }, expectedStatusCode: http.StatusInternalServerError, expectedBody: "error removing bucket\n", diff --git a/delete-object_test.go b/delete-object_test.go index 8d25c11..ea79b75 100644 --- a/delete-object_test.go +++ b/delete-object_test.go @@ -24,7 +24,7 @@ func TestDeleteObjectHandler(t *testing.T) { }, "s3 error": { s3: &S3ClientMock{ - Err: errors.New("internal S3 error"), + Err: errors.New("mocked S3 error"), }, expectedStatusCode: http.StatusInternalServerError, expectedBody: "error removing object\n", diff --git a/get-object.go b/get-object.go index 77865a3..6801942 100644 --- a/get-object.go +++ b/get-object.go @@ -27,7 +27,17 @@ func GetObjectHandler(s3 S3Client) http.Handler { _, err = io.Copy(w, object) if err != nil { msg := "error copying object" - handleHTTPError(w, msg, err, http.StatusInternalServerError) + code := http.StatusInternalServerError + if err.Error() == "The specified key does not exist." { + msg = "object not found" + code = http.StatusNotFound + } + if err.Error() == "The specified bucket does not exist." { + msg = "bucket not found" + code = http.StatusNotFound + } + + handleHTTPError(w, msg, err, code) return } }) diff --git a/get-object_test.go b/get-object_test.go new file mode 100644 index 0000000..1e468f2 --- /dev/null +++ b/get-object_test.go @@ -0,0 +1,57 @@ +package main + +import ( + "errors" + "fmt" + "io/ioutil" + "net/http" + "net/http/httptest" + "testing" + + "github.com/gorilla/mux" + "github.com/stretchr/testify/assert" +) + +func TestGetObjectHandler(t *testing.T) { + assert := assert.New(t) + + tests := map[string]struct { + s3 S3Client + bucketName string + objectName string + expectedStatusCode int + expectedBodyCountains string + }{ + "s3 error": { + s3: &S3ClientMock{ + Err: errors.New("mocked S3 error"), + }, + bucketName: "testBucket", + objectName: "testObject", + expectedStatusCode: http.StatusInternalServerError, + expectedBodyCountains: "error getting object\n", + }, + } + + for _, tc := range tests { + r := mux.NewRouter() + r. + Methods("GET"). + Path("/buckets/{bucketName}/objects/{objectName}"). + Handler(GetObjectHandler(tc.s3)) + + ts := httptest.NewServer(r) + defer ts.Close() + + url := fmt.Sprintf("%s/buckets/%s/objects/%s", ts.URL, tc.bucketName, tc.objectName) + resp, err := http.Get(url) + assert.NoError(err) + defer resp.Body.Close() + + body, err := ioutil.ReadAll(resp.Body) + assert.NoError(err) + + assert.Equal(tc.expectedStatusCode, resp.StatusCode) + assert.Contains(string(body), tc.expectedBodyCountains) + } +} diff --git a/index-view.go b/index-view.go index 8dfadbb..45a60e7 100644 --- a/index-view.go +++ b/index-view.go @@ -2,7 +2,7 @@ package main import "net/http" -// IndexHandler forwards to "/buckets" +// IndexViewHandler forwards to "/buckets" func IndexViewHandler() http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { http.Redirect(w, r, "/buckets", http.StatusPermanentRedirect) diff --git a/index-view_test.go b/index-view_test.go new file mode 100644 index 0000000..8394b08 --- /dev/null +++ b/index-view_test.go @@ -0,0 +1,36 @@ +package main + +import ( + "net/http" + "net/http/httptest" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestIndexViewHandler(t *testing.T) { + assert := assert.New(t) + + tests := map[string]struct { + expectedStatusCode int + expectedBodyContains string + }{ + "success": { + expectedStatusCode: http.StatusPermanentRedirect, + expectedBodyContains: "Redirect", + }, + } + + for _, tc := range tests { + req, err := http.NewRequest("GET", "/", nil) + assert.NoError(err) + + rr := httptest.NewRecorder() + handler := IndexViewHandler() + + handler.ServeHTTP(rr, req) + + assert.Equal(tc.expectedStatusCode, rr.Code) + assert.Contains(rr.Body.String(), tc.expectedBodyContains) + } +} diff --git a/main.go b/main.go index 26ba595..c3ef265 100644 --- a/main.go +++ b/main.go @@ -11,7 +11,7 @@ import ( ) func main() { - s3 := NewMinioClient() + s3 := newMinioClient() logger := log.New(os.Stdout, "", log.Ldate|log.Ltime) router := mux.NewRouter() diff --git a/minio.go b/minio.go index cbd1b27..7e10db1 100644 --- a/minio.go +++ b/minio.go @@ -7,23 +7,23 @@ import ( "github.com/minio/minio-go" ) -// NewMinioClient creates a new Minio client -func NewMinioClient() *minio.Client { +// newMinioClient creates a new Minio client +func newMinioClient() *minio.Client { var err error var client *minio.Client s3Endpoint := os.Getenv("S3_ENDPOINT") - if len(s3Endpoint) == 0 { + if s3Endpoint == "" { s3Endpoint = "s3.amazonaws.com" } s3AccessKeyID := os.Getenv("S3_ACCESS_KEY_ID") - if len(s3AccessKeyID) == 0 { + if s3AccessKeyID == "" { log.Fatal("Please set S3_ACCESS_KEY_ID") } s3SecretAccessKey := os.Getenv("S3_SECRET_ACCESS_KEY") - if len(s3SecretAccessKey) == 0 { + if s3SecretAccessKey == "" { log.Fatal("Please set S3_SECRET_ACCESS_KEY") } diff --git a/s3-client-mock.go b/s3-client-mock.go index c3626fd..3ffbf5c 100644 --- a/s3-client-mock.go +++ b/s3-client-mock.go @@ -9,18 +9,21 @@ import ( // S3ClientMock is a mocked S3 client type S3ClientMock struct { - Buckets []minio.BucketInfo - ObjectInfos []minio.ObjectInfo - Objects []minio.Object - Err error + Buckets []minio.BucketInfo + Objects []minio.ObjectInfo + Err error } func (s S3ClientMock) CopyObject(string, string, string, minio.CopyConditions) error { return s.Err } -func (s S3ClientMock) GetObject(string, string) (*minio.Object, error) { - return &s.Objects[0], s.Err +func (s S3ClientMock) GetObject(bucketName string, objectName string) (*minio.Object, error) { + if s.Err != nil { + return nil, s.Err + } + + return &minio.Object{}, nil } func (s S3ClientMock) ListBuckets() ([]minio.BucketInfo, error) { @@ -30,7 +33,7 @@ func (s S3ClientMock) ListBuckets() ([]minio.BucketInfo, error) { func (s S3ClientMock) ListObjectsV2(bucketName string, p string, r bool, d <-chan struct{}) <-chan minio.ObjectInfo { // Add error if exists if s.Err != nil { - s.ObjectInfos = append(s.ObjectInfos, minio.ObjectInfo{ + s.Objects = append(s.Objects, minio.ObjectInfo{ Err: s.Err, }) } @@ -40,19 +43,20 @@ func (s S3ClientMock) ListObjectsV2(bucketName string, p string, r bool, d <-cha for _, b := range s.Buckets { if b.Name == bucketName { found = true + break } } if !found { - s.ObjectInfos = append(s.ObjectInfos, minio.ObjectInfo{ + s.Objects = append(s.Objects, minio.ObjectInfo{ Err: errors.New("The specified bucket does not exist."), }) } - objCh := make(chan minio.ObjectInfo, len(s.ObjectInfos)) + objCh := make(chan minio.ObjectInfo, len(s.Objects)) defer close(objCh) - for _, obj := range s.ObjectInfos { + for _, obj := range s.Objects { objCh <- obj }