1/* 2Copyright 2014 The Kubernetes Authors. 3 4Licensed under the Apache License, Version 2.0 (the "License"); 5you may not use this file except in compliance with the License. 6You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10Unless required by applicable law or agreed to in writing, software 11distributed under the License is distributed on an "AS IS" BASIS, 12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13See the License for the specific language governing permissions and 14limitations under the License. 15*/ 16 17package errors 18 19import ( 20 "errors" 21 "fmt" 22 "reflect" 23 "testing" 24 25 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 26 "k8s.io/apimachinery/pkg/runtime" 27 "k8s.io/apimachinery/pkg/runtime/schema" 28 "k8s.io/apimachinery/pkg/util/validation/field" 29) 30 31func resource(resource string) schema.GroupResource { 32 return schema.GroupResource{Group: "", Resource: resource} 33} 34func kind(kind string) schema.GroupKind { 35 return schema.GroupKind{Group: "", Kind: kind} 36} 37 38func TestErrorNew(t *testing.T) { 39 err := NewAlreadyExists(resource("tests"), "1") 40 if !IsAlreadyExists(err) { 41 t.Errorf("expected to be %s", metav1.StatusReasonAlreadyExists) 42 } 43 if IsConflict(err) { 44 t.Errorf("expected to not be %s", metav1.StatusReasonConflict) 45 } 46 if IsNotFound(err) { 47 t.Errorf(fmt.Sprintf("expected to not be %s", metav1.StatusReasonNotFound)) 48 } 49 if IsInvalid(err) { 50 t.Errorf("expected to not be %s", metav1.StatusReasonInvalid) 51 } 52 if IsBadRequest(err) { 53 t.Errorf("expected to not be %s", metav1.StatusReasonBadRequest) 54 } 55 if IsForbidden(err) { 56 t.Errorf("expected to not be %s", metav1.StatusReasonForbidden) 57 } 58 if IsServerTimeout(err) { 59 t.Errorf("expected to not be %s", metav1.StatusReasonServerTimeout) 60 } 61 if IsMethodNotSupported(err) { 62 t.Errorf("expected to not be %s", metav1.StatusReasonMethodNotAllowed) 63 } 64 65 if !IsConflict(NewConflict(resource("tests"), "2", errors.New("message"))) { 66 t.Errorf("expected to be conflict") 67 } 68 if !IsNotFound(NewNotFound(resource("tests"), "3")) { 69 t.Errorf("expected to be %s", metav1.StatusReasonNotFound) 70 } 71 if !IsInvalid(NewInvalid(kind("Test"), "2", nil)) { 72 t.Errorf("expected to be %s", metav1.StatusReasonInvalid) 73 } 74 if !IsBadRequest(NewBadRequest("reason")) { 75 t.Errorf("expected to be %s", metav1.StatusReasonBadRequest) 76 } 77 if !IsForbidden(NewForbidden(resource("tests"), "2", errors.New("reason"))) { 78 t.Errorf("expected to be %s", metav1.StatusReasonForbidden) 79 } 80 if !IsUnauthorized(NewUnauthorized("reason")) { 81 t.Errorf("expected to be %s", metav1.StatusReasonUnauthorized) 82 } 83 if !IsServerTimeout(NewServerTimeout(resource("tests"), "reason", 0)) { 84 t.Errorf("expected to be %s", metav1.StatusReasonServerTimeout) 85 } 86 if !IsMethodNotSupported(NewMethodNotSupported(resource("foos"), "delete")) { 87 t.Errorf("expected to be %s", metav1.StatusReasonMethodNotAllowed) 88 } 89 90 if time, ok := SuggestsClientDelay(NewServerTimeout(resource("tests"), "doing something", 10)); time != 10 || !ok { 91 t.Errorf("unexpected %d", time) 92 } 93 if time, ok := SuggestsClientDelay(NewServerTimeout(resource("tests"), "doing something", 0)); time != 0 || !ok { 94 t.Errorf("unexpected %d", time) 95 } 96 if time, ok := SuggestsClientDelay(NewTimeoutError("test reason", 10)); time != 10 || !ok { 97 t.Errorf("unexpected %d", time) 98 } 99 if time, ok := SuggestsClientDelay(NewTooManyRequests("doing something", 10)); time != 10 || !ok { 100 t.Errorf("unexpected %d", time) 101 } 102 if time, ok := SuggestsClientDelay(NewTooManyRequests("doing something", 1)); time != 1 || !ok { 103 t.Errorf("unexpected %d", time) 104 } 105 if time, ok := SuggestsClientDelay(NewGenericServerResponse(429, "get", resource("tests"), "test", "doing something", 10, true)); time != 10 || !ok { 106 t.Errorf("unexpected %d", time) 107 } 108 if time, ok := SuggestsClientDelay(NewGenericServerResponse(500, "get", resource("tests"), "test", "doing something", 10, true)); time != 10 || !ok { 109 t.Errorf("unexpected %d", time) 110 } 111 if time, ok := SuggestsClientDelay(NewGenericServerResponse(429, "get", resource("tests"), "test", "doing something", 0, true)); time != 0 || ok { 112 t.Errorf("unexpected %d", time) 113 } 114} 115 116func TestNewInvalid(t *testing.T) { 117 testCases := []struct { 118 Err *field.Error 119 Details *metav1.StatusDetails 120 }{ 121 { 122 field.Duplicate(field.NewPath("field[0].name"), "bar"), 123 &metav1.StatusDetails{ 124 Kind: "Kind", 125 Name: "name", 126 Causes: []metav1.StatusCause{{ 127 Type: metav1.CauseTypeFieldValueDuplicate, 128 Field: "field[0].name", 129 }}, 130 }, 131 }, 132 { 133 field.Invalid(field.NewPath("field[0].name"), "bar", "detail"), 134 &metav1.StatusDetails{ 135 Kind: "Kind", 136 Name: "name", 137 Causes: []metav1.StatusCause{{ 138 Type: metav1.CauseTypeFieldValueInvalid, 139 Field: "field[0].name", 140 }}, 141 }, 142 }, 143 { 144 field.NotFound(field.NewPath("field[0].name"), "bar"), 145 &metav1.StatusDetails{ 146 Kind: "Kind", 147 Name: "name", 148 Causes: []metav1.StatusCause{{ 149 Type: metav1.CauseTypeFieldValueNotFound, 150 Field: "field[0].name", 151 }}, 152 }, 153 }, 154 { 155 field.NotSupported(field.NewPath("field[0].name"), "bar", nil), 156 &metav1.StatusDetails{ 157 Kind: "Kind", 158 Name: "name", 159 Causes: []metav1.StatusCause{{ 160 Type: metav1.CauseTypeFieldValueNotSupported, 161 Field: "field[0].name", 162 }}, 163 }, 164 }, 165 { 166 field.Required(field.NewPath("field[0].name"), ""), 167 &metav1.StatusDetails{ 168 Kind: "Kind", 169 Name: "name", 170 Causes: []metav1.StatusCause{{ 171 Type: metav1.CauseTypeFieldValueRequired, 172 Field: "field[0].name", 173 }}, 174 }, 175 }, 176 } 177 for i, testCase := range testCases { 178 vErr, expected := testCase.Err, testCase.Details 179 expected.Causes[0].Message = vErr.ErrorBody() 180 err := NewInvalid(kind("Kind"), "name", field.ErrorList{vErr}) 181 status := err.ErrStatus 182 if status.Code != 422 || status.Reason != metav1.StatusReasonInvalid { 183 t.Errorf("%d: unexpected status: %#v", i, status) 184 } 185 if !reflect.DeepEqual(expected, status.Details) { 186 t.Errorf("%d: expected %#v, got %#v", i, expected, status.Details) 187 } 188 } 189} 190 191func TestReasonForError(t *testing.T) { 192 if e, a := metav1.StatusReasonUnknown, ReasonForError(nil); e != a { 193 t.Errorf("unexpected reason type: %#v", a) 194 } 195} 196 197type TestType struct{} 198 199func (obj *TestType) GetObjectKind() schema.ObjectKind { return schema.EmptyObjectKind } 200func (obj *TestType) DeepCopyObject() runtime.Object { 201 if obj == nil { 202 return nil 203 } 204 clone := *obj 205 return &clone 206} 207 208func TestFromObject(t *testing.T) { 209 table := []struct { 210 obj runtime.Object 211 message string 212 }{ 213 {&metav1.Status{Message: "foobar"}, "foobar"}, 214 {&TestType{}, "unexpected object: &{}"}, 215 } 216 217 for _, item := range table { 218 if e, a := item.message, FromObject(item.obj).Error(); e != a { 219 t.Errorf("Expected %v, got %v", e, a) 220 } 221 } 222} 223