1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
|
package errcode
import (
"encoding/json"
"net/http"
"reflect"
"strings"
"testing"
)
// TestErrorsManagement does a quick check of the Errors type to ensure that
// members are properly pushed and marshaled.
var ErrorCodeTest1 = Register("test.errors", ErrorDescriptor{
Value: "TEST1",
Message: "test error 1",
Description: `Just a test message #1.`,
HTTPStatusCode: http.StatusInternalServerError,
})
var ErrorCodeTest2 = Register("test.errors", ErrorDescriptor{
Value: "TEST2",
Message: "test error 2",
Description: `Just a test message #2.`,
HTTPStatusCode: http.StatusNotFound,
})
var ErrorCodeTest3 = Register("test.errors", ErrorDescriptor{
Value: "TEST3",
Message: "Sorry %q isn't valid",
Description: `Just a test message #3.`,
HTTPStatusCode: http.StatusNotFound,
})
// TestErrorCodes ensures that error code format, mappings and
// marshaling/unmarshaling. round trips are stable.
func TestErrorCodes(t *testing.T) {
if len(errorCodeToDescriptors) == 0 {
t.Fatal("errors aren't loaded!")
}
for ec, desc := range errorCodeToDescriptors {
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 mtach 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)
}
}
}
func TestErrorsManagement(t *testing.T) {
var errs Errors
errs = append(errs, ErrorCodeTest1)
errs = append(errs, ErrorCodeTest2.WithDetail(
map[string]interface{}{"digest": "sometestblobsumdoesntmatter"}))
errs = append(errs, ErrorCodeTest3.WithArgs("BOOGIE"))
errs = append(errs, ErrorCodeTest3.WithArgs("BOOGIE").WithDetail("data"))
p, err := json.Marshal(errs)
if err != nil {
t.Fatalf("error marashaling errors: %v", err)
}
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"}` +
`]}`
if string(p) != expectedJSON {
t.Fatalf("unexpected json:\ngot:\n%q\n\nexpected:\n%q", string(p), expectedJSON)
}
// 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)
}
// 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)
}
exp1 = "test3: " + exp1
if e1.Error() != exp1 {
t.Fatalf("Error() didn't return the right string, got:%s\nexpected:%s", e1.Error(), exp1)
}
// Test again with a single value this time
errs = Errors{ErrorCodeUnknown}
expectedJSON = "{\"errors\":[{\"code\":\"UNKNOWN\",\"message\":\"unknown error\"}]}"
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)
}
// Now test the reverse
unmarshaled = nil
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)
}
// 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)
}
}
|