...

Source file src/github.com/chaos-mesh/chaos-mesh/e2e-test/e2e/chaos/httpchaos/http_patch.go

Documentation: github.com/chaos-mesh/chaos-mesh/e2e-test/e2e/chaos/httpchaos

     1  // Copyright 2021 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 httpchaos
    17  
    18  import (
    19  	"context"
    20  	"io"
    21  	"strings"
    22  	"time"
    23  
    24  	. "github.com/onsi/ginkgo/v2"
    25  	corev1 "k8s.io/api/core/v1"
    26  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    27  	"k8s.io/apimachinery/pkg/types"
    28  	"k8s.io/apimachinery/pkg/util/wait"
    29  	"k8s.io/klog/v2"
    30  	"k8s.io/kubernetes/test/e2e/framework"
    31  	"sigs.k8s.io/controller-runtime/pkg/client"
    32  
    33  	"github.com/chaos-mesh/chaos-mesh/api/v1alpha1"
    34  	"github.com/chaos-mesh/chaos-mesh/e2e-test/e2e/util"
    35  )
    36  
    37  func TestcaseHttpPatchThenRecover(
    38  	ns string,
    39  	cli client.Client,
    40  	c HTTPE2EClient,
    41  	port uint16,
    42  ) {
    43  	ctx, cancel := context.WithCancel(context.Background())
    44  	defer cancel()
    45  
    46  	By("waiting on e2e helper ready")
    47  	err := util.WaitHTTPE2EHelperReady(*c.C, c.IP, port)
    48  	framework.ExpectNoError(err, "wait e2e helper ready error")
    49  
    50  	body := `{"msg":"Hello","target":"World"}`
    51  	secret := "Bar"
    52  
    53  	By("waiting for assertion normal behaviour")
    54  	err = wait.PollImmediate(1*time.Second, 1*time.Minute, func() (bool, error) {
    55  		resp, err := getPodHttp(c, port, secret, body)
    56  		if err != nil {
    57  			return false, err
    58  		}
    59  		defer resp.Body.Close()
    60  
    61  		s := strings.Join(resp.Header[SECRET], "; ")
    62  		b, err := io.ReadAll(resp.Body)
    63  		if err != nil {
    64  			return false, err
    65  		}
    66  
    67  		klog.Infof("Status(%d), Secret(%s), Body(%s)", resp.StatusCode, s, string(b))
    68  
    69  		if s == secret && string(b) == body {
    70  			return true, nil
    71  		}
    72  		return false, nil
    73  	})
    74  	framework.ExpectNoError(err, "helper server doesn't work as expected")
    75  	By("deploy helper server successfully")
    76  
    77  	By("create http patch chaos CRD objects")
    78  
    79  	patchbody := `{"target": "Chaos Mesh"}`
    80  	patchSecret := "Foo!"
    81  	expectedSecret := "Bar; Foo!"
    82  	expectedBody := `{"msg":"Hello","target":"Chaos Mesh"}`
    83  
    84  	httpChaos := &v1alpha1.HTTPChaos{
    85  		ObjectMeta: metav1.ObjectMeta{
    86  			Name:      "http-chaos",
    87  			Namespace: ns,
    88  		},
    89  		Spec: v1alpha1.HTTPChaosSpec{
    90  			PodSelector: v1alpha1.PodSelector{
    91  				Selector: v1alpha1.PodSelectorSpec{
    92  					GenericSelectorSpec: v1alpha1.GenericSelectorSpec{
    93  						Namespaces:     []string{ns},
    94  						LabelSelectors: map[string]string{"app": "http"},
    95  					},
    96  				},
    97  				Mode: v1alpha1.OneMode,
    98  			},
    99  			Port:   8080,
   100  			Target: "Request",
   101  			PodHttpChaosActions: v1alpha1.PodHttpChaosActions{
   102  				Patch: &v1alpha1.PodHttpChaosPatchActions{
   103  					Headers: [][]string{
   104  						{SECRET, patchSecret},
   105  					},
   106  					Body: &v1alpha1.PodHttpChaosPatchBodyAction{
   107  						Type:  "JSON",
   108  						Value: patchbody,
   109  					},
   110  				},
   111  			},
   112  		},
   113  	}
   114  	err = cli.Create(ctx, httpChaos)
   115  	framework.ExpectNoError(err, "create http chaos error")
   116  
   117  	By("waiting for assertion HTTP patch")
   118  	err = wait.PollImmediate(1*time.Second, 1*time.Minute, func() (bool, error) {
   119  		resp, err := getPodHttp(c, port, secret, body)
   120  		if err != nil {
   121  			return false, err
   122  		}
   123  		defer resp.Body.Close()
   124  
   125  		s := strings.Join(resp.Header[SECRET], "; ")
   126  		b, err := io.ReadAll(resp.Body)
   127  		if err != nil {
   128  			return false, err
   129  		}
   130  
   131  		klog.Infof("Status(%d), Secret(%s), Body(%s)", resp.StatusCode, s, string(b))
   132  
   133  		if s == expectedSecret && string(b) == expectedBody {
   134  			return true, nil
   135  		}
   136  		return false, nil
   137  	})
   138  	framework.ExpectNoError(err, "http chaos doesn't work as expected")
   139  	By("apply http chaos successfully")
   140  
   141  	By("delete chaos CRD objects")
   142  	// delete chaos CRD
   143  	err = cli.Delete(ctx, httpChaos)
   144  	framework.ExpectNoError(err, "failed to delete http chaos")
   145  
   146  	By("waiting for assertion recovering")
   147  	err = wait.PollImmediate(1*time.Second, 1*time.Minute, func() (bool, error) {
   148  		resp, err := getPodHttp(c, port, secret, body)
   149  		if err != nil {
   150  			return false, err
   151  		}
   152  		defer resp.Body.Close()
   153  
   154  		s := strings.Join(resp.Header[SECRET], "; ")
   155  		b, err := io.ReadAll(resp.Body)
   156  		if err != nil {
   157  			return false, err
   158  		}
   159  
   160  		klog.Infof("Status(%d), Secret(%s), Body(%s)", resp.StatusCode, s, string(b))
   161  
   162  		if s == secret && string(b) == body {
   163  			return true, nil
   164  		}
   165  		return false, nil
   166  	})
   167  	framework.ExpectNoError(err, "fail to recover http chaos")
   168  }
   169  
   170  func TestcaseHttpPatchPauseAndUnPause(
   171  	ns string,
   172  	cli client.Client,
   173  	c HTTPE2EClient,
   174  	port uint16,
   175  ) {
   176  	ctx, cancel := context.WithCancel(context.Background())
   177  	defer cancel()
   178  
   179  	By("waiting on e2e helper ready")
   180  	err := util.WaitHTTPE2EHelperReady(*c.C, c.IP, port)
   181  	framework.ExpectNoError(err, "wait e2e helper ready error")
   182  
   183  	body := `{"msg":"Hello","target":"World"}`
   184  	secret := "Bar"
   185  
   186  	By("waiting for assertion normal behaviour")
   187  	err = wait.PollImmediate(1*time.Second, 1*time.Minute, func() (bool, error) {
   188  		resp, err := getPodHttp(c, port, secret, body)
   189  		if err != nil {
   190  			return false, err
   191  		}
   192  		defer resp.Body.Close()
   193  
   194  		s := strings.Join(resp.Header[SECRET], "; ")
   195  		b, err := io.ReadAll(resp.Body)
   196  		if err != nil {
   197  			return false, err
   198  		}
   199  
   200  		klog.Infof("Status(%d), Secret(%s), Body(%s)", resp.StatusCode, s, string(b))
   201  
   202  		if s == secret && string(b) == body {
   203  			return true, nil
   204  		}
   205  		return false, nil
   206  	})
   207  	framework.ExpectNoError(err, "helper server doesn't work as expected")
   208  	By("deploy helper server successfully")
   209  
   210  	By("create http patch chaos CRD objects")
   211  	patchbody := `{"target": "Chaos Mesh"}`
   212  	patchSecret := "Foo!"
   213  	expectedSecret := "Bar; Foo!"
   214  	expectedBody := `{"msg":"Hello","target":"Chaos Mesh"}`
   215  
   216  	httpChaos := &v1alpha1.HTTPChaos{
   217  		ObjectMeta: metav1.ObjectMeta{
   218  			Name:      "http-chaos",
   219  			Namespace: ns,
   220  		},
   221  		Spec: v1alpha1.HTTPChaosSpec{
   222  			PodSelector: v1alpha1.PodSelector{
   223  				Selector: v1alpha1.PodSelectorSpec{
   224  					GenericSelectorSpec: v1alpha1.GenericSelectorSpec{
   225  						Namespaces:     []string{ns},
   226  						LabelSelectors: map[string]string{"app": "http"},
   227  					},
   228  				},
   229  				Mode: v1alpha1.OneMode,
   230  			},
   231  			Port:   8080,
   232  			Target: "Request",
   233  			PodHttpChaosActions: v1alpha1.PodHttpChaosActions{
   234  				Patch: &v1alpha1.PodHttpChaosPatchActions{
   235  					Headers: [][]string{
   236  						{SECRET, patchSecret},
   237  					},
   238  					Body: &v1alpha1.PodHttpChaosPatchBodyAction{
   239  						Type:  "JSON",
   240  						Value: patchbody,
   241  					},
   242  				},
   243  			},
   244  		},
   245  	}
   246  	err = cli.Create(ctx, httpChaos)
   247  	framework.ExpectNoError(err, "create http chaos error")
   248  
   249  	chaosKey := types.NamespacedName{
   250  		Namespace: ns,
   251  		Name:      "http-chaos",
   252  	}
   253  
   254  	By("waiting for assertion http chaos")
   255  	err = wait.PollImmediate(1*time.Second, 1*time.Minute, func() (bool, error) {
   256  		chaos := &v1alpha1.HTTPChaos{}
   257  		err = cli.Get(ctx, chaosKey, chaos)
   258  		framework.ExpectNoError(err, "get http chaos error")
   259  
   260  		for _, c := range chaos.GetStatus().Conditions {
   261  			if c.Type == v1alpha1.ConditionAllInjected {
   262  				if c.Status != corev1.ConditionTrue {
   263  					return false, nil
   264  				}
   265  			} else if c.Type == v1alpha1.ConditionSelected {
   266  				if c.Status != corev1.ConditionTrue {
   267  					return false, nil
   268  				}
   269  			}
   270  		}
   271  
   272  		resp, err := getPodHttp(c, port, secret, body)
   273  		if err != nil {
   274  			return false, err
   275  		}
   276  		defer resp.Body.Close()
   277  
   278  		s := strings.Join(resp.Header[SECRET], "; ")
   279  		b, err := io.ReadAll(resp.Body)
   280  		if err != nil {
   281  			return false, err
   282  		}
   283  
   284  		klog.Infof("Status(%d), Secret(%s), Body(%s)", resp.StatusCode, s, string(b))
   285  
   286  		if s == expectedSecret && string(b) == expectedBody {
   287  			return true, nil
   288  		}
   289  		return false, nil
   290  	})
   291  	framework.ExpectNoError(err, "http chaos doesn't work as expected")
   292  
   293  	By("pause http patch chaos experiment")
   294  	// pause experiment
   295  	err = util.PauseChaos(ctx, cli, httpChaos)
   296  	framework.ExpectNoError(err, "pause chaos error")
   297  
   298  	By("waiting for assertion about pause")
   299  	err = wait.Poll(1*time.Second, 1*time.Minute, func() (done bool, err error) {
   300  		chaos := &v1alpha1.HTTPChaos{}
   301  		err = cli.Get(ctx, chaosKey, chaos)
   302  		framework.ExpectNoError(err, "get http chaos error")
   303  
   304  		for _, c := range chaos.GetStatus().Conditions {
   305  			if c.Type == v1alpha1.ConditionAllRecovered {
   306  				if c.Status != corev1.ConditionTrue {
   307  					return false, nil
   308  				}
   309  			} else if c.Type == v1alpha1.ConditionSelected {
   310  				if c.Status != corev1.ConditionTrue {
   311  					return false, nil
   312  				}
   313  			}
   314  		}
   315  
   316  		return true, err
   317  	})
   318  	framework.ExpectNoError(err, "check paused chaos failed")
   319  
   320  	// wait 1 min to check whether io patch still exists
   321  	err = wait.PollImmediate(1*time.Second, 1*time.Minute, func() (bool, error) {
   322  		resp, err := getPodHttp(c, port, secret, body)
   323  		if err != nil {
   324  			return false, err
   325  		}
   326  		defer resp.Body.Close()
   327  
   328  		s := strings.Join(resp.Header[SECRET], "; ")
   329  		b, err := io.ReadAll(resp.Body)
   330  		if err != nil {
   331  			return false, err
   332  		}
   333  
   334  		klog.Infof("Status(%d), Secret(%s), Body(%s)", resp.StatusCode, s, string(b))
   335  
   336  		if s == secret && string(b) == body {
   337  			return true, nil
   338  		}
   339  		return false, nil
   340  	})
   341  	framework.ExpectNoError(err, "fail to recover http chaos")
   342  
   343  	By("resume http patch chaos experiment")
   344  	// resume experiment
   345  	err = util.UnPauseChaos(ctx, cli, httpChaos)
   346  	framework.ExpectNoError(err, "resume chaos error")
   347  
   348  	By("assert that http patch is effective again")
   349  	err = wait.Poll(1*time.Second, 1*time.Minute, func() (done bool, err error) {
   350  		chaos := &v1alpha1.HTTPChaos{}
   351  		err = cli.Get(ctx, chaosKey, chaos)
   352  		framework.ExpectNoError(err, "get http chaos error")
   353  
   354  		for _, c := range chaos.GetStatus().Conditions {
   355  			if c.Type == v1alpha1.ConditionAllInjected {
   356  				if c.Status != corev1.ConditionTrue {
   357  					return false, nil
   358  				}
   359  			} else if c.Type == v1alpha1.ConditionSelected {
   360  				if c.Status != corev1.ConditionTrue {
   361  					return false, nil
   362  				}
   363  			}
   364  		}
   365  
   366  		return true, err
   367  	})
   368  	framework.ExpectNoError(err, "check resumed chaos failed")
   369  
   370  	err = wait.PollImmediate(1*time.Second, 1*time.Minute, func() (bool, error) {
   371  		resp, err := getPodHttp(c, port, secret, body)
   372  		if err != nil {
   373  			return false, err
   374  		}
   375  		defer resp.Body.Close()
   376  
   377  		s := strings.Join(resp.Header[SECRET], "; ")
   378  		b, err := io.ReadAll(resp.Body)
   379  		if err != nil {
   380  			return false, err
   381  		}
   382  
   383  		klog.Infof("Status(%d), Secret(%s), Body(%s)", resp.StatusCode, s, string(b))
   384  
   385  		if s == expectedSecret && string(b) == expectedBody {
   386  			return true, nil
   387  		}
   388  		return false, nil
   389  	})
   390  	framework.ExpectNoError(err, "HTTP chaos doesn't work as expected")
   391  
   392  	By("cleanup")
   393  	// cleanup
   394  	cli.Delete(ctx, httpChaos)
   395  }
   396