Use standard error messages

This commit is contained in:
Lena Fuhrimann 2017-04-09 16:28:57 +02:00
parent 9c697a99f5
commit 39521e331d
15 changed files with 87 additions and 105 deletions

View file

@ -32,8 +32,7 @@ func BucketViewHandler(s3 S3Client) http.Handler {
t, err := template.ParseFiles(l, p) t, err := template.ParseFiles(l, p)
if err != nil { if err != nil {
msg := "error parsing templates" handleHTTPError(w, http.StatusInternalServerError, err)
handleHTTPError(w, msg, err, http.StatusInternalServerError)
return return
} }
@ -42,14 +41,12 @@ func BucketViewHandler(s3 S3Client) http.Handler {
objectCh := s3.ListObjectsV2(bucketName, "", true, doneCh) objectCh := s3.ListObjectsV2(bucketName, "", true, doneCh)
for object := range objectCh { for object := range objectCh {
if object.Err != nil { if object.Err != nil {
msg := "error listing objects"
code := http.StatusInternalServerError code := http.StatusInternalServerError
if object.Err.Error() == "The specified bucket does not exist." { if object.Err.Error() == ErrBucketDoesNotExist {
msg = "bucket not found"
code = http.StatusNotFound code = http.StatusNotFound
} }
handleHTTPError(w, msg, object.Err, code) handleHTTPError(w, code, object.Err)
return return
} }
objectWithIcon := ObjectWithIcon{object, icon(object.Key)} objectWithIcon := ObjectWithIcon{object, icon(object.Key)}
@ -63,8 +60,7 @@ func BucketViewHandler(s3 S3Client) http.Handler {
err = t.ExecuteTemplate(w, "layout", bucketPage) err = t.ExecuteTemplate(w, "layout", bucketPage)
if err != nil { if err != nil {
msg := "error executing template" handleHTTPError(w, http.StatusInternalServerError, err)
handleHTTPError(w, msg, err, http.StatusInternalServerError)
return return
} }
}) })

View file

@ -88,7 +88,7 @@ func TestBucketViewHandler(t *testing.T) {
s3: &S3ClientMock{}, s3: &S3ClientMock{},
bucketName: "testBucket", bucketName: "testBucket",
expectedStatusCode: http.StatusNotFound, expectedStatusCode: http.StatusNotFound,
expectedBodyCountains: "bucket not found\n", expectedBodyCountains: http.StatusText(http.StatusNotFound),
}, },
"s3 error": { "s3 error": {
s3: &S3ClientMock{ s3: &S3ClientMock{
@ -96,7 +96,7 @@ func TestBucketViewHandler(t *testing.T) {
}, },
bucketName: "testBucket", bucketName: "testBucket",
expectedStatusCode: http.StatusInternalServerError, expectedStatusCode: http.StatusInternalServerError,
expectedBodyCountains: "error listing objects\n", expectedBodyCountains: http.StatusText(http.StatusInternalServerError),
}, },
} }

View file

@ -14,22 +14,19 @@ func BucketsViewHandler(s3 S3Client) http.Handler {
t, err := template.ParseFiles(l, p) t, err := template.ParseFiles(l, p)
if err != nil { if err != nil {
msg := "error parsing templates" handleHTTPError(w, http.StatusInternalServerError, err)
handleHTTPError(w, msg, err, http.StatusInternalServerError)
return return
} }
buckets, err := s3.ListBuckets() buckets, err := s3.ListBuckets()
if err != nil { if err != nil {
msg := "error listing buckets" handleHTTPError(w, http.StatusInternalServerError, err)
handleHTTPError(w, msg, err, http.StatusInternalServerError)
return return
} }
err = t.ExecuteTemplate(w, "layout", buckets) err = t.ExecuteTemplate(w, "layout", buckets)
if err != nil { if err != nil {
msg := "error executing template" handleHTTPError(w, http.StatusInternalServerError, err)
handleHTTPError(w, msg, err, http.StatusInternalServerError)
return return
} }
}) })

View file

@ -37,7 +37,7 @@ func TestBucketsViewHandler(t *testing.T) {
Err: errors.New("mocked S3 error"), Err: errors.New("mocked S3 error"),
}, },
expectedStatusCode: http.StatusInternalServerError, expectedStatusCode: http.StatusInternalServerError,
expectedBodyContains: "error listing buckets\n", expectedBodyContains: http.StatusText(http.StatusInternalServerError),
}, },
} }

