2016-08-10 02:04:28 +00:00
|
|
|
package errors
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"encoding/json"
|
|
|
|
|
"errors"
|
|
|
|
|
"net/http"
|
|
|
|
|
"net/http/httptest"
|
|
|
|
|
"sort"
|
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
|
|
"github.com/gin-gonic/gin"
|
|
|
|
|
"github.com/jinzhu/gorm"
|
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
|
"gopkg.in/go-playground/validator.v8"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func TestNew(t *testing.T) {
|
|
|
|
|
kolideErr := New("Public message", "Private message")
|
|
|
|
|
|
|
|
|
|
expect := &KolideError{
|
|
|
|
|
Err: nil,
|
|
|
|
|
StatusCode: http.StatusInternalServerError,
|
|
|
|
|
PublicMessage: "Public message",
|
|
|
|
|
PrivateMessage: "Private message",
|
|
|
|
|
}
|
|
|
|
|
assert.Equal(t, expect, kolideErr)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestNewWithStatus(t *testing.T) {
|
|
|
|
|
kolideErr := NewWithStatus(http.StatusUnauthorized, "Public message", "Private message")
|
|
|
|
|
|
|
|
|
|
expect := &KolideError{
|
|
|
|
|
Err: nil,
|
|
|
|
|
StatusCode: http.StatusUnauthorized,
|
|
|
|
|
PublicMessage: "Public message",
|
|
|
|
|
PrivateMessage: "Private message",
|
|
|
|
|
}
|
|
|
|
|
assert.Equal(t, expect, kolideErr)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestNewFromError(t *testing.T) {
|
|
|
|
|
err := errors.New("Foo error")
|
|
|
|
|
kolideErr := NewFromError(err, StatusUnprocessableEntity, "Public error")
|
|
|
|
|
|
2016-09-29 04:21:39 +00:00
|
|
|
assert.Equal(t, "Public error", kolideErr.Error())
|
2016-08-10 02:04:28 +00:00
|
|
|
|
|
|
|
|
expect := &KolideError{
|
|
|
|
|
Err: err,
|
|
|
|
|
StatusCode: StatusUnprocessableEntity,
|
|
|
|
|
PublicMessage: "Public error",
|
|
|
|
|
PrivateMessage: "Foo error",
|
|
|
|
|
}
|
|
|
|
|
assert.Equal(t, expect, kolideErr)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestDatabaseError(t *testing.T) {
|
|
|
|
|
err := errors.New("Foo error")
|
|
|
|
|
kolideErr := DatabaseError(err)
|
|
|
|
|
|
|
|
|
|
expect := &KolideError{
|
|
|
|
|
Err: err,
|
|
|
|
|
StatusCode: http.StatusInternalServerError,
|
|
|
|
|
PublicMessage: "Database error",
|
|
|
|
|
PrivateMessage: "Foo error",
|
|
|
|
|
}
|
|
|
|
|
assert.Equal(t, expect, kolideErr)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestReturnErrorUnspecified(t *testing.T) {
|
|
|
|
|
r := gin.New()
|
|
|
|
|
r.POST("/foo", func(c *gin.Context) {
|
|
|
|
|
ReturnError(c, errors.New("foo"))
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
req, _ := http.NewRequest("POST", "/foo", nil)
|
|
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
|
|
|
|
|
|
r.ServeHTTP(resp, req)
|
2016-09-14 18:40:51 +00:00
|
|
|
assert.Equal(t, http.StatusInternalServerError, resp.Code)
|
2016-08-10 02:04:28 +00:00
|
|
|
|
|
|
|
|
expect := `{"message": "Unspecified error"}`
|
|
|
|
|
assert.JSONEq(t, expect, resp.Body.String())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestReturnErrorKolideError(t *testing.T) {
|
|
|
|
|
r := gin.New()
|
|
|
|
|
r.POST("/foo", func(c *gin.Context) {
|
|
|
|
|
ReturnError(c, &KolideError{
|
|
|
|
|
StatusCode: http.StatusUnauthorized,
|
|
|
|
|
PublicMessage: "Some error",
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
req, _ := http.NewRequest("POST", "/foo", nil)
|
|
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
|
|
|
|
|
|
r.ServeHTTP(resp, req)
|
2016-09-14 18:40:51 +00:00
|
|
|
assert.Equal(t, http.StatusUnauthorized, resp.Code)
|
2016-08-10 02:04:28 +00:00
|
|
|
|
|
|
|
|
expect := `{"message": "Some error"}`
|
|
|
|
|
assert.JSONEq(t, expect, resp.Body.String())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// These types and functions for performing an unordered comparison on a
|
|
|
|
|
// []map[string]string] as parsed from the error JSON
|
|
|
|
|
type errorField map[string]string
|
|
|
|
|
type errorFields []errorField
|
|
|
|
|
|
|
|
|
|
func (e errorFields) Len() int {
|
|
|
|
|
return len(e)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (e errorFields) Less(i, j int) bool {
|
|
|
|
|
return e[i]["field"] <= e[j]["field"] &&
|
|
|
|
|
e[i]["code"] <= e[j]["code"] &&
|
|
|
|
|
e[i]["message"] <= e[j]["message"]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (e errorFields) Swap(i, j int) {
|
|
|
|
|
e[i], e[j] = e[j], e[i]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestReturnErrorValidationError(t *testing.T) {
|
|
|
|
|
r := gin.New()
|
|
|
|
|
|
|
|
|
|
type Foo struct {
|
|
|
|
|
Email string `json:"email_foo" validate:"required,email"`
|
|
|
|
|
Password string `json:"password" validate:"required"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
validate := validator.New(&validator.Config{TagName: "validate", FieldNameTag: "json"})
|
|
|
|
|
|
|
|
|
|
r.POST("/foo", func(c *gin.Context) {
|
|
|
|
|
ReturnError(c, validate.Struct(&Foo{Email: "foo", Password: ""}))
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
req, _ := http.NewRequest("POST", "/foo", nil)
|
|
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
|
|
|
|
|
|
r.ServeHTTP(resp, req)
|
2016-09-14 18:40:51 +00:00
|
|
|
assert.Equal(t, StatusUnprocessableEntity, resp.Code)
|
2016-08-10 02:04:28 +00:00
|
|
|
|
|
|
|
|
var bodyJson map[string]interface{}
|
2016-09-14 18:40:51 +00:00
|
|
|
err := json.Unmarshal(resp.Body.Bytes(), &bodyJson)
|
|
|
|
|
assert.Nil(t, err)
|
2016-08-10 02:04:28 +00:00
|
|
|
assert.Equal(t, "Validation error", bodyJson["message"])
|
|
|
|
|
|
|
|
|
|
fields, ok := bodyJson["errors"].([]interface{})
|
2016-09-14 18:40:51 +00:00
|
|
|
assert.True(t, ok)
|
2016-08-10 02:04:28 +00:00
|
|
|
|
|
|
|
|
// The error fields must be copied from []interface{} to
|
|
|
|
|
// []map[string][string] before we can sort
|
|
|
|
|
compFields := make(errorFields, 0, 0)
|
|
|
|
|
for _, field := range fields {
|
|
|
|
|
field := field.(map[string]interface{})
|
|
|
|
|
compFields = append(
|
|
|
|
|
compFields,
|
|
|
|
|
errorField{
|
|
|
|
|
"code": field["code"].(string),
|
|
|
|
|
"field": field["field"].(string),
|
|
|
|
|
"message": field["message"].(string),
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
expect := errorFields{
|
|
|
|
|
{"code": "invalid", "field": "email_foo", "message": "email"},
|
|
|
|
|
{"code": "invalid", "field": "password", "message": "required"},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Sort to standardize ordering before comparison
|
|
|
|
|
sort.Sort(compFields)
|
|
|
|
|
sort.Sort(expect)
|
|
|
|
|
|
|
|
|
|
assert.Equal(t, expect, compFields)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestReturnErrorGormError(t *testing.T) {
|
|
|
|
|
r := gin.New()
|
|
|
|
|
|
|
|
|
|
r.POST("/foo", func(c *gin.Context) {
|
|
|
|
|
err := gorm.Errors{}
|
|
|
|
|
err.Add(gorm.ErrInvalidSQL)
|
|
|
|
|
ReturnError(c, err)
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
req, _ := http.NewRequest("POST", "/foo", nil)
|
|
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
|
|
|
|
|
|
r.ServeHTTP(resp, req)
|
2016-09-14 18:40:51 +00:00
|
|
|
assert.Equal(t, http.StatusInternalServerError, resp.Code)
|
2016-08-10 02:04:28 +00:00
|
|
|
|
|
|
|
|
assert.JSONEq(t, `{"message": "Database error"}`, resp.Body.String())
|
|
|
|
|
}
|