Skip to content

Commit 1f5be8a

Browse files
author
Eric Abramov
committed
Adding tests for webhook/admission/validator.go
1 parent f61e953 commit 1f5be8a

File tree

1 file changed

+307
-0
lines changed

1 file changed

+307
-0
lines changed
Lines changed: 307 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,307 @@
1+
package admission
2+
3+
import (
4+
"context"
5+
goerrors "errors"
6+
"net/http"
7+
8+
. "github.com/onsi/ginkgo"
9+
. "github.com/onsi/gomega"
10+
11+
"k8s.io/api/admission/v1beta1"
12+
apierrs "k8s.io/apimachinery/pkg/api/errors"
13+
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
14+
"k8s.io/apimachinery/pkg/runtime"
15+
"k8s.io/apimachinery/pkg/runtime/schema"
16+
"k8s.io/client-go/kubernetes/scheme"
17+
)
18+
19+
var _ = FDescribe("validatingHandler", func() {
20+
Describe("Handle", func() {
21+
22+
When("create succeeds", func() {
23+
It("should return allowed in response", func() {
24+
25+
handler := createSucceedingValidatingHandler()
26+
27+
response := handler.Handle(context.TODO(), Request{
28+
AdmissionRequest: v1beta1.AdmissionRequest{
29+
Operation: v1beta1.Create,
30+
Object: runtime.RawExtension{
31+
Raw: []byte("{}"),
32+
Object: handler.validator,
33+
},
34+
},
35+
})
36+
Expect(response.Allowed).Should(BeTrue())
37+
Expect(response.Result.Code).Should(Equal(int32(http.StatusOK)))
38+
})
39+
})
40+
41+
When("create fails on decode", func() {
42+
It("should return 400 in response", func() {
43+
//TODO
44+
})
45+
})
46+
47+
When("ValidateCreate returns APIStatus error", func() {
48+
It("should return Status.Code and embed the Status object from APIStatus in the response", func() {
49+
50+
handler, expectedError := createValidatingHandlerWhichReturnsStatusError()
51+
52+
response := handler.Handle(context.TODO(), Request{
53+
AdmissionRequest: v1beta1.AdmissionRequest{
54+
Operation: v1beta1.Create,
55+
Object: runtime.RawExtension{
56+
Raw: []byte("{}"),
57+
Object: handler.validator,
58+
},
59+
},
60+
})
61+
Expect(response.Allowed).Should(BeFalse())
62+
63+
apiStatus, ok := expectedError.(apierrs.APIStatus)
64+
Expect(ok).Should(BeTrue())
65+
Expect(response.Result.Code).Should(Equal(apiStatus.Status().Code))
66+
Expect(*response.Result).Should(Equal(apiStatus.Status()))
67+
68+
})
69+
})
70+
71+
When("ValidateCreate returns any error", func() {
72+
It("should return 403 and embed the error message in a generated Status object in the response", func() {
73+
74+
handler, expectedError := createValidatingHandlerWhichReturnsRegularError()
75+
76+
response := handler.Handle(context.TODO(), Request{
77+
AdmissionRequest: v1beta1.AdmissionRequest{
78+
Operation: v1beta1.Create,
79+
Object: runtime.RawExtension{
80+
Raw: []byte("{}"),
81+
Object: handler.validator,
82+
},
83+
},
84+
})
85+
Expect(response.Allowed).Should(BeFalse())
86+
Expect(response.Result.Code).Should(Equal(int32(http.StatusForbidden)))
87+
Expect(string(response.Result.Reason)).Should(Equal(expectedError.Error()))
88+
89+
})
90+
})
91+
92+
When("update succeeds", func() {
93+
It("should return allowed in response", func() {
94+
95+
handler := createSucceedingValidatingHandler()
96+
97+
response := handler.Handle(context.TODO(), Request{
98+
AdmissionRequest: v1beta1.AdmissionRequest{
99+
Operation: v1beta1.Update,
100+
Object: runtime.RawExtension{
101+
Raw: []byte("{}"),
102+
Object: handler.validator,
103+
},
104+
OldObject: runtime.RawExtension{
105+
Raw: []byte("{}"),
106+
Object: handler.validator,
107+
},
108+
},
109+
})
110+
Expect(response.Allowed).Should(BeTrue())
111+
Expect(response.Result.Code).Should(Equal(int32(http.StatusOK)))
112+
})
113+
})
114+
115+
When("update fails on decoding new object", func() {
116+
It("should return 400 in response", func() {
117+
//TODO
118+
})
119+
})
120+
121+
When("update fails on decoding old object", func() {
122+
It("should return 400 in response", func() {
123+
//TODO
124+
})
125+
})
126+
127+
When("ValidateUpdate returns APIStatus error", func() {
128+
It("should return Status.Code and embed the Status object from APIStatus in the response", func() {
129+
130+
handler, expectedError := createValidatingHandlerWhichReturnsStatusError()
131+
132+
response := handler.Handle(context.TODO(), Request{
133+
AdmissionRequest: v1beta1.AdmissionRequest{
134+
Operation: v1beta1.Update,
135+
Object: runtime.RawExtension{
136+
Raw: []byte("{}"),
137+
Object: handler.validator,
138+
},
139+
OldObject: runtime.RawExtension{
140+
Raw: []byte("{}"),
141+
Object: handler.validator,
142+
},
143+
},
144+
})
145+
Expect(response.Allowed).Should(BeFalse())
146+
147+
apiStatus, ok := expectedError.(apierrs.APIStatus)
148+
Expect(ok).Should(BeTrue())
149+
Expect(response.Result.Code).Should(Equal(apiStatus.Status().Code))
150+
Expect(*response.Result).Should(Equal(apiStatus.Status()))
151+
152+
})
153+
})
154+
155+
When("ValidateUpdate returns any error", func() {
156+
It("should return 403 and embed the error message in a generated Status object in the response", func() {
157+
158+
handler, expectedError := createValidatingHandlerWhichReturnsRegularError()
159+
160+
response := handler.Handle(context.TODO(), Request{
161+
AdmissionRequest: v1beta1.AdmissionRequest{
162+
Operation: v1beta1.Update,
163+
Object: runtime.RawExtension{
164+
Raw: []byte("{}"),
165+
Object: handler.validator,
166+
},
167+
OldObject: runtime.RawExtension{
168+
Raw: []byte("{}"),
169+
Object: handler.validator,
170+
},
171+
},
172+
})
173+
Expect(response.Allowed).Should(BeFalse())
174+
Expect(response.Result.Code).Should(Equal(int32(http.StatusForbidden)))
175+
Expect(string(response.Result.Reason)).Should(Equal(expectedError.Error()))
176+
177+
})
178+
})
179+
180+
When("delete succeeds", func() {
181+
It("should return allowed in response", func() {
182+
183+
handler := createSucceedingValidatingHandler()
184+
185+
response := handler.Handle(context.TODO(), Request{
186+
AdmissionRequest: v1beta1.AdmissionRequest{
187+
Operation: v1beta1.Delete,
188+
OldObject: runtime.RawExtension{
189+
Raw: []byte("{}"),
190+
Object: handler.validator,
191+
},
192+
},
193+
})
194+
Expect(response.Allowed).Should(BeTrue())
195+
Expect(response.Result.Code).Should(Equal(int32(http.StatusOK)))
196+
})
197+
})
198+
199+
When("delete fails on decode", func() {
200+
It("should return 400 in response", func() {
201+
//TODO
202+
})
203+
})
204+
205+
When("ValidateDelete returns APIStatus error", func() {
206+
It("should return Status.Code and embed the Status object from APIStatus in the response", func() {
207+
208+
handler, expectedError := createValidatingHandlerWhichReturnsStatusError()
209+
210+
response := handler.Handle(context.TODO(), Request{
211+
AdmissionRequest: v1beta1.AdmissionRequest{
212+
Operation: v1beta1.Delete,
213+
OldObject: runtime.RawExtension{
214+
Raw: []byte("{}"),
215+
Object: handler.validator,
216+
},
217+
},
218+
})
219+
Expect(response.Allowed).Should(BeFalse())
220+
221+
apiStatus, ok := expectedError.(apierrs.APIStatus)
222+
Expect(ok).Should(BeTrue())
223+
Expect(response.Result.Code).Should(Equal(apiStatus.Status().Code))
224+
Expect(*response.Result).Should(Equal(apiStatus.Status()))
225+
226+
})
227+
})
228+
229+
When("ValidateDelete returns any error", func() {
230+
It("should return 403 and embed the error message in a generated Status object in the response", func() {
231+
232+
handler, expectedError := createValidatingHandlerWhichReturnsRegularError()
233+
234+
response := handler.Handle(context.TODO(), Request{
235+
AdmissionRequest: v1beta1.AdmissionRequest{
236+
Operation: v1beta1.Delete,
237+
OldObject: runtime.RawExtension{
238+
Raw: []byte("{}"),
239+
Object: handler.validator,
240+
},
241+
},
242+
})
243+
Expect(response.Allowed).Should(BeFalse())
244+
Expect(response.Result.Code).Should(Equal(int32(http.StatusForbidden)))
245+
Expect(string(response.Result.Reason)).Should(Equal(expectedError.Error()))
246+
247+
})
248+
})
249+
})
250+
})
251+
252+
type fakeValidator struct {
253+
ErrorToReturn error `json:"ErrorToReturn,omitempty"`
254+
}
255+
256+
var _ Validator = &fakeValidator{}
257+
258+
var fakeValidatorVK = schema.GroupVersionKind{Group: "foo.test.org", Version: "v1", Kind: "fakeValidator"}
259+
260+
func (v *fakeValidator) ValidateCreate() error {
261+
return v.ErrorToReturn
262+
}
263+
264+
func (v *fakeValidator) ValidateUpdate(old runtime.Object) error {
265+
return v.ErrorToReturn
266+
}
267+
268+
func (v *fakeValidator) ValidateDelete() error {
269+
return v.ErrorToReturn
270+
}
271+
272+
func (v *fakeValidator) GetObjectKind() schema.ObjectKind { return v }
273+
274+
func (v *fakeValidator) DeepCopyObject() runtime.Object {
275+
return &fakeValidator{ErrorToReturn: v.ErrorToReturn}
276+
}
277+
278+
func (v *fakeValidator) GroupVersionKind() schema.GroupVersionKind {
279+
return fakeValidatorVK
280+
}
281+
282+
func (v *fakeValidator) SetGroupVersionKind(gvk schema.GroupVersionKind) {}
283+
284+
func createSucceedingValidatingHandler() *validatingHandler {
285+
decoder, _ := NewDecoder(scheme.Scheme)
286+
f := &fakeValidator{ErrorToReturn: nil}
287+
return &validatingHandler{f, decoder}
288+
}
289+
290+
func createValidatingHandlerWhichReturnsRegularError() (validatingHandler, error) {
291+
decoder, _ := NewDecoder(scheme.Scheme)
292+
errToReturn := goerrors.New("some error")
293+
f := &fakeValidator{ErrorToReturn: errToReturn}
294+
return validatingHandler{f, decoder}, errToReturn
295+
}
296+
297+
func createValidatingHandlerWhichReturnsStatusError() (validatingHandler, error) {
298+
decoder, _ := NewDecoder(scheme.Scheme)
299+
errToReturn := &apierrs.StatusError{
300+
ErrStatus: v1.Status{
301+
Message: "some message",
302+
Code: http.StatusUnprocessableEntity,
303+
},
304+
}
305+
f := &fakeValidator{ErrorToReturn: errToReturn}
306+
return validatingHandler{f, decoder}, errToReturn
307+
}

0 commit comments

Comments
 (0)