View file

@ -14,15 +14,13 @@ func CreateBucketHandler(s3 S3Client) http.Handler {
err := json.NewDecoder(r.Body).Decode(&bucket) err := json.NewDecoder(r.Body).Decode(&bucket)
if err != nil { if err != nil {
msg := "error decoding json" handleHTTPError(w, http.StatusUnprocessableEntity, err)
handleHTTPError(w, msg, err, http.StatusUnprocessableEntity)
return return
} }
err = s3.MakeBucket(bucket.Name, "") err = s3.MakeBucket(bucket.Name, "")
if err != nil { if err != nil {
msg := "error making bucket" handleHTTPError(w, http.StatusInternalServerError, err)
handleHTTPError(w, msg, err, http.StatusInternalServerError)
return return
} }
@ -31,8 +29,7 @@ func CreateBucketHandler(s3 S3Client) http.Handler {
err = json.NewEncoder(w).Encode(bucket) err = json.NewEncoder(w).Encode(bucket)
if err != nil { if err != nil {
msg := "error encoding json" handleHTTPError(w, http.StatusInternalServerError, err)
handleHTTPError(w, msg, err, http.StatusInternalServerError)
return return
} }
}) })

View file

@ -14,36 +14,36 @@ func TestCreateBucketHandler(t *testing.T) {
assert := assert.New(t) assert := assert.New(t)
tests := map[string]struct { tests := map[string]struct {
s3 S3Client s3 S3Client
body string body string
expectedStatusCode int expectedStatusCode int
expectedBody string expectedBodyContains string
}{ }{
"success": { "success": {
s3: &S3ClientMock{}, s3: &S3ClientMock{},
body: "{\"name\":\"myBucket\"}", body: "{\"name\":\"myBucket\"}",
expectedStatusCode: http.StatusCreated, expectedStatusCode: http.StatusCreated,
expectedBody: "{\"name\":\"myBucket\",\"creationDate\":\"0001-01-01T00:00:00Z\"}\n", expectedBodyContains: "{\"name\":\"myBucket\",\"creationDate\":\"0001-01-01T00:00:00Z\"}\n",
}, },
"empty request": { "empty request": {
s3: &S3ClientMock{}, s3: &S3ClientMock{},
body: "", body: "",
expectedStatusCode: http.StatusUnprocessableEntity, expectedStatusCode: http.StatusUnprocessableEntity,
expectedBody: "error decoding json\n", expectedBodyContains: http.StatusText(http.StatusUnprocessableEntity),
}, },
"malformed request": { "malformed request": {
s3: &S3ClientMock{}, s3: &S3ClientMock{},
body: "}", body: "}",
expectedStatusCode: http.StatusUnprocessableEntity, expectedStatusCode: http.StatusUnprocessableEntity,
expectedBody: "error decoding json\n", expectedBodyContains: http.StatusText(http.StatusUnprocessableEntity),
}, },
"s3 error": { "s3 error": {
s3: &S3ClientMock{ s3: &S3ClientMock{
Err: errors.New("mocked S3 error"), Err: errors.New("mocked S3 error"),
}, },
body: "{\"name\":\"myBucket\"}", body: "{\"name\":\"myBucket\"}",
expectedStatusCode: http.StatusInternalServerError, expectedStatusCode: http.StatusInternalServerError,
expectedBody: "error making bucket\n", expectedBodyContains: http.StatusText(http.StatusInternalServerError),
}, },
} }
@ -57,6 +57,6 @@ func TestCreateBucketHandler(t *testing.T) {
handler.ServeHTTP(rr, req) handler.ServeHTTP(rr, req)
assert.Equal(tc.expectedStatusCode, rr.Code, tcID) assert.Equal(tc.expectedStatusCode, rr.Code, tcID)
assert.Equal(tc.expectedBody, rr.Body.String(), tcID) assert.Contains(rr.Body.String(), tc.expectedBodyContains, tcID)
} }
} }

View file

