1 package devstate
2
3 import (
4 "testing"
5
6 "github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2"
7 "github.com/google/go-cmp/cmp"
8 . "github.com/redhat-developer/odo/pkg/apiserver-gen/go"
9 openapi "github.com/redhat-developer/odo/pkg/apiserver-gen/go"
10 )
11
12 func TestDevfileState_AddExecCommand(t *testing.T) {
13 type args struct {
14 name string
15 component string
16 commandLine string
17 workingDir string
18 hotReloadCapable bool
19 }
20 tests := []struct {
21 name string
22 state func() DevfileState
23 args args
24 want DevfileContent
25 wantErr bool
26 }{
27 {
28 name: "Add an exec command",
29 state: func() DevfileState {
30 state := NewDevfileState()
31 _, err := state.AddContainer(
32 "a-container",
33 "an-image",
34 []string{"run", "command"},
35 []string{"arg1", "arg2"},
36 nil,
37 "1Gi",
38 "2Gi",
39 "100m",
40 "200m",
41 nil,
42 true,
43 true,
44 "",
45 openapi.Annotation{},
46 nil,
47 )
48 if err != nil {
49 t.Fatal(err)
50 }
51 return state
52 },
53 args: args{
54 name: "an-exec-command",
55 component: "a-container",
56 commandLine: "run command",
57 workingDir: "/path/to/work",
58 hotReloadCapable: true,
59 },
60 want: DevfileContent{
61 Content: `commands:
62 - exec:
63 commandLine: run command
64 component: a-container
65 hotReloadCapable: true
66 workingDir: /path/to/work
67 id: an-exec-command
68 components:
69 - container:
70 args:
71 - arg1
72 - arg2
73 command:
74 - run
75 - command
76 cpuLimit: 200m
77 cpuRequest: 100m
78 image: an-image
79 memoryLimit: 2Gi
80 memoryRequest: 1Gi
81 mountSources: true
82 name: a-container
83 metadata: {}
84 schemaVersion: 2.2.0
85 `,
86 Version: "2.2.0",
87 Commands: []Command{
88 {
89 Name: "an-exec-command",
90 Type: "exec",
91 Exec: ExecCommand{
92 Component: "a-container",
93 CommandLine: "run command",
94 WorkingDir: "/path/to/work",
95 HotReloadCapable: true,
96 },
97 },
98 },
99 Containers: []Container{
100 {
101 Name: "a-container",
102 Image: "an-image",
103 Command: []string{"run", "command"},
104 Args: []string{"arg1", "arg2"},
105 MemoryRequest: "1Gi",
106 MemoryLimit: "2Gi",
107 CpuRequest: "100m",
108 CpuLimit: "200m",
109 VolumeMounts: []openapi.VolumeMount{},
110 Endpoints: []openapi.Endpoint{},
111 Env: []openapi.Env{},
112 ConfigureSources: true,
113 MountSources: true,
114 },
115 },
116 Images: []Image{},
117 Resources: []Resource{},
118 Volumes: []Volume{},
119 Events: Events{},
120 },
121 },
122
123 }
124 for _, tt := range tests {
125 t.Run(tt.name, func(t *testing.T) {
126 o := tt.state()
127 got, err := o.AddExecCommand(tt.args.name, tt.args.component, tt.args.commandLine, tt.args.workingDir, tt.args.hotReloadCapable)
128 if (err != nil) != tt.wantErr {
129 t.Errorf("DevfileState.AddExecCommand() error = %v, wantErr %v", err, tt.wantErr)
130 return
131 }
132 if diff := cmp.Diff(tt.want.Content, got.Content); diff != "" {
133 t.Errorf("DevfileState.AddExecCommand() mismatch (-want +got):\n%s", diff)
134 }
135 if diff := cmp.Diff(tt.want, got); diff != "" {
136 t.Errorf("DevfileState.AddExecCommand() mismatch (-want +got):\n%s", diff)
137 }
138 })
139 }
140 }
141
142 func TestDevfileState_AddApplyCommand(t *testing.T) {
143 type args struct {
144 name string
145 component string
146 }
147 tests := []struct {
148 name string
149 state func() DevfileState
150 args args
151 want DevfileContent
152 wantErr bool
153 }{
154 {
155 name: "Add an Apply command",
156 state: func() DevfileState {
157 state := NewDevfileState()
158 _, err := state.AddImage(
159 "an-image",
160 "an-image-name",
161 nil, "/context", false, "", "undefined",
162 )
163 if err != nil {
164 t.Fatal(err)
165 }
166 return state
167 },
168 args: args{
169 name: "an-apply-command",
170 component: "an-image",
171 },
172 want: DevfileContent{
173 Content: `commands:
174 - apply:
175 component: an-image
176 id: an-apply-command
177 components:
178 - image:
179 dockerfile:
180 buildContext: /context
181 rootRequired: false
182 imageName: an-image-name
183 name: an-image
184 metadata: {}
185 schemaVersion: 2.2.0
186 `,
187 Version: "2.2.0",
188 Commands: []Command{
189 {
190 Name: "an-apply-command",
191 Type: "image",
192 Image: ImageCommand{
193 Component: "an-image",
194 },
195 },
196 },
197 Containers: []Container{},
198 Images: []Image{
199 {
200 Name: "an-image",
201 ImageName: "an-image-name",
202 BuildContext: "/context",
203 AutoBuild: "undefined",
204 },
205 },
206 Resources: []Resource{},
207 Volumes: []Volume{},
208 Events: Events{},
209 },
210 },
211
212 }
213 for _, tt := range tests {
214 t.Run(tt.name, func(t *testing.T) {
215 o := tt.state()
216 got, err := o.AddApplyCommand(tt.args.name, tt.args.component)
217 if (err != nil) != tt.wantErr {
218 t.Errorf("DevfileState.AddApplyCommand() error = %v, wantErr %v", err, tt.wantErr)
219 return
220 }
221 if diff := cmp.Diff(tt.want.Content, got.Content); diff != "" {
222 t.Errorf("DevfileState.AddApplyCommand() mismatch (-want +got):\n%s", diff)
223 }
224 if diff := cmp.Diff(tt.want, got); diff != "" {
225 t.Errorf("DevfileState.AddApplyCommand() mismatch (-want +got):\n%s", diff)
226 }
227 })
228 }
229 }
230
231 func TestDevfileState_AddCompositeCommand(t *testing.T) {
232 type args struct {
233 name string
234 parallel bool
235 commands []string
236 }
237 tests := []struct {
238 name string
239 state func() DevfileState
240 args args
241 want DevfileContent
242 wantErr bool
243 }{
244 {
245 name: "Add an Apply command",
246 state: func() DevfileState {
247 state := NewDevfileState()
248 _, err := state.AddContainer(
249 "a-container",
250 "an-image",
251 []string{"run", "command"},
252 []string{"arg1", "arg2"},
253 nil,
254 "1Gi",
255 "2Gi",
256 "100m",
257 "200m",
258 nil,
259 true,
260 true,
261 "",
262 openapi.Annotation{},
263 nil,
264 )
265 if err != nil {
266 t.Fatal(err)
267 }
268 _, err = state.AddExecCommand(
269 "an-exec-command",
270 "a-container",
271 "run command",
272 "/path/to/work",
273 true,
274 )
275 if err != nil {
276 t.Fatal(err)
277 }
278 return state
279 },
280 args: args{
281 name: "a-composite-command",
282 parallel: true,
283 commands: []string{"an-exec-command"},
284 },
285 want: DevfileContent{
286 Content: `commands:
287 - exec:
288 commandLine: run command
289 component: a-container
290 hotReloadCapable: true
291 workingDir: /path/to/work
292 id: an-exec-command
293 - composite:
294 commands:
295 - an-exec-command
296 parallel: true
297 id: a-composite-command
298 components:
299 - container:
300 args:
301 - arg1
302 - arg2
303 command:
304 - run
305 - command
306 cpuLimit: 200m
307 cpuRequest: 100m
308 image: an-image
309 memoryLimit: 2Gi
310 memoryRequest: 1Gi
311 mountSources: true
312 name: a-container
313 metadata: {}
314 schemaVersion: 2.2.0
315 `,
316 Version: "2.2.0",
317 Commands: []Command{
318 {
319 Name: "an-exec-command",
320 Type: "exec",
321 Exec: ExecCommand{
322 Component: "a-container",
323 CommandLine: "run command",
324 WorkingDir: "/path/to/work",
325 HotReloadCapable: true,
326 },
327 },
328 {
329 Name: "a-composite-command",
330 Type: "composite",
331 Composite: CompositeCommand{Commands: []string{"an-exec-command"}, Parallel: true},
332 },
333 },
334 Containers: []Container{
335 {
336 Name: "a-container",
337 Image: "an-image",
338 Command: []string{"run", "command"},
339 Args: []string{"arg1", "arg2"},
340 MemoryRequest: "1Gi",
341 MemoryLimit: "2Gi",
342 CpuRequest: "100m",
343 CpuLimit: "200m",
344 VolumeMounts: []openapi.VolumeMount{},
345 Endpoints: []openapi.Endpoint{},
346 Env: []openapi.Env{},
347 ConfigureSources: true,
348 MountSources: true,
349 },
350 },
351 Images: []Image{},
352 Resources: []Resource{},
353 Volumes: []Volume{},
354 Events: Events{},
355 },
356 },
357
358 }
359 for _, tt := range tests {
360 t.Run(tt.name, func(t *testing.T) {
361 o := tt.state()
362 got, err := o.AddCompositeCommand(tt.args.name, tt.args.parallel, tt.args.commands)
363 if (err != nil) != tt.wantErr {
364 t.Errorf("DevfileState.AddApplyCommand() error = %v, wantErr %v", err, tt.wantErr)
365 return
366 }
367 if diff := cmp.Diff(tt.want.Content, got.Content); diff != "" {
368 t.Errorf("DevfileState.AddApplyCommand() mismatch (-want +got):\n%s", diff)
369 }
370 if diff := cmp.Diff(tt.want, got); diff != "" {
371 t.Errorf("DevfileState.AddApplyCommand() mismatch (-want +got):\n%s", diff)
372 }
373 })
374 }
375 }
376
377 func TestDevfileState_DeleteCommand(t *testing.T) {
378 type args struct {
379 name string
380 }
381 tests := []struct {
382 name string
383 state func(t *testing.T) DevfileState
384 args args
385 want DevfileContent
386 wantErr bool
387 }{
388 {
389 name: "Delete an existing command",
390 state: func(t *testing.T) DevfileState {
391 state := NewDevfileState()
392 _, err := state.AddContainer(
393 "a-container",
394 "an-image",
395 []string{"run", "command"},
396 []string{"arg1", "arg2"},
397 nil,
398 "1Gi",
399 "2Gi",
400 "100m",
401 "200m",
402 nil,
403 true,
404 true,
405 "",
406 openapi.Annotation{},
407 nil,
408 )
409 if err != nil {
410 t.Fatal(err)
411 }
412 _, err = state.AddExecCommand(
413 "an-exec-command",
414 "a-container",
415 "run command",
416 "/path/to/work",
417 true,
418 )
419 if err != nil {
420 t.Fatal(err)
421 }
422 return state
423 },
424 args: args{
425 name: "an-exec-command",
426 },
427 want: DevfileContent{
428 Content: `components:
429 - container:
430 args:
431 - arg1
432 - arg2
433 command:
434 - run
435 - command
436 cpuLimit: 200m
437 cpuRequest: 100m
438 image: an-image
439 memoryLimit: 2Gi
440 memoryRequest: 1Gi
441 mountSources: true
442 name: a-container
443 metadata: {}
444 schemaVersion: 2.2.0
445 `,
446 Version: "2.2.0",
447 Commands: []Command{},
448 Containers: []Container{
449 {
450 Name: "a-container",
451 Image: "an-image",
452 Command: []string{"run", "command"},
453 Args: []string{"arg1", "arg2"},
454 MemoryRequest: "1Gi",
455 MemoryLimit: "2Gi",
456 CpuRequest: "100m",
457 CpuLimit: "200m",
458 VolumeMounts: []openapi.VolumeMount{},
459 Endpoints: []openapi.Endpoint{},
460 Env: []openapi.Env{},
461 ConfigureSources: true,
462 MountSources: true,
463 },
464 },
465 Images: []Image{},
466 Resources: []Resource{},
467 Volumes: []Volume{},
468 Events: Events{},
469 },
470 },
471 {
472 name: "Delete a non existing command",
473 state: func(t *testing.T) DevfileState {
474 state := NewDevfileState()
475 return state
476 },
477 args: args{
478 name: "another-name",
479 },
480 want: DevfileContent{},
481 wantErr: true,
482 },
483
484 }
485 for _, tt := range tests {
486 t.Run(tt.name, func(t *testing.T) {
487 o := tt.state(t)
488 got, err := o.DeleteCommand(tt.args.name)
489 if (err != nil) != tt.wantErr {
490 t.Errorf("DevfileState.DeleteCommand() error = %v, wantErr %v", err, tt.wantErr)
491 return
492 }
493 if diff := cmp.Diff(tt.want.Content, got.Content); diff != "" {
494 t.Errorf("DevfileState.DeleteCommand() mismatch (-want +got):\n%s", diff)
495 }
496 if diff := cmp.Diff(tt.want, got); diff != "" {
497 t.Errorf("DevfileState.DeleteCommand() mismatch (-want +got):\n%s", diff)
498 }
499 })
500 }
501 }
502
503 func newCommand(group string, id string) v1alpha2.Command {
504 return v1alpha2.Command{
505 Id: id,
506 CommandUnion: v1alpha2.CommandUnion{
507 Exec: &v1alpha2.ExecCommand{
508 LabeledCommand: v1alpha2.LabeledCommand{
509 BaseCommand: v1alpha2.BaseCommand{
510 Group: &v1alpha2.CommandGroup{
511 Kind: v1alpha2.CommandGroupKind(group),
512 },
513 },
514 },
515 },
516 },
517 }
518 }
519
520 func Test_subMoveCommand(t *testing.T) {
521 type args struct {
522 commands []v1alpha2.Command
523 previousGroup string
524 newGroup string
525 previousIndex int
526 newIndex int
527 }
528 tests := []struct {
529 name string
530 args args
531 want map[string][]v1alpha2.Command
532 wantErr bool
533 }{
534 {
535 name: "Move from run to test",
536 args: args{
537 commands: []v1alpha2.Command{
538 newCommand("build", "build1"),
539 newCommand("run", "runToTest"),
540 newCommand("", "other1"),
541 },
542 previousGroup: "run",
543 previousIndex: 0,
544 newGroup: "test",
545 newIndex: 0,
546 },
547 want: map[string][]v1alpha2.Command{
548 "build": {
549 newCommand("build", "build1"),
550 },
551 "run": {},
552 "test": {
553 newCommand("test", "runToTest"),
554 },
555 "": {
556 newCommand("", "other1"),
557 },
558 },
559 },
560 {
561 name: "Move from other to build",
562 args: args{
563 commands: []v1alpha2.Command{
564 newCommand("build", "build1"),
565 newCommand("run", "run"),
566 newCommand("other", "otherToBuild"),
567 },
568 previousGroup: "other",
569 previousIndex: 0,
570 newGroup: "build",
571 newIndex: 1,
572 },
573 want: map[string][]v1alpha2.Command{
574 "build": {
575 newCommand("build", "build1"),
576 newCommand("build", "otherToBuild"),
577 },
578 "run": {
579 newCommand("run", "run"),
580 },
581 "other": {},
582 },
583 },
584
585 }
586 for _, tt := range tests {
587 t.Run(tt.name, func(t *testing.T) {
588 got, err := subMoveCommand(tt.args.commands, tt.args.previousGroup, tt.args.newGroup, tt.args.previousIndex, tt.args.newIndex)
589 if (err != nil) != tt.wantErr {
590 t.Errorf("moveCommand() error = %v, wantErr %v", err, tt.wantErr)
591 return
592 }
593 if diff := cmp.Diff(tt.want, got); diff != "" {
594 t.Errorf("moveCommand() mismatch (-want +got):\n%s", diff)
595 }
596 })
597 }
598 }
599
600 func TestDevfileState_MoveCommand(t *testing.T) {
601 type args struct {
602 previousGroup string
603 newGroup string
604 previousIndex int
605 newIndex int
606 }
607 tests := []struct {
608 name string
609 state func(t *testing.T) DevfileState
610 args args
611 want DevfileContent
612 wantErr bool
613 }{
614 {
615 name: "not found command",
616 state: func(t *testing.T) DevfileState {
617 return NewDevfileState()
618 },
619 args: args{
620 previousGroup: "build",
621 previousIndex: 0,
622 newGroup: "run",
623 newIndex: 0,
624 },
625 wantErr: true,
626 },
627 {
628 name: "command moved from no group to run group",
629 state: func(t *testing.T) DevfileState {
630 state := NewDevfileState()
631 _, err := state.AddExecCommand(
632 "an-exec-command",
633 "a-container",
634 "run command",
635 "/path/to/work",
636 true,
637 )
638 if err != nil {
639 t.Fatal(err)
640 }
641 return state
642 },
643 args: args{
644 previousGroup: "",
645 previousIndex: 0,
646 newGroup: "run",
647 newIndex: 0,
648 },
649 want: DevfileContent{
650 Content: `commands:
651 - exec:
652 commandLine: run command
653 component: a-container
654 group:
655 kind: run
656 hotReloadCapable: true
657 workingDir: /path/to/work
658 id: an-exec-command
659 metadata: {}
660 schemaVersion: 2.2.0
661 `,
662 Version: "2.2.0",
663 Commands: []Command{
664 {
665 Name: "an-exec-command",
666 Group: "run",
667 Default: false,
668 Type: "exec",
669 Exec: ExecCommand{
670 Component: "a-container",
671 CommandLine: "run command",
672 WorkingDir: "/path/to/work",
673 HotReloadCapable: true,
674 },
675 },
676 },
677 Containers: []Container{},
678 Images: []Image{},
679 Resources: []Resource{},
680 Volumes: []Volume{},
681 },
682 },
683
684 }
685 for _, tt := range tests {
686 t.Run(tt.name, func(t *testing.T) {
687 o := tt.state(t)
688 got, err := o.MoveCommand(tt.args.previousGroup, tt.args.newGroup, tt.args.previousIndex, tt.args.newIndex)
689 if (err != nil) != tt.wantErr {
690 t.Errorf("DevfileState.MoveCommand() error = %v, wantErr %v", err, tt.wantErr)
691 return
692 }
693 if diff := cmp.Diff(tt.want, got); diff != "" {
694 t.Errorf("DevfileState.MoveCommand() mismatch (-want +got):\n%s", diff)
695 }
696 })
697 }
698 }
699
700 func TestDevfileState_SetDefaultCommand(t *testing.T) {
701 type args struct {
702 commandName string
703 group string
704 }
705 tests := []struct {
706 name string
707 state func(t *testing.T) DevfileState
708 args args
709 want DevfileContent
710 wantErr bool
711 }{
712 {
713 name: "command set to default in run group",
714 state: func(t *testing.T) DevfileState {
715 state := NewDevfileState()
716 _, err := state.AddExecCommand(
717 "an-exec-command",
718 "a-container",
719 "run command",
720 "/path/to/work",
721 true,
722 )
723 if err != nil {
724 t.Fatal(err)
725 }
726 _, err = state.MoveCommand("", "run", 0, 0)
727 if err != nil {
728 t.Fatal(err)
729 }
730 return state
731 },
732 args: args{
733 commandName: "an-exec-command",
734 group: "run",
735 },
736 want: DevfileContent{
737 Content: `commands:
738 - exec:
739 commandLine: run command
740 component: a-container
741 group:
742 isDefault: true
743 kind: run
744 hotReloadCapable: true
745 workingDir: /path/to/work
746 id: an-exec-command
747 metadata: {}
748 schemaVersion: 2.2.0
749 `,
750 Version: "2.2.0",
751 Commands: []Command{
752 {
753 Name: "an-exec-command",
754 Group: "run",
755 Default: true,
756 Type: "exec",
757 Exec: ExecCommand{
758 Component: "a-container",
759 CommandLine: "run command",
760 WorkingDir: "/path/to/work",
761 HotReloadCapable: true,
762 },
763 },
764 },
765 Containers: []Container{},
766 Images: []Image{},
767 Resources: []Resource{},
768 Volumes: []Volume{},
769 },
770 },
771
772 }
773 for _, tt := range tests {
774 t.Run(tt.name, func(t *testing.T) {
775 o := tt.state(t)
776 got, err := o.SetDefaultCommand(tt.args.commandName, tt.args.group)
777 if (err != nil) != tt.wantErr {
778 t.Errorf("DevfileState.SetDefaultCommand() error = %v, wantErr %v", err, tt.wantErr)
779 return
780 }
781 if diff := cmp.Diff(tt.want, got); diff != "" {
782 t.Errorf("DevfileState.SetDefaultCommand() mismatch (-want +got):\n%s", diff)
783 }
784 })
785 }
786 }
787
788 func TestDevfileState_UnsetDefaultCommand(t *testing.T) {
789 type args struct {
790 commandName string
791 }
792 tests := []struct {
793 name string
794 state func(t *testing.T) DevfileState
795 args args
796 want DevfileContent
797 wantErr bool
798 }{
799 {
800 name: "command unset default",
801 state: func(t *testing.T) DevfileState {
802 state := NewDevfileState()
803 _, err := state.AddExecCommand(
804 "an-exec-command",
805 "a-container",
806 "run command",
807 "/path/to/work",
808 true,
809 )
810 if err != nil {
811 t.Fatal(err)
812 }
813 _, err = state.MoveCommand("", "run", 0, 0)
814 if err != nil {
815 t.Fatal(err)
816 }
817 _, err = state.SetDefaultCommand("an-exec-command", "run")
818 if err != nil {
819 t.Fatal(err)
820 }
821 return state
822 },
823 args: args{
824 commandName: "an-exec-command",
825 },
826 want: DevfileContent{
827 Content: `commands:
828 - exec:
829 commandLine: run command
830 component: a-container
831 group:
832 isDefault: false
833 kind: run
834 hotReloadCapable: true
835 workingDir: /path/to/work
836 id: an-exec-command
837 metadata: {}
838 schemaVersion: 2.2.0
839 `,
840 Version: "2.2.0",
841 Commands: []Command{
842 {
843 Name: "an-exec-command",
844 Group: "run",
845 Default: false,
846 Type: "exec",
847 Exec: ExecCommand{
848 Component: "a-container",
849 CommandLine: "run command",
850 WorkingDir: "/path/to/work",
851 HotReloadCapable: true,
852 },
853 },
854 },
855 Containers: []Container{},
856 Images: []Image{},
857 Resources: []Resource{},
858 Volumes: []Volume{},
859 },
860 },
861
862 }
863 for _, tt := range tests {
864 t.Run(tt.name, func(t *testing.T) {
865 o := tt.state(t)
866 got, err := o.UnsetDefaultCommand(tt.args.commandName)
867 if (err != nil) != tt.wantErr {
868 t.Errorf("DevfileState.UnsetDefaultCommand() error = %v, wantErr %v", err, tt.wantErr)
869 return
870 }
871 if diff := cmp.Diff(tt.want, got); diff != "" {
872 t.Errorf("DevfileState.UnsetDefaultCommand() mismatch (-want +got):\n%s", diff)
873 }
874 })
875 }
876 }
877
View as plain text