1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package statuscheck
17
18 import (
19 "context"
20 "time"
21
22 . "github.com/onsi/ginkgo/v2"
23 . "github.com/onsi/gomega"
24 . "github.com/onsi/gomega/gstruct"
25 corev1 "k8s.io/api/core/v1"
26 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
27 "k8s.io/apimachinery/pkg/types"
28
29 "github.com/chaos-mesh/chaos-mesh/api/v1alpha1"
30 )
31
32
33
34
35 var _ = Describe("StatusCheck", func() {
36
37 BeforeEach(func() {
38
39 })
40
41 AfterEach(func() {
42
43 })
44
45 Context("Reconcile Synchronous StatusCheck", func() {
46 It("success threshold exceed", func() {
47 key := types.NamespacedName{
48 Name: "foo1",
49 Namespace: "default",
50 }
51 statusCheck := &v1alpha1.StatusCheck{
52 ObjectMeta: metav1.ObjectMeta{
53 Name: "foo1",
54 Namespace: "default",
55 },
56 Spec: v1alpha1.StatusCheckSpec{
57 Mode: v1alpha1.StatusCheckSynchronous,
58 Type: v1alpha1.TypeHTTP,
59 IntervalSeconds: 1,
60 TimeoutSeconds: 1,
61 FailureThreshold: 3,
62 SuccessThreshold: 1,
63 RecordsHistoryLimit: 10,
64 EmbedStatusCheck: &v1alpha1.EmbedStatusCheck{
65 HTTPStatusCheck: &v1alpha1.HTTPStatusCheck{
66 RequestUrl: "http://123.123.123.123",
67 RequestBody: "success",
68 Criteria: v1alpha1.HTTPCriteria{
69 StatusCode: "200",
70 },
71 },
72 },
73 },
74 }
75
76 By("creating a status check")
77 {
78 Expect(k8sClient.Create(context.TODO(), statusCheck)).To(Succeed())
79 }
80
81 By("reconciling status check")
82 {
83 Eventually(func() ([]v1alpha1.StatusCheckCondition, error) {
84 err := k8sClient.Get(context.TODO(), key, statusCheck)
85 if err != nil {
86 return nil, err
87 }
88 return statusCheck.Status.Conditions, nil
89 }, 5*time.Second, time.Second).Should(
90 ConsistOf(
91 MatchFields(IgnoreExtras, Fields{
92 "Type": Equal(v1alpha1.StatusCheckConditionCompleted),
93 "Status": Equal(corev1.ConditionTrue),
94 }),
95 MatchFields(IgnoreExtras, Fields{
96 "Type": Equal(v1alpha1.StatusCheckConditionSuccessThresholdExceed),
97 "Status": Equal(corev1.ConditionTrue),
98 }),
99 MatchFields(IgnoreExtras, Fields{
100 "Type": Equal(v1alpha1.StatusCheckConditionFailureThresholdExceed),
101 "Status": Equal(corev1.ConditionFalse),
102 }),
103 MatchFields(IgnoreExtras, Fields{
104 "Type": Equal(v1alpha1.StatusCheckConditionDurationExceed),
105 "Status": Equal(corev1.ConditionFalse),
106 }),
107 ))
108 }
109
110 By("deleting the created object")
111 {
112 Expect(k8sClient.Delete(context.TODO(), statusCheck)).To(Succeed())
113 }
114 })
115 It("failure threshold exceed", func() {
116 key := types.NamespacedName{
117 Name: "foo1",
118 Namespace: "default",
119 }
120 statusCheck := &v1alpha1.StatusCheck{
121 ObjectMeta: metav1.ObjectMeta{
122 Name: "foo1",
123 Namespace: "default",
124 },
125 Spec: v1alpha1.StatusCheckSpec{
126 Mode: v1alpha1.StatusCheckSynchronous,
127 Type: v1alpha1.TypeHTTP,
128 IntervalSeconds: 1,
129 TimeoutSeconds: 1,
130 FailureThreshold: 3,
131 SuccessThreshold: 1,
132 RecordsHistoryLimit: 10,
133 EmbedStatusCheck: &v1alpha1.EmbedStatusCheck{
134 HTTPStatusCheck: &v1alpha1.HTTPStatusCheck{
135 RequestUrl: "http://123.123.123.123",
136 RequestBody: "failure",
137 Criteria: v1alpha1.HTTPCriteria{
138 StatusCode: "200",
139 },
140 },
141 },
142 },
143 }
144
145 By("creating a status check")
146 {
147 Expect(k8sClient.Create(context.TODO(), statusCheck)).To(Succeed())
148 }
149
150 By("reconciling status check")
151 {
152 Eventually(func() ([]v1alpha1.StatusCheckCondition, error) {
153 err := k8sClient.Get(context.TODO(), key, statusCheck)
154 if err != nil {
155 return nil, err
156 }
157 return statusCheck.Status.Conditions, nil
158 }, 10*time.Second, time.Second).Should(
159 ConsistOf(
160 MatchFields(IgnoreExtras, Fields{
161 "Type": Equal(v1alpha1.StatusCheckConditionCompleted),
162 "Status": Equal(corev1.ConditionTrue),
163 }),
164 MatchFields(IgnoreExtras, Fields{
165 "Type": Equal(v1alpha1.StatusCheckConditionSuccessThresholdExceed),
166 "Status": Equal(corev1.ConditionFalse),
167 }),
168 MatchFields(IgnoreExtras, Fields{
169 "Type": Equal(v1alpha1.StatusCheckConditionFailureThresholdExceed),
170 "Status": Equal(corev1.ConditionTrue),
171 }),
172 MatchFields(IgnoreExtras, Fields{
173 "Type": Equal(v1alpha1.StatusCheckConditionDurationExceed),
174 "Status": Equal(corev1.ConditionFalse),
175 }),
176 ))
177 }
178
179 By("deleting the created object")
180 {
181 Expect(k8sClient.Delete(context.TODO(), statusCheck)).To(Succeed())
182 }
183 })
184 It("duration exceed", func() {
185 key := types.NamespacedName{
186 Name: "foo1",
187 Namespace: "default",
188 }
189 duration := "100ms"
190 statusCheck := &v1alpha1.StatusCheck{
191 ObjectMeta: metav1.ObjectMeta{
192 Name: "foo1",
193 Namespace: "default",
194 },
195 Spec: v1alpha1.StatusCheckSpec{
196 Mode: v1alpha1.StatusCheckSynchronous,
197 Type: v1alpha1.TypeHTTP,
198 IntervalSeconds: 1,
199 TimeoutSeconds: 1,
200 FailureThreshold: 3,
201 SuccessThreshold: 3,
202 RecordsHistoryLimit: 10,
203 Duration: &duration,
204 EmbedStatusCheck: &v1alpha1.EmbedStatusCheck{
205 HTTPStatusCheck: &v1alpha1.HTTPStatusCheck{
206 RequestUrl: "http://123.123.123.123",
207 RequestBody: "success",
208 Criteria: v1alpha1.HTTPCriteria{
209 StatusCode: "200",
210 },
211 },
212 },
213 },
214 }
215
216 By("creating a status check")
217 {
218 Expect(k8sClient.Create(context.TODO(), statusCheck)).To(Succeed())
219 }
220
221 By("reconciling status check")
222 {
223 Eventually(func() ([]v1alpha1.StatusCheckCondition, error) {
224 err := k8sClient.Get(context.TODO(), key, statusCheck)
225 if err != nil {
226 return nil, err
227 }
228 return statusCheck.Status.Conditions, nil
229 }, 10*time.Second, time.Second).Should(
230 ConsistOf(
231 MatchFields(IgnoreExtras, Fields{
232 "Type": Equal(v1alpha1.StatusCheckConditionCompleted),
233 "Status": Equal(corev1.ConditionTrue),
234 }),
235 MatchFields(IgnoreExtras, Fields{
236 "Type": Equal(v1alpha1.StatusCheckConditionSuccessThresholdExceed),
237 "Status": Equal(corev1.ConditionFalse),
238 }),
239 MatchFields(IgnoreExtras, Fields{
240 "Type": Equal(v1alpha1.StatusCheckConditionFailureThresholdExceed),
241 "Status": Equal(corev1.ConditionFalse),
242 }),
243 MatchFields(IgnoreExtras, Fields{
244 "Type": Equal(v1alpha1.StatusCheckConditionDurationExceed),
245 "Status": Equal(corev1.ConditionTrue),
246 }),
247 ))
248 }
249
250 By("deleting the created object")
251 {
252 Expect(k8sClient.Delete(context.TODO(), statusCheck)).To(Succeed())
253 }
254 })
255 It("failure threshold exceed, execution timeout", func() {
256 key := types.NamespacedName{
257 Name: "foo1",
258 Namespace: "default",
259 }
260 statusCheck := &v1alpha1.StatusCheck{
261 ObjectMeta: metav1.ObjectMeta{
262 Name: "foo1",
263 Namespace: "default",
264 },
265 Spec: v1alpha1.StatusCheckSpec{
266 Mode: v1alpha1.StatusCheckSynchronous,
267 Type: v1alpha1.TypeHTTP,
268 IntervalSeconds: 1,
269 TimeoutSeconds: 1,
270 FailureThreshold: 3,
271 SuccessThreshold: 1,
272 RecordsHistoryLimit: 10,
273 EmbedStatusCheck: &v1alpha1.EmbedStatusCheck{
274 HTTPStatusCheck: &v1alpha1.HTTPStatusCheck{
275 RequestUrl: "http://123.123.123.123",
276 RequestBody: "timeout",
277 Criteria: v1alpha1.HTTPCriteria{
278 StatusCode: "200",
279 },
280 },
281 },
282 },
283 }
284
285 By("creating a status check")
286 {
287 Expect(k8sClient.Create(context.TODO(), statusCheck)).To(Succeed())
288 }
289
290 By("reconciling status check")
291 {
292 Eventually(func() ([]v1alpha1.StatusCheckCondition, error) {
293 err := k8sClient.Get(context.TODO(), key, statusCheck)
294 if err != nil {
295 return nil, err
296 }
297 return statusCheck.Status.Conditions, nil
298 }, 10*time.Second, time.Second).Should(
299 ConsistOf(
300 MatchFields(IgnoreExtras, Fields{
301 "Type": Equal(v1alpha1.StatusCheckConditionCompleted),
302 "Status": Equal(corev1.ConditionTrue),
303 }),
304 MatchFields(IgnoreExtras, Fields{
305 "Type": Equal(v1alpha1.StatusCheckConditionSuccessThresholdExceed),
306 "Status": Equal(corev1.ConditionFalse),
307 }),
308 MatchFields(IgnoreExtras, Fields{
309 "Type": Equal(v1alpha1.StatusCheckConditionFailureThresholdExceed),
310 "Status": Equal(corev1.ConditionTrue),
311 }),
312 MatchFields(IgnoreExtras, Fields{
313 "Type": Equal(v1alpha1.StatusCheckConditionDurationExceed),
314 "Status": Equal(corev1.ConditionFalse),
315 }),
316 ))
317 }
318
319 By("deleting the created object")
320 {
321 Expect(k8sClient.Delete(context.TODO(), statusCheck)).To(Succeed())
322 }
323 })
324
325 Context("Reconcile Continuous StatusCheck", func() {
326 It("success threshold exceed", func() {
327 key := types.NamespacedName{
328 Name: "foo1",
329 Namespace: "default",
330 }
331 duration := "10s"
332 statusCheck := &v1alpha1.StatusCheck{
333 ObjectMeta: metav1.ObjectMeta{
334 Name: "foo1",
335 Namespace: "default",
336 },
337 Spec: v1alpha1.StatusCheckSpec{
338 Mode: v1alpha1.StatusCheckContinuous,
339 Type: v1alpha1.TypeHTTP,
340 Duration: &duration,
341 IntervalSeconds: 1,
342 TimeoutSeconds: 1,
343 FailureThreshold: 3,
344 SuccessThreshold: 1,
345 RecordsHistoryLimit: 10,
346 EmbedStatusCheck: &v1alpha1.EmbedStatusCheck{
347 HTTPStatusCheck: &v1alpha1.HTTPStatusCheck{
348 RequestUrl: "http://123.123.123.123",
349 RequestBody: "success",
350 Criteria: v1alpha1.HTTPCriteria{
351 StatusCode: "200",
352 },
353 },
354 },
355 },
356 }
357
358 By("creating a status check")
359 {
360 Expect(k8sClient.Create(context.TODO(), statusCheck)).To(Succeed())
361 }
362
363 By("reconciling status check, success threshold exceed but not completed")
364 {
365 Eventually(func() ([]v1alpha1.StatusCheckCondition, error) {
366 err := k8sClient.Get(context.TODO(), key, statusCheck)
367 if err != nil {
368 return nil, err
369 }
370 return statusCheck.Status.Conditions, nil
371 }, 5*time.Second, time.Second).Should(
372 ConsistOf(
373 MatchFields(IgnoreExtras, Fields{
374 "Type": Equal(v1alpha1.StatusCheckConditionCompleted),
375 "Status": Equal(corev1.ConditionFalse),
376 }),
377 MatchFields(IgnoreExtras, Fields{
378 "Type": Equal(v1alpha1.StatusCheckConditionSuccessThresholdExceed),
379 "Status": Equal(corev1.ConditionTrue),
380 }),
381 MatchFields(IgnoreExtras, Fields{
382 "Type": Equal(v1alpha1.StatusCheckConditionFailureThresholdExceed),
383 "Status": Equal(corev1.ConditionFalse),
384 }),
385 MatchFields(IgnoreExtras, Fields{
386 "Type": Equal(v1alpha1.StatusCheckConditionDurationExceed),
387 "Status": Equal(corev1.ConditionFalse),
388 }),
389 ))
390 }
391
392 By("reconciling status check, duration exceed and completed")
393 {
394 Eventually(func() ([]v1alpha1.StatusCheckCondition, error) {
395 err := k8sClient.Get(context.TODO(), key, statusCheck)
396 if err != nil {
397 return nil, err
398 }
399 return statusCheck.Status.Conditions, nil
400 }, 10*time.Second, time.Second).Should(
401 ConsistOf(
402 MatchFields(IgnoreExtras, Fields{
403 "Type": Equal(v1alpha1.StatusCheckConditionCompleted),
404 "Status": Equal(corev1.ConditionTrue),
405 }),
406 MatchFields(IgnoreExtras, Fields{
407 "Type": Equal(v1alpha1.StatusCheckConditionSuccessThresholdExceed),
408 "Status": Equal(corev1.ConditionTrue),
409 }),
410 MatchFields(IgnoreExtras, Fields{
411 "Type": Equal(v1alpha1.StatusCheckConditionFailureThresholdExceed),
412 "Status": Equal(corev1.ConditionFalse),
413 }),
414 MatchFields(IgnoreExtras, Fields{
415 "Type": Equal(v1alpha1.StatusCheckConditionDurationExceed),
416 "Status": Equal(corev1.ConditionTrue),
417 }),
418 ))
419 }
420
421 By("deleting the created object")
422 {
423 Expect(k8sClient.Delete(context.TODO(), statusCheck)).To(Succeed())
424 }
425 })
426
427 It("failure threshold exceed", func() {
428 key := types.NamespacedName{
429 Name: "foo1",
430 Namespace: "default",
431 }
432 duration := "10s"
433 statusCheck := &v1alpha1.StatusCheck{
434 ObjectMeta: metav1.ObjectMeta{
435 Name: "foo1",
436 Namespace: "default",
437 },
438 Spec: v1alpha1.StatusCheckSpec{
439 Mode: v1alpha1.StatusCheckContinuous,
440 Type: v1alpha1.TypeHTTP,
441 Duration: &duration,
442 IntervalSeconds: 1,
443 TimeoutSeconds: 1,
444 FailureThreshold: 3,
445 SuccessThreshold: 1,
446 RecordsHistoryLimit: 10,
447 EmbedStatusCheck: &v1alpha1.EmbedStatusCheck{
448 HTTPStatusCheck: &v1alpha1.HTTPStatusCheck{
449 RequestUrl: "http://123.123.123.123",
450 RequestBody: "failure",
451 Criteria: v1alpha1.HTTPCriteria{
452 StatusCode: "200",
453 },
454 },
455 },
456 },
457 }
458
459 By("creating a status check")
460 {
461 Expect(k8sClient.Create(context.TODO(), statusCheck)).To(Succeed())
462 }
463
464 By("reconciling status check, failure threshold exceed and completed (duration not exceed)")
465 {
466 Eventually(func() ([]v1alpha1.StatusCheckCondition, error) {
467 err := k8sClient.Get(context.TODO(), key, statusCheck)
468 if err != nil {
469 return nil, err
470 }
471 return statusCheck.Status.Conditions, nil
472 }, 5*time.Second, time.Second).Should(
473 ConsistOf(
474 MatchFields(IgnoreExtras, Fields{
475 "Type": Equal(v1alpha1.StatusCheckConditionCompleted),
476 "Status": Equal(corev1.ConditionTrue),
477 }),
478 MatchFields(IgnoreExtras, Fields{
479 "Type": Equal(v1alpha1.StatusCheckConditionSuccessThresholdExceed),
480 "Status": Equal(corev1.ConditionFalse),
481 }),
482 MatchFields(IgnoreExtras, Fields{
483 "Type": Equal(v1alpha1.StatusCheckConditionFailureThresholdExceed),
484 "Status": Equal(corev1.ConditionTrue),
485 }),
486 MatchFields(IgnoreExtras, Fields{
487 "Type": Equal(v1alpha1.StatusCheckConditionDurationExceed),
488 "Status": Equal(corev1.ConditionFalse),
489 }),
490 ))
491 }
492
493 By("deleting the created object")
494 {
495 Expect(k8sClient.Delete(context.TODO(), statusCheck)).To(Succeed())
496 }
497 })
498 })
499 })
500 })
501