@ -28,8 +28,7 @@ func CreateObjectHandler(s3 S3Client) http.Handler {
err := json.NewDecoder(r.Body).Decode(&copy) err := json.NewDecoder(r.Body).Decode(&copy)
if err != nil { if err != nil {
msg := "error decoding json" handleHTTPError(w, http.StatusInternalServerError, err)
handleHTTPError(w, msg, err, http.StatusUnprocessableEntity)
return return
} }
@ -37,8 +36,7 @@ func CreateObjectHandler(s3 S3Client) http.Handler {
objectSource := fmt.Sprintf("/%s/%s", copy.SourceBucketName, copy.SourceObjectName) objectSource := fmt.Sprintf("/%s/%s", copy.SourceBucketName, copy.SourceObjectName)
err = s3.CopyObject(copy.BucketName, copy.ObjectName, objectSource, copyConds) err = s3.CopyObject(copy.BucketName, copy.ObjectName, objectSource, copyConds)
if err != nil { if err != nil {
msg := "error copying object" handleHTTPError(w, http.StatusInternalServerError, err)
handleHTTPError(w, msg, err, http.StatusInternalServerError)
return return
} }
@ -47,30 +45,26 @@ func CreateObjectHandler(s3 S3Client) http.Handler {
err = json.NewEncoder(w).Encode(copy) err = json.NewEncoder(w).Encode(copy)
if err != nil { if err != nil {
msg := "error encoding json" handleHTTPError(w, http.StatusInternalServerError, err)
handleHTTPError(w, msg, err, http.StatusInternalServerError)
return return
} }
} else { } else {
err := r.ParseMultipartForm(32 << 20) err := r.ParseMultipartForm(32 << 20)
if err != nil { if err != nil {
msg := "error parsing form" handleHTTPError(w, http.StatusUnprocessableEntity, err)
handleHTTPError(w, msg, err, http.StatusUnprocessableEntity)
return return
} }
file, handler, err := r.FormFile("file") file, handler, err := r.FormFile("file")
if err != nil { if err != nil {
msg := "error getting form file" handleHTTPError(w, http.StatusInternalServerError, err)
handleHTTPError(w, msg, err, http.StatusInternalServerError)
return return
} }
defer file.Close() defer file.Close()
_, err = s3.PutObject(vars["bucketName"], handler.Filename, file, contentTypeOctetStream) _, err = s3.PutObject(vars["bucketName"], handler.Filename, file, contentTypeOctetStream)
if err != nil { if err != nil {
msg := "error putting object" handleHTTPError(w, http.StatusInternalServerError, err)
handleHTTPError(w, msg, err, http.StatusInternalServerError)
return return
} }

View file

@ -13,8 +13,7 @@ func DeleteBucketHandler(s3 S3Client) http.Handler {
err := s3.RemoveBucket(vars["bucketName"]) err := s3.RemoveBucket(vars["bucketName"])
if err != nil { if err != nil {
msg := "error removing bucket" handleHTTPError(w, http.StatusInternalServerError, err)
handleHTTPError(w, msg, err, http.StatusInternalServerError)
return return
} }

View file

@ -13,21 +13,21 @@ func TestDeleteBucketHandler(t *testing.T) {
assert := assert.New(t) assert := assert.New(t)
tests := map[string]struct { tests := map[string]struct {
s3 S3Client s3 S3Client
expectedStatusCode int expectedStatusCode int
expectedBody string expectedBodyContains string
}{ }{
"success": { "success": {
s3: &S3ClientMock{}, s3: &S3ClientMock{},
expectedStatusCode: http.StatusNoContent, expectedStatusCode: http.StatusNoContent,
expectedBody: "", expectedBodyContains: "",
}, },
"s3 error": { "s3 error": {
s3: &S3ClientMock{ s3: &S3ClientMock{
Err: errors.New("mocked S3 error"), Err: errors.New("mocked S3 error"),
}, },
expectedStatusCode: http.StatusInternalServerError, expectedStatusCode: http.StatusInternalServerError,
expectedBody: "error removing bucket\n", expectedBodyContains: http.StatusText(http.StatusInternalServerError),
}, },
} }
@ -41,6 +41,6 @@ func TestDeleteBucketHandler(t *testing.T) {
handler.ServeHTTP(rr, req) handler.ServeHTTP(rr, req)
assert.Equal(tc.expectedStatusCode, rr.Code, tcID) assert.Equal(tc.expectedStatusCode, rr.Code, tcID)
assert.Equal(tc.expectedBody, rr.Body.String(), tcID) assert.Contains(rr.Body.String(), tc.expectedBodyContains, tcID)
} }
} }

View file

@ -13,8 +13,7 @@ func DeleteObjectHandler(s3 S3Client) http.Handler {
err := s3.RemoveObject(vars["bucketName"], vars["objectName"]) err := s3.RemoveObject(vars["bucketName"], vars["objectName"])
if err != nil { if err != nil {
msg := "error removing object" handleHTTPError(w, http.StatusInternalServerError, err)
handleHTTPError(w, msg, err, http.StatusInternalServerError)
return return
} }

View file

@ -13,21 +13,21 @@ func TestDeleteObjectHandler(t *testing.T) {
assert := assert.New(t) assert := assert.New(t)
tests := map[string]struct { tests := map[string]struct {
s3 S3Client s3 S3Client
expectedStatusCode int expectedStatusCode int
expectedBody string expectedBodyContains string
}{ }{
"success": { "success": {
s3: &S3ClientMock{}, s3: &S3ClientMock{},
expectedStatusCode: http.StatusNoContent, expectedStatusCode: http.StatusNoContent,
expectedBody: "", expectedBodyContains: "",
}, },
"s3 error": { "s3 error": {
s3: &S3ClientMock{ s3: &S3ClientMock{
Err: errors.New("mocked S3 error"), Err: errors.New("mocked S3 error"),
}, },
expectedStatusCode: http.StatusInternalServerError, expectedStatusCode: http.StatusInternalServerError,
expectedBody: "error removing object\n", expectedBodyContains: http.StatusText(http.StatusInternalServerError),
}, },
} }
@ -41,6 +41,6 @@ func TestDeleteObjectHandler(t *testing.T) {
handler.ServeHTTP(rr, req) handler.ServeHTTP(rr, req)
assert.Equal(tc.expectedStatusCode, rr.Code, tcID) assert.Equal(tc.expectedStatusCode, rr.Code, tcID)
assert.Equal(tc.expectedBody, rr.Body.String(), tcID) assert.Contains(rr.Body.String(), tc.expectedBodyContains, tcID)
} }
} }

24
errors.go Normal file
View file

@ -0,0 +1,24 @@
package main
import (
"log"
"net/http"
)
// Common error messages within the app
const (
ErrBucketDoesNotExist = "The specified bucket does not exist."
ErrKeyDoesNotExist = "The specified key does not exist."
)
// handleHTTPError handles HTTP errors
func handleHTTPError(w http.ResponseWriter, statusCode int, err error) {
msg := http.StatusText(statusCode)
http.Error(w, msg, statusCode)
logMsg := msg
if err != nil {
logMsg = logMsg + ": " + err.Error()
}
log.Println(logMsg)
}

View file

@ -16,8 +16,7 @@ func GetObjectHandler(s3 S3Client) http.Handler {
object, err := s3.GetObject(vars["bucketName"], objectName) object, err := s3.GetObject(vars["bucketName"], objectName)
if err != nil { if err != nil {
msg := "error getting object" handleHTTPError(w, http.StatusInternalServerError, err)
handleHTTPError(w, msg, err, http.StatusInternalServerError)
return return
} }
@ -26,18 +25,11 @@ func GetObjectHandler(s3 S3Client) http.Handler {
_, err = io.Copy(w, object) _, err = io.Copy(w, object)
if err != nil { if err != nil {
msg := "error copying object"
code := http.StatusInternalServerError code := http.StatusInternalServerError
if err.Error() == "The specified key does not exist." { if err.Error() == ErrBucketDoesNotExist || err.Error() == ErrKeyDoesNotExist {
msg = "object not found"
code = http.StatusNotFound code = http.StatusNotFound
} }
if err.Error() == "The specified bucket does not exist." { handleHTTPError(w, code, err)
msg = "bucket not found"
code = http.StatusNotFound
}
handleHTTPError(w, msg, err, code)
return return
} }
}) })

View file

@ -29,7 +29,7 @@ func TestGetObjectHandler(t *testing.T) {
bucketName: "testBucket", bucketName: "testBucket",
objectName: "testObject", objectName: "testObject",
expectedStatusCode: http.StatusInternalServerError, expectedStatusCode: http.StatusInternalServerError,
expectedBodyCountains: "error getting object\n", expectedBodyCountains: http.StatusText(http.StatusInternalServerError),
}, },
} }

View file

@ -1,16 +0,0 @@
package main
import (
"log"
"net/http"
)
// handleHTTPError handles HTTP errors
func handleHTTPError(w http.ResponseWriter, msg string, err error, statusCode int) {
http.Error(w, msg, statusCode)
if err != nil {
log.Println(msg+":", err.Error())
} else {
log.Println(msg)
}
}