1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package v1alpha1
17
18 import (
19 "fmt"
20 "reflect"
21 "testing"
22 "time"
23
24 corev1 "k8s.io/api/core/v1"
25 "k8s.io/apimachinery/pkg/util/validation/field"
26 )
27
28 func Test_entryMustExists(t *testing.T) {
29 entryPath := field.NewPath("spec", "entry")
30
31 type args struct {
32 path *field.Path
33 entry string
34 templates []Template
35 }
36 tests := []struct {
37 name string
38 args args
39 want field.ErrorList
40 }{
41 {
42 name: "entry is empty",
43 args: args{
44 path: entryPath,
45 entry: "",
46 templates: nil,
47 },
48 want: field.ErrorList{
49 field.Required(entryPath, "the entry of workflow is required"),
50 field.Invalid(entryPath, "", fmt.Sprintf("can not find a template with name %s", "")),
51 },
52 }, {
53 name: "entry does not exist in templates",
54 args: args{
55 path: entryPath,
56 entry: "entry",
57 templates: []Template{
58 {
59 Name: "whatever is not entry",
60 Type: TypeSuspend,
61 },
62 },
63 },
64 want: field.ErrorList{
65 field.Invalid(entryPath, "entry", fmt.Sprintf("can not find a template with name %s", "entry")),
66 },
67 },
68 }
69 for _, tt := range tests {
70 t.Run(tt.name, func(t *testing.T) {
71 if got := entryMustExists(tt.args.path, tt.args.entry, tt.args.templates); !reflect.DeepEqual(got, tt.want) {
72 t.Errorf("entryMustExists() = %v, want %v", got, tt.want)
73 }
74 })
75 }
76 }
77
78 func Test_validateTemplates(t *testing.T) {
79 templatesPath := field.NewPath("spec", "templates")
80 var nilTemplates []Template
81 type args struct {
82 path *field.Path
83 templates []Template
84 }
85 tests := []struct {
86 name string
87 args args
88 want field.ErrorList
89 }{
90 {
91 name: "templates is nil",
92 args: args{
93 path: templatesPath,
94 templates: nil,
95 },
96 want: field.ErrorList{
97 field.Invalid(templatesPath, nilTemplates, "templates in workflow could not be empty"),
98 },
99 }, {
100 name: "templates is empty",
101 args: args{
102 path: templatesPath,
103 templates: []Template{},
104 },
105 want: field.ErrorList{
106 field.Invalid(templatesPath, []Template{}, "templates in workflow could not be empty"),
107 },
108 },
109 }
110 for _, tt := range tests {
111 t.Run(tt.name, func(t *testing.T) {
112 if got := validateTemplates(tt.args.path, tt.args.templates); !reflect.DeepEqual(got, tt.want) {
113 t.Errorf("validateTemplates() = %v, want %v", got, tt.want)
114 }
115 })
116 }
117 }
118
119 func Test_shouldBeNoTask(t *testing.T) {
120 templatePath := field.NewPath("spec", "templates").Index(0)
121 mockTask := Task{
122 Container: &corev1.Container{Name: "fake-container"},
123 }
124 type args struct {
125 path *field.Path
126 template Template
127 }
128 tests := []struct {
129 name string
130 args args
131 want field.ErrorList
132 }{
133 {
134 name: "contains unexpected task",
135 args: args{
136 path: templatePath,
137 template: Template{
138 Task: &mockTask,
139 },
140 },
141 want: field.ErrorList{
142 field.Invalid(templatePath, &mockTask, "this template should not contain Task"),
143 },
144 }, {
145 name: "does not contain task",
146 args: args{
147 path: templatePath,
148 template: Template{},
149 },
150 want: nil,
151 },
152 }
153 for _, tt := range tests {
154 t.Run(tt.name, func(t *testing.T) {
155 if got := shouldBeNoTask(tt.args.path, tt.args.template); !reflect.DeepEqual(got, tt.want) {
156 t.Errorf("shouldBeNoTask() = %v, want %v", got, tt.want)
157 }
158 })
159 }
160 }
161
162 func Test_shouldBeNoChildren(t *testing.T) {
163 templatePath := field.NewPath("spec", "templates").Index(0)
164 mockChildren := []string{"child-a", "child-b"}
165 type args struct {
166 path *field.Path
167 template Template
168 }
169 tests := []struct {
170 name string
171 args args
172 want field.ErrorList
173 }{
174 {
175 name: "contains unexpected children",
176 args: args{
177 path: templatePath,
178 template: Template{
179 Children: mockChildren,
180 },
181 },
182 want: field.ErrorList{
183 field.Invalid(templatePath, mockChildren, "this template should not contain Children"),
184 },
185 }, {
186 name: "does not contain children",
187 args: args{
188 path: templatePath,
189 template: Template{},
190 },
191 want: nil,
192 }, {
193 name: "empty array is also valid",
194 args: args{
195 path: templatePath,
196 template: Template{
197 Children: []string{},
198 },
199 },
200 want: nil,
201 },
202 }
203 for _, tt := range tests {
204 t.Run(tt.name, func(t *testing.T) {
205 if got := shouldBeNoChildren(tt.args.path, tt.args.template); !reflect.DeepEqual(got, tt.want) {
206 t.Errorf("shouldBeNoChildren() = %v, want %v", got, tt.want)
207 }
208 })
209 }
210 }
211
212 func Test_shouldBeNoConditionalBranches(t *testing.T) {
213 templatePath := field.NewPath("spec", "templates").Index(0)
214 mockConditionalBranches := []ConditionalBranch{
215 {Target: "", Expression: ""},
216 }
217 type args struct {
218 path *field.Path
219 template Template
220 }
221 tests := []struct {
222 name string
223 args args
224 want field.ErrorList
225 }{
226 {
227 name: "contains unexpected conditional branches",
228 args: args{
229 path: templatePath,
230 template: Template{
231 ConditionalBranches: mockConditionalBranches,
232 },
233 },
234 want: field.ErrorList{
235 field.Invalid(templatePath, mockConditionalBranches, "this template should not contain ConditionalBranches"),
236 },
237 }, {
238 name: "does not contain conditional branches",
239 args: args{
240 path: templatePath,
241 template: Template{},
242 },
243 want: nil,
244 }, {
245 name: "empty array is also valid",
246 args: args{
247 path: templatePath,
248 template: Template{
249 ConditionalBranches: []ConditionalBranch{},
250 },
251 },
252 want: nil,
253 },
254 }
255 for _, tt := range tests {
256 t.Run(tt.name, func(t *testing.T) {
257 if got := shouldBeNoConditionalBranches(tt.args.path, tt.args.template); !reflect.DeepEqual(got, tt.want) {
258 t.Errorf("shouldBeNoConditionalBranches() = %v, want %v", got, tt.want)
259 }
260 })
261 }
262 }
263
264 func Test_shouldBeNoEmbedChaos(t *testing.T) {
265 templatePath := field.NewPath("spec", "templates").Index(0)
266 type args struct {
267 path *field.Path
268 template Template
269 }
270 mockedEmbedChaos := &EmbedChaos{
271 PodChaos: &PodChaosSpec{
272 ContainerSelector: ContainerSelector{
273 PodSelector: PodSelector{
274 Selector: PodSelectorSpec{
275 GenericSelectorSpec: GenericSelectorSpec{
276 Namespaces: []string{"default"},
277 },
278 },
279 },
280 },
281 Action: PodKillAction,
282 },
283 }
284 tests := []struct {
285 name string
286 args args
287 want field.ErrorList
288 }{
289 {
290 name: "unexpected embedded chaos",
291 args: args{
292 path: templatePath,
293 template: Template{
294 EmbedChaos: mockedEmbedChaos,
295 },
296 },
297 want: field.ErrorList{
298 field.Invalid(templatePath, mockedEmbedChaos, "this template should not contain any Chaos"),
299 },
300 }, {
301 name: "only nil embedded chaos is valid",
302 args: args{
303 path: templatePath,
304 template: Template{
305 EmbedChaos: nil,
306 },
307 },
308 want: nil,
309 }, {
310 name: "an embedded chaos with all the nil fields is also INVALID",
311 args: args{
312 path: templatePath,
313 template: Template{
314 EmbedChaos: &EmbedChaos{},
315 },
316 },
317 want: field.ErrorList{
318 field.Invalid(templatePath, &EmbedChaos{}, "this template should not contain any Chaos"),
319 },
320 },
321 }
322 for _, tt := range tests {
323 t.Run(tt.name, func(t *testing.T) {
324 if got := shouldBeNoEmbedChaos(tt.args.path, tt.args.template); !reflect.DeepEqual(got, tt.want) {
325 t.Errorf("shouldBeNoEmbedChaos() = %v, want %v", got, tt.want)
326 }
327 })
328 }
329 }
330
331 func Test_shouldBeNoSchedule(t *testing.T) {
332 templatePath := field.NewPath("spec", "templates").Index(0)
333 type args struct {
334 path *field.Path
335 template Template
336 }
337 mockedSchedule := &ChaosOnlyScheduleSpec{
338 Type: ScheduleTypePodChaos,
339 }
340 tests := []struct {
341 name string
342 args args
343 want field.ErrorList
344 }{
345 {
346 name: "unexpected schedule",
347 args: args{
348 path: templatePath,
349 template: Template{
350 Schedule: mockedSchedule,
351 },
352 },
353 want: field.ErrorList{
354 field.Invalid(templatePath, mockedSchedule, "this template should not contain Schedule"),
355 },
356 }, {
357 name: "no schedule",
358 args: args{
359 path: templatePath,
360 template: Template{
361 Schedule: nil,
362 },
363 },
364 want: nil,
365 },
366 }
367 for _, tt := range tests {
368 t.Run(tt.name, func(t *testing.T) {
369 if got := shouldBeNoSchedule(tt.args.path, tt.args.template); !reflect.DeepEqual(got, tt.want) {
370 t.Errorf("shouldBeNoSchedule() = %v, want %v", got, tt.want)
371 }
372 })
373 }
374 }
375
376 func Test_namesCouldNotBeDuplicated(t *testing.T) {
377 templatesPath := field.NewPath("spec", "templates")
378 type args struct {
379 templatesPath *field.Path
380 names []string
381 }
382 tests := []struct {
383 name string
384 args args
385 want field.ErrorList
386 }{
387 {
388 name: "names could not be duplicated",
389 args: args{
390 templatesPath: templatesPath,
391 names: []string{"template-a", "template-b", "template-c", "template-a", "template-b", "template-d"},
392 },
393 want: field.ErrorList{
394 field.Invalid(templatesPath, "", fmt.Sprintf("template name must be unique, duplicated names: %s", []string{"template-a", "template-b"})),
395 },
396 }, {
397 name: "names could not be duplicated",
398 args: args{
399 templatesPath: templatesPath,
400 names: []string{"template-a", "template-b", "template-c", "template-d"},
401 },
402 want: nil,
403 },
404 }
405 for _, tt := range tests {
406 t.Run(tt.name, func(t *testing.T) {
407 if got := namesCouldNotBeDuplicated(tt.args.templatesPath, tt.args.names); !reflect.DeepEqual(got, tt.want) {
408 t.Errorf("namesCouldNotBeDuplicated() = %v, want %v", got, tt.want)
409 }
410 })
411 }
412 }
413
414 func Test_shouldNotSetupDurationInTheChaos(t *testing.T) {
415 templatesPath := field.NewPath("spec", "templates")
416 duration20sString := "20s"
417 duration20s := 20 * time.Second
418
419 type args struct {
420 path *field.Path
421 template Template
422 }
423 tests := []struct {
424 name string
425 args args
426 want field.ErrorList
427 }{
428 {
429 name: "should return error when embed chaos is not set",
430 args: args{
431 path: templatesPath,
432 template: Template{
433 Name: "invalid-pod-chaos",
434 Type: TypePodChaos,
435 EmbedChaos: nil,
436 },
437 },
438 want: field.ErrorList{
439 field.Invalid(templatesPath.Child(string(TypePodChaos)), nil, fmt.Sprintf("the value of chaos %s is required", string(TypePodChaos))),
440 },
441 },
442 {
443 name: "should not set duration in the chaos",
444 args: args{
445 path: templatesPath,
446 template: Template{
447 Name: "invalid-pod-chaos",
448 Type: TypePodChaos,
449 EmbedChaos: &EmbedChaos{
450 PodChaos: &PodChaosSpec{
451 Duration: &duration20sString,
452 },
453 },
454 },
455 },
456 want: field.ErrorList{
457 field.Invalid(templatesPath, &duration20s, "should not define duration in chaos when using Workflow, use Template#Deadline instead."),
458 },
459 }, {
460 name: "should set duration in the template",
461 args: args{
462 path: templatesPath,
463 template: Template{
464 Name: "invalid-pod-chaos",
465 Type: TypePodChaos,
466 Deadline: &duration20sString,
467 EmbedChaos: &EmbedChaos{
468 PodChaos: &PodChaosSpec{},
469 },
470 },
471 },
472 want: nil,
473 },
474 }
475 for _, tt := range tests {
476 t.Run(tt.name, func(t *testing.T) {
477 if got := shouldNotSetupDurationInTheChaos(tt.args.path, tt.args.template); !reflect.DeepEqual(got, tt.want) {
478 t.Errorf("shouldNotSetupDurationInTheChaos() = %v, want %v", got, tt.want)
479 }
480 })
481 }
482 }
483