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"
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
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
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
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
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
394 cli.Delete(ctx, httpChaos)
395 }
396