2015-05-15 01:21:39 +00:00
|
|
|
package errcode
|
2014-12-10 05:25:54 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
2015-05-27 01:16:45 +00:00
|
|
|
"net/http"
|
|
|
|
"reflect"
|
2015-08-21 00:36:24 +00:00
|
|
|
"strings"
|
2014-12-10 05:25:54 +00:00
|
|
|
"testing"
|
|
|
|
)
|
|
|
|
|
2015-08-21 00:36:24 +00:00
|
|
|
// TestErrorsManagement does a quick check of the Errors type to ensure that
|
|
|
|
// members are properly pushed and marshaled.
|
2023-09-04 15:54:48 +00:00
|
|
|
var ErrorCodeTest1 = register("test.errors", ErrorDescriptor{
|
2015-08-21 00:36:24 +00:00
|
|
|
Value: "TEST1",
|
|
|
|
Message: "test error 1",
|
|
|
|
Description: `Just a test message #1.`,
|
|
|
|
HTTPStatusCode: http.StatusInternalServerError,
|
|
|
|
})
|
|
|
|
|
2023-09-04 15:54:48 +00:00
|
|
|
var ErrorCodeTest2 = register("test.errors", ErrorDescriptor{
|
2015-08-21 00:36:24 +00:00
|
|
|
Value: "TEST2",
|
|
|
|
Message: "test error 2",
|
|
|
|
Description: `Just a test message #2.`,
|
|
|
|
HTTPStatusCode: http.StatusNotFound,
|
|
|
|
})
|
|
|
|
|
2023-09-04 15:54:48 +00:00
|
|
|
var ErrorCodeTest3 = register("test.errors", ErrorDescriptor{
|
2015-08-21 00:36:24 +00:00
|
|
|
Value: "TEST3",
|
|
|
|
Message: "Sorry %q isn't valid",
|
|
|
|
Description: `Just a test message #3.`,
|
|
|
|
HTTPStatusCode: http.StatusNotFound,
|
|
|
|
})
|
|
|
|
|
2014-12-10 05:25:54 +00:00
|
|
|
// TestErrorCodes ensures that error code format, mappings and
|
|
|
|
// marshaling/unmarshaling. round trips are stable.
|
|
|
|
func TestErrorCodes(t *testing.T) {
|
2023-04-30 13:23:44 +00:00
|
|
|
t.Parallel()
|
2015-05-27 01:16:45 +00:00
|
|
|
if len(errorCodeToDescriptors) == 0 {
|
|
|
|
t.Fatal("errors aren't loaded!")
|
|
|
|
}
|
|
|
|
|
reference, registry: fix loop variable captured by func literal (govet)
reference/normalize_test.go:274:40: loopclosure: loop variable r captured by func literal (govet)
named, err := ParseNormalizedNamed(r)
^
reference/normalize_test.go:276:29: loopclosure: loop variable r captured by func literal (govet)
t.Fatalf("ref=%s: %v", r, err)
^
registry/api/errcode/errors_test.go:45:7: loopclosure: loop variable ec captured by func literal (govet)
if ec != desc.Code {
^
registry/api/errcode/errors_test.go:46:66: loopclosure: loop variable ec captured by func literal (govet)
t.Fatalf("error code in descriptor isn't correct, %q != %q", ec, desc.Code)
^
registry/api/errcode/errors_test.go:49:23: loopclosure: loop variable desc captured by func literal (govet)
if idToDescriptors[desc.Value].Code != ec {
^
registry/api/errcode/errors_test.go:50:80: loopclosure: loop variable desc captured by func literal (govet)
t.Fatalf("error code in idToDesc isn't correct, %q != %q", idToDescriptors[desc.Value].Code, ec)
^
registry/api/errcode/errors_test.go:53:7: loopclosure: loop variable ec captured by func literal (govet)
if ec.Message() != desc.Message {
^
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2023-05-09 13:29:12 +00:00
|
|
|
for ec := range errorCodeToDescriptors {
|
|
|
|
ec := ec
|
2023-04-30 13:23:44 +00:00
|
|
|
t.Run(ec.String(), func(t *testing.T) {
|
|
|
|
t.Parallel()
|
reference, registry: fix loop variable captured by func literal (govet)
reference/normalize_test.go:274:40: loopclosure: loop variable r captured by func literal (govet)
named, err := ParseNormalizedNamed(r)
^
reference/normalize_test.go:276:29: loopclosure: loop variable r captured by func literal (govet)
t.Fatalf("ref=%s: %v", r, err)
^
registry/api/errcode/errors_test.go:45:7: loopclosure: loop variable ec captured by func literal (govet)
if ec != desc.Code {
^
registry/api/errcode/errors_test.go:46:66: loopclosure: loop variable ec captured by func literal (govet)
t.Fatalf("error code in descriptor isn't correct, %q != %q", ec, desc.Code)
^
registry/api/errcode/errors_test.go:49:23: loopclosure: loop variable desc captured by func literal (govet)
if idToDescriptors[desc.Value].Code != ec {
^
registry/api/errcode/errors_test.go:50:80: loopclosure: loop variable desc captured by func literal (govet)
t.Fatalf("error code in idToDesc isn't correct, %q != %q", idToDescriptors[desc.Value].Code, ec)
^
registry/api/errcode/errors_test.go:53:7: loopclosure: loop variable ec captured by func literal (govet)
if ec.Message() != desc.Message {
^
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2023-05-09 13:29:12 +00:00
|
|
|
desc := errorCodeToDescriptors[ec]
|
2023-04-30 13:23:44 +00:00
|
|
|
if ec != desc.Code {
|
|
|
|
t.Fatalf("error code in descriptor isn't correct, %q != %q", ec, desc.Code)
|
|
|
|
}
|
|
|
|
|
|
|
|
if idToDescriptors[desc.Value].Code != ec {
|
|
|
|
t.Fatalf("error code in idToDesc isn't correct, %q != %q", idToDescriptors[desc.Value].Code, ec)
|
|
|
|
}
|
|
|
|
|
|
|
|
if ec.Message() != desc.Message {
|
|
|
|
t.Fatalf("ec.Message doesn't match desc.Message: %q != %q", ec.Message(), desc.Message)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Test (de)serializing the ErrorCode
|
|
|
|
p, err := json.Marshal(ec)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("couldn't marshal ec %v: %v", ec, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(p) <= 0 {
|
|
|
|
t.Fatalf("expected content in marshaled before for error code %v", ec)
|
|
|
|
}
|
|
|
|
|
|
|
|
// First, unmarshal to interface and ensure we have a string.
|
|
|
|
var ecUnspecified interface{}
|
|
|
|
if err := json.Unmarshal(p, &ecUnspecified); err != nil {
|
|
|
|
t.Fatalf("error unmarshaling error code %v: %v", ec, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if _, ok := ecUnspecified.(string); !ok {
|
|
|
|
t.Fatalf("expected a string for error code %v on unmarshal got a %T", ec, ecUnspecified)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now, unmarshal with the error code type and ensure they are equal
|
|
|
|
var ecUnmarshaled ErrorCode
|
|
|
|
if err := json.Unmarshal(p, &ecUnmarshaled); err != nil {
|
|
|
|
t.Fatalf("error unmarshaling error code %v: %v", ec, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if ecUnmarshaled != ec {
|
|
|
|
t.Fatalf("unexpected error code during error code marshal/unmarshal: %v != %v", ecUnmarshaled, ec)
|
|
|
|
}
|
|
|
|
|
|
|
|
expectedErrorString := strings.ToLower(strings.Replace(ec.Descriptor().Value, "_", " ", -1))
|
|
|
|
if ec.Error() != expectedErrorString {
|
|
|
|
t.Fatalf("unexpected return from %v.Error(): %q != %q", ec, ec.Error(), expectedErrorString)
|
|
|
|
}
|
|
|
|
})
|
2014-12-10 05:25:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestErrorsManagement(t *testing.T) {
|
|
|
|
var errs Errors
|
|
|
|
|
2015-06-03 13:52:39 +00:00
|
|
|
errs = append(errs, ErrorCodeTest1)
|
|
|
|
errs = append(errs, ErrorCodeTest2.WithDetail(
|
2015-05-27 01:16:45 +00:00
|
|
|
map[string]interface{}{"digest": "sometestblobsumdoesntmatter"}))
|
2015-06-18 00:39:27 +00:00
|
|
|
errs = append(errs, ErrorCodeTest3.WithArgs("BOOGIE"))
|
|
|
|
errs = append(errs, ErrorCodeTest3.WithArgs("BOOGIE").WithDetail("data"))
|
2014-12-10 05:25:54 +00:00
|
|
|
|
|
|
|
p, err := json.Marshal(errs)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("error marashaling errors: %v", err)
|
|
|
|
}
|
|
|
|
|
2015-06-18 00:39:27 +00:00
|
|
|
expectedJSON := `{"errors":[` +
|
|
|
|
`{"code":"TEST1","message":"test error 1"},` +
|
|
|
|
`{"code":"TEST2","message":"test error 2","detail":{"digest":"sometestblobsumdoesntmatter"}},` +
|
|
|
|
`{"code":"TEST3","message":"Sorry \"BOOGIE\" isn't valid"},` +
|
|
|
|
`{"code":"TEST3","message":"Sorry \"BOOGIE\" isn't valid","detail":"data"}` +
|
|
|
|
`]}`
|
2014-12-10 05:25:54 +00:00
|
|
|
|
|
|
|
if string(p) != expectedJSON {
|
2015-06-03 13:52:39 +00:00
|
|
|
t.Fatalf("unexpected json:\ngot:\n%q\n\nexpected:\n%q", string(p), expectedJSON)
|
2014-12-10 05:25:54 +00:00
|
|
|
}
|
|
|
|
|
2015-05-27 01:16:45 +00:00
|
|
|
// Now test the reverse
|
|
|
|
var unmarshaled Errors
|
|
|
|
if err := json.Unmarshal(p, &unmarshaled); err != nil {
|
|
|
|
t.Fatalf("unexpected error unmarshaling error envelope: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if !reflect.DeepEqual(unmarshaled, errs) {
|
|
|
|
t.Fatalf("errors not equal after round trip:\nunmarshaled:\n%#v\n\nerrs:\n%#v", unmarshaled, errs)
|
|
|
|
}
|
|
|
|
|
2015-06-18 00:39:27 +00:00
|
|
|
// Test the arg substitution stuff
|
|
|
|
e1 := unmarshaled[3].(Error)
|
|
|
|
exp1 := `Sorry "BOOGIE" isn't valid`
|
|
|
|
if e1.Message != exp1 {
|
|
|
|
t.Fatalf("Wrong msg, got:\n%q\n\nexpected:\n%q", e1.Message, exp1)
|
|
|
|
}
|
|
|
|
|
2015-07-22 17:18:36 +00:00
|
|
|
exp1 = "test3: " + exp1
|
|
|
|
if e1.Error() != exp1 {
|
|
|
|
t.Fatalf("Error() didn't return the right string, got:%s\nexpected:%s", e1.Error(), exp1)
|
|
|
|
}
|
|
|
|
|
2015-05-27 01:16:45 +00:00
|
|
|
// Test again with a single value this time
|
2015-06-03 13:52:39 +00:00
|
|
|
errs = Errors{ErrorCodeUnknown}
|
2015-06-19 01:00:26 +00:00
|
|
|
expectedJSON = "{\"errors\":[{\"code\":\"UNKNOWN\",\"message\":\"unknown error\"}]}"
|
2014-12-10 05:25:54 +00:00
|
|
|
p, err = json.Marshal(errs)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("error marashaling errors: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if string(p) != expectedJSON {
|
|
|
|
t.Fatalf("unexpected json: %q != %q", string(p), expectedJSON)
|
|
|
|
}
|
|
|
|
|
2015-05-27 01:16:45 +00:00
|
|
|
// Now test the reverse
|
|
|
|
unmarshaled = nil
|
2014-12-10 05:25:54 +00:00
|
|
|
if err := json.Unmarshal(p, &unmarshaled); err != nil {
|
|
|
|
t.Fatalf("unexpected error unmarshaling error envelope: %v", err)
|
|
|
|
}
|
|
|
|
|
2015-05-27 01:16:45 +00:00
|
|
|
if !reflect.DeepEqual(unmarshaled, errs) {
|
|
|
|
t.Fatalf("errors not equal after round trip:\nunmarshaled:\n%#v\n\nerrs:\n%#v", unmarshaled, errs)
|
2014-12-10 05:25:54 +00:00
|
|
|
}
|
2015-05-27 01:16:45 +00:00
|
|
|
|
2015-06-18 00:39:27 +00:00
|
|
|
// Verify that calling WithArgs() more than once does the right thing.
|
|
|
|
// Meaning creates a new Error and uses the ErrorCode Message
|
|
|
|
e1 = ErrorCodeTest3.WithArgs("test1")
|
|
|
|
e2 := e1.WithArgs("test2")
|
|
|
|
if &e1 == &e2 {
|
|
|
|
t.Fatalf("args: e2 and e1 should not be the same, but they are")
|
|
|
|
}
|
|
|
|
if e2.Message != `Sorry "test2" isn't valid` {
|
|
|
|
t.Fatalf("e2 had wrong message: %q", e2.Message)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Verify that calling WithDetail() more than once does the right thing.
|
|
|
|
// Meaning creates a new Error and overwrites the old detail field
|
|
|
|
e1 = ErrorCodeTest3.WithDetail("stuff1")
|
|
|
|
e2 = e1.WithDetail("stuff2")
|
|
|
|
if &e1 == &e2 {
|
|
|
|
t.Fatalf("detail: e2 and e1 should not be the same, but they are")
|
|
|
|
}
|
|
|
|
if e2.Detail != `stuff2` {
|
|
|
|
t.Fatalf("e2 had wrong detail: %q", e2.Detail)
|
|
|
|
}
|
2014-12-10 05:25:54 +00:00
|
|
|
}
|