1
2
3
4
5
6
7
8
9
10
11
12
13
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
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
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
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
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
395 cli.Delete(ctx, httpChaos)
396 }
397