...

Source file src/github.com/chaos-mesh/chaos-mesh/controllers/statuscheck/controller_test.go

Documentation: github.com/chaos-mesh/chaos-mesh/controllers/statuscheck

     1  // Copyright Chaos Mesh Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  // http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    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  // These tests use Ginkgo (BDD-style Go testing framework). Refer to
    33  // http://onsi.github.io/ginkgo/ to learn more about Ginkgo.
    34  
    35  var _ = Describe("StatusCheck", func() {
    36  
    37  	BeforeEach(func() {
    38  		// Add any setup steps that needs to be executed before each test
    39  	})
    40  
    41  	AfterEach(func() {
    42  		// Add any teardown steps that needs to be executed after each test
    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