1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package schedule
17
18 import (
19 "context"
20 "time"
21
22 . "github.com/onsi/ginkgo"
23 . "github.com/onsi/gomega"
24 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
25 "k8s.io/apimachinery/pkg/types"
26 "k8s.io/apimachinery/pkg/util/wait"
27 ctrl "sigs.k8s.io/controller-runtime"
28
29 "github.com/chaos-mesh/chaos-mesh/api/v1alpha1"
30 )
31
32
33
34
35 var _ = Describe("Schedule", func() {
36
37 BeforeEach(func() {
38
39 })
40
41 AfterEach(func() {
42
43 })
44
45 Context(("Schedule basic"), func() {
46 It(("Should be created and deleted successfully"), func() {
47 key := types.NamespacedName{
48 Name: "foo0",
49 Namespace: "default",
50 }
51 duration := "100m"
52 schedule := &v1alpha1.Schedule{
53 ObjectMeta: metav1.ObjectMeta{
54 Name: "foo0",
55 Namespace: "default",
56 },
57 Spec: v1alpha1.ScheduleSpec{
58 Schedule: "@every 10s",
59 ScheduleItem: v1alpha1.ScheduleItem{
60 EmbedChaos: v1alpha1.EmbedChaos{TimeChaos: &v1alpha1.TimeChaosSpec{
61 TimeOffset: "100ms",
62 ClockIds: []string{"CLOCK_REALTIME"},
63 Duration: &duration,
64 ContainerSelector: v1alpha1.ContainerSelector{
65 PodSelector: v1alpha1.PodSelector{
66 Mode: v1alpha1.OneMode,
67 },
68 },
69 }},
70 },
71 ConcurrencyPolicy: v1alpha1.ForbidConcurrent,
72 HistoryLimit: 5,
73 Type: v1alpha1.ScheduleTypeTimeChaos,
74 },
75 Status: v1alpha1.ScheduleStatus{
76 LastScheduleTime: metav1.NewTime(time.Time{}),
77 },
78 }
79
80 By("creating an API obj")
81 Expect(k8sClient.Create(context.TODO(), schedule)).To(Succeed())
82
83 fetched := &v1alpha1.Schedule{}
84 Expect(k8sClient.Get(context.TODO(), key, fetched)).To(Succeed())
85 Expect(fetched).To(Equal(schedule))
86
87 By("deleting the created object")
88 Expect(k8sClient.Delete(context.TODO(), schedule)).To(Succeed())
89 Expect(k8sClient.Get(context.TODO(), key, schedule)).ToNot(Succeed())
90 })
91 })
92
93 Context("Schedule cron", func() {
94 It("should create non-concurrent chaos", func() {
95 key := types.NamespacedName{
96 Name: "foo1",
97 Namespace: "default",
98 }
99 duration := "100s"
100 schedule := &v1alpha1.Schedule{
101 ObjectMeta: metav1.ObjectMeta{
102 Name: "foo1",
103 Namespace: "default",
104 },
105 Spec: v1alpha1.ScheduleSpec{
106 Schedule: "@every 1s",
107 ScheduleItem: v1alpha1.ScheduleItem{
108 EmbedChaos: v1alpha1.EmbedChaos{TimeChaos: &v1alpha1.TimeChaosSpec{
109 TimeOffset: "100ms",
110 ClockIds: []string{"CLOCK_REALTIME"},
111 Duration: &duration,
112 ContainerSelector: v1alpha1.ContainerSelector{
113 PodSelector: v1alpha1.PodSelector{
114 Mode: v1alpha1.OneMode,
115 },
116 },
117 }},
118 },
119 ConcurrencyPolicy: v1alpha1.ForbidConcurrent,
120 HistoryLimit: 2,
121 Type: v1alpha1.ScheduleTypeTimeChaos,
122 },
123 Status: v1alpha1.ScheduleStatus{
124 LastScheduleTime: metav1.NewTime(time.Now()),
125 },
126 }
127
128 By("creating a schedule obj")
129 {
130 Expect(k8sClient.Create(context.TODO(), schedule)).To(Succeed())
131 }
132
133 By("Reconciling the created schedule obj")
134 {
135 err := wait.Poll(time.Second*1, time.Minute*1, func() (ok bool, err error) {
136 err = k8sClient.Get(context.TODO(), key, schedule)
137 if err != nil {
138 return false, err
139 }
140 return len(schedule.Status.Active) > 0, nil
141 })
142 Expect(err).ToNot(HaveOccurred())
143 }
144
145 By("Disallow concurrency")
146 {
147 time.Sleep(5 * time.Second)
148 err := k8sClient.Get(context.TODO(), key, schedule)
149 Expect(err).ToNot(HaveOccurred())
150 Expect(len(schedule.Status.Active)).To(Equal(1))
151 }
152
153 By("deleting the created object")
154 {
155 Expect(k8sClient.Delete(context.TODO(), schedule)).To(Succeed())
156 Expect(k8sClient.Get(context.TODO(), key, schedule)).ToNot(Succeed())
157 }
158 })
159 It("should create concurrent chaos", func() {
160 key := types.NamespacedName{
161 Name: "foo2",
162 Namespace: "default",
163 }
164 duration := "100s"
165 schedule := &v1alpha1.Schedule{
166 ObjectMeta: metav1.ObjectMeta{
167 Name: "foo2",
168 Namespace: "default",
169 },
170 Spec: v1alpha1.ScheduleSpec{
171 Schedule: "@every 2s",
172 ScheduleItem: v1alpha1.ScheduleItem{
173 EmbedChaos: v1alpha1.EmbedChaos{TimeChaos: &v1alpha1.TimeChaosSpec{
174 TimeOffset: "100ms",
175 ClockIds: []string{"CLOCK_REALTIME"},
176 Duration: &duration,
177 ContainerSelector: v1alpha1.ContainerSelector{
178 PodSelector: v1alpha1.PodSelector{
179 Mode: v1alpha1.OneMode,
180 },
181 },
182 }},
183 },
184 ConcurrencyPolicy: v1alpha1.AllowConcurrent,
185 HistoryLimit: 2,
186 Type: v1alpha1.ScheduleTypeTimeChaos,
187 },
188 Status: v1alpha1.ScheduleStatus{
189 LastScheduleTime: metav1.NewTime(time.Now()),
190 },
191 }
192
193 By("creating a schedule obj")
194 {
195 Expect(k8sClient.Create(context.TODO(), schedule)).To(Succeed())
196 }
197
198 By("Allowing concurrency and skip deleting running chaos")
199 {
200 err := wait.Poll(5*time.Second, 1*time.Minute, func() (done bool, err error) {
201 err = k8sClient.Get(context.TODO(), key, schedule)
202 if err != nil {
203 return false, err
204 }
205 ctrl.Log.Info("active chaos", "size", len(schedule.Status.Active))
206 return len(schedule.Status.Active) >= 4, nil
207 })
208 Expect(err).ToNot(HaveOccurred())
209 }
210
211 By("deleting the created object")
212 {
213 Expect(k8sClient.Delete(context.TODO(), schedule)).To(Succeed())
214 Expect(k8sClient.Get(context.TODO(), key, schedule)).ToNot(Succeed())
215 }
216 })
217 It("should collect garbage", func() {
218 key := types.NamespacedName{
219 Name: "foo3",
220 Namespace: "default",
221 }
222 duration := "1s"
223 schedule := &v1alpha1.Schedule{
224 ObjectMeta: metav1.ObjectMeta{
225 Name: "foo3",
226 Namespace: "default",
227 },
228 Spec: v1alpha1.ScheduleSpec{
229 Schedule: "@every 3s",
230 ScheduleItem: v1alpha1.ScheduleItem{
231 EmbedChaos: v1alpha1.EmbedChaos{TimeChaos: &v1alpha1.TimeChaosSpec{
232 TimeOffset: "100ms",
233 ClockIds: []string{"CLOCK_REALTIME"},
234 Duration: &duration,
235 ContainerSelector: v1alpha1.ContainerSelector{
236 PodSelector: v1alpha1.PodSelector{
237 Mode: v1alpha1.OneMode,
238 },
239 },
240 }},
241 },
242 ConcurrencyPolicy: v1alpha1.AllowConcurrent,
243 HistoryLimit: 2,
244 Type: v1alpha1.ScheduleTypeTimeChaos,
245 },
246 Status: v1alpha1.ScheduleStatus{
247 LastScheduleTime: metav1.NewTime(time.Now()),
248 },
249 }
250
251 By("creating a schedule obj")
252 {
253 Expect(k8sClient.Create(context.TODO(), schedule)).To(Succeed())
254 }
255
256 By("deleting outdated chaos")
257 {
258 time.Sleep(time.Second * 10)
259 err := wait.Poll(5*time.Second, 1*time.Minute, func() (done bool, err error) {
260 err = k8sClient.Get(context.TODO(), key, schedule)
261 if err != nil {
262 return false, err
263 }
264 ctrl.Log.Info("active chaos", "size", len(schedule.Status.Active))
265 return len(schedule.Status.Active) == 2, nil
266 })
267 Expect(err).ToNot(HaveOccurred())
268 }
269
270 By("deleting the created object")
271 {
272 Expect(k8sClient.Delete(context.TODO(), schedule)).To(Succeed())
273 Expect(k8sClient.Get(context.TODO(), key, schedule)).ToNot(Succeed())
274 }
275 })
276 })
277
278 Context(("Schedule workflow"), func() {
279 It(("Should forbid concurrent"), func() {
280 key := types.NamespacedName{
281 Name: "foo10",
282 Namespace: "default",
283 }
284 duration := "10000s"
285 schedule := &v1alpha1.Schedule{
286 ObjectMeta: metav1.ObjectMeta{
287 Name: "foo10",
288 Namespace: "default",
289 },
290 Spec: v1alpha1.ScheduleSpec{
291 Schedule: "@every 3s",
292 ScheduleItem: v1alpha1.ScheduleItem{
293 Workflow: &v1alpha1.WorkflowSpec{
294 Entry: "the-entry",
295 Templates: []v1alpha1.Template{
296 {
297 Name: "the-entry",
298 Type: v1alpha1.TypeSerial,
299 Deadline: &duration,
300 Children: []string{"hardwork"},
301 },
302 {
303 Name: "hardwork",
304 Type: v1alpha1.TypeSuspend,
305 Deadline: &duration,
306 Children: nil,
307 },
308 },
309 },
310 },
311 ConcurrencyPolicy: v1alpha1.ForbidConcurrent,
312 HistoryLimit: 2,
313 Type: v1alpha1.ScheduleTypeWorkflow,
314 },
315 Status: v1alpha1.ScheduleStatus{
316 LastScheduleTime: metav1.NewTime(time.Time{}),
317 },
318 }
319
320 By("creating a schedule obj")
321 {
322 Expect(k8sClient.Create(context.TODO(), schedule)).To(Succeed())
323 }
324
325 By("disallowing concurrent")
326 {
327 time.Sleep(time.Second * 10)
328 err := wait.Poll(5*time.Second, 1*time.Minute, func() (done bool, err error) {
329 err = k8sClient.Get(context.TODO(), key, schedule)
330 if err != nil {
331 return false, err
332 }
333 ctrl.Log.Info("active chaos", "size", len(schedule.Status.Active))
334 return len(schedule.Status.Active) == 1, nil
335 })
336 Expect(err).ToNot(HaveOccurred())
337 }
338
339 By("deleting the created object")
340 {
341 Expect(k8sClient.Delete(context.TODO(), schedule)).To(Succeed())
342 Expect(k8sClient.Get(context.TODO(), key, schedule)).ToNot(Succeed())
343 }
344 })
345
346 It(("Should be garbage collected successfully"), func() {
347 key := types.NamespacedName{
348 Name: "foo11",
349 Namespace: "default",
350 }
351 duration := "1s"
352 schedule := &v1alpha1.Schedule{
353 ObjectMeta: metav1.ObjectMeta{
354 Name: "foo11",
355 Namespace: "default",
356 },
357 Spec: v1alpha1.ScheduleSpec{
358 Schedule: "@every 3s",
359 ScheduleItem: v1alpha1.ScheduleItem{
360 Workflow: &v1alpha1.WorkflowSpec{
361 Entry: "the-entry",
362 Templates: []v1alpha1.Template{
363 {
364 Name: "the-entry",
365 Type: v1alpha1.TypeSerial,
366 Deadline: &duration,
367 Children: nil,
368 },
369 },
370 },
371 },
372 ConcurrencyPolicy: v1alpha1.AllowConcurrent,
373 HistoryLimit: 2,
374 Type: v1alpha1.ScheduleTypeWorkflow,
375 },
376 Status: v1alpha1.ScheduleStatus{
377 LastScheduleTime: metav1.NewTime(time.Time{}),
378 },
379 }
380
381 By("creating a schedule obj")
382 {
383 Expect(k8sClient.Create(context.TODO(), schedule)).To(Succeed())
384 }
385
386 By("deleting outdated workflow")
387 {
388 time.Sleep(time.Second * 10)
389 err := wait.Poll(5*time.Second, 1*time.Minute, func() (done bool, err error) {
390 err = k8sClient.Get(context.TODO(), key, schedule)
391 if err != nil {
392 return false, err
393 }
394 ctrl.Log.Info("active chaos", "size", len(schedule.Status.Active))
395 return len(schedule.Status.Active) == 2, nil
396 })
397 Expect(err).ToNot(HaveOccurred())
398 }
399
400 By("deleting the created object")
401 {
402 Expect(k8sClient.Delete(context.TODO(), schedule)).To(Succeed())
403 Expect(k8sClient.Get(context.TODO(), key, schedule)).ToNot(Succeed())
404 }
405 })
406 })
407 })
408