...

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