1 package util
2
3 import (
4 "bufio"
5 "bytes"
6 "fmt"
7 "io"
8 "net"
9 "net/http"
10 "net/http/httptest"
11 "os"
12 "os/user"
13 "path/filepath"
14 "regexp"
15 "runtime"
16 "strconv"
17 "strings"
18 "testing"
19
20 "github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2"
21 dfutil "github.com/devfile/library/v2/pkg/util"
22 "github.com/go-git/go-git/v5"
23 "github.com/go-git/go-git/v5/config"
24 "github.com/google/go-cmp/cmp"
25 corev1 "k8s.io/api/core/v1"
26
27 "github.com/redhat-developer/odo/pkg/testingutil/filesystem"
28 )
29
30
31
32 func TestNamespaceOpenShiftObject(t *testing.T) {
33
34 tests := []struct {
35 testName string
36 componentName string
37 applicationName string
38 want string
39 wantErr bool
40 }{
41 {
42 testName: "Test namespacing",
43 componentName: "foo",
44 applicationName: "bar",
45 want: "foo-bar",
46 },
47 {
48 testName: "Blank applicationName with namespacing",
49 componentName: "foo",
50 applicationName: "",
51 wantErr: true,
52 },
53 {
54 testName: "Blank componentName with namespacing",
55 componentName: "",
56 applicationName: "bar",
57 wantErr: true,
58 },
59 }
60
61
62
63 for _, tt := range tests {
64 t.Log("Running test: ", tt.testName)
65 t.Run(tt.testName, func(t *testing.T) {
66 name, err := dfutil.NamespaceOpenShiftObject(tt.componentName, tt.applicationName)
67
68 if tt.wantErr && err == nil {
69 t.Errorf("Expected an error, got success")
70 } else if tt.wantErr == false && err != nil {
71 t.Errorf("Error with namespacing: %s", err)
72 }
73
74 if tt.want != name {
75 t.Errorf("Expected %s, got %s", tt.want, name)
76 }
77 })
78 }
79
80 }
81
82 func TestExtractComponentType(t *testing.T) {
83
84 tests := []struct {
85 testName string
86 componentType string
87 want string
88 wantErr bool
89 }{
90 {
91 testName: "Test namespacing and versioning",
92 componentType: "myproject/foo:3.5",
93 want: "foo",
94 },
95 {
96 testName: "Test versioning",
97 componentType: "foo:3.5",
98 want: "foo",
99 },
100 {
101 testName: "Test plain component type",
102 componentType: "foo",
103 want: "foo",
104 },
105 }
106
107
108
109 for _, tt := range tests {
110 t.Log("Running test: ", tt.testName)
111 t.Run(tt.testName, func(t *testing.T) {
112 name := dfutil.ExtractComponentType(tt.componentType)
113 if tt.want != name {
114 t.Errorf("Expected %s, got %s", tt.want, name)
115 }
116 })
117 }
118
119 }
120
121 func TestGetDNS1123Name(t *testing.T) {
122
123 tests := []struct {
124 testName string
125 param string
126 want string
127 }{
128 {
129 testName: "Case 1: Test get DNS-1123 name for namespace and version qualified imagestream",
130 param: "myproject/foo:3.5",
131 want: "myproject-foo-3-5",
132 },
133 {
134 testName: "Case 2: Test get DNS-1123 name for doubly hyphenated string",
135 param: "nodejs--myproject-foo-3.5",
136 want: "nodejs-myproject-foo-3-5",
137 },
138 {
139 testName: "Case 3: Test get DNS-1123 name for string starting with underscore",
140 param: "_nodejs--myproject-foo-3.5",
141 want: "nodejs-myproject-foo-3-5",
142 },
143 {
144 testName: "Case 4: Test get DNS-1123 name for string ending with underscore",
145 param: "nodejs--myproject-foo-3.5_",
146 want: "nodejs-myproject-foo-3-5",
147 },
148 {
149 testName: "Case 5: Test get DNS-1123 name for string having multiple non alpha-numeric chars as prefix",
150 param: "_#*nodejs--myproject-foo-3.5",
151 want: "nodejs-myproject-foo-3-5",
152 },
153 {
154 testName: "Case 6: Test get DNS-1123 name for string having multiple non alpha-numeric chars as suffix",
155 param: "nodejs--myproject-foo-3.5=_@",
156 want: "nodejs-myproject-foo-3-5",
157 },
158 {
159 testName: "Case 7: Test get DNS-1123 name for string having with multiple non alpha-numeric chars as prefix and suffix",
160 param: " _#*nodejs--myproject-foo-3.5=_@ ",
161 want: "nodejs-myproject-foo-3-5",
162 },
163 {
164 testName: "Case 8: Test get DNS-1123 should remove invalid chars",
165 param: "myproject/$foo@@:3.5",
166 want: "myproject-foo-3-5",
167 },
168 {
169 testName: "Case 9: Test get DNS-1123 should remove invalid chars with sufix and prefix",
170 param: "54myproject/$foo@@:3.5",
171 want: "myproject-foo-3-5",
172 },
173 {
174 testName: "Case 9: Test get DNS-1123 should add x as a prefix for all numerics",
175 param: "54453443",
176 want: "x54453443",
177 },
178 }
179
180
181
182 for _, tt := range tests {
183 t.Log("Running test: ", tt.testName)
184 t.Run(tt.testName, func(t *testing.T) {
185 name := GetDNS1123Name(tt.param)
186 if tt.want != name {
187 t.Errorf("Expected %s, got %s", tt.want, name)
188 }
189 })
190 }
191
192 }
193
194 func TestGetRandomName(t *testing.T) {
195 type args struct {
196 prefix string
197 existList []string
198 }
199 tests := []struct {
200 testName string
201 args args
202
203 want string
204 }{
205 {
206 testName: "Case: Optional suffix passed and prefix-suffix as a name is not already used",
207 args: args{
208 prefix: "odo",
209 existList: []string{
210 "odo-auth",
211 "odo-pqrs",
212 },
213 },
214 want: "odo-[a-z]{4}",
215 },
216 {
217 testName: "Case: Optional suffix passed and prefix-suffix as a name is already used",
218 args: args{
219 prefix: "nodejs-ex-nodejs",
220 existList: []string{
221 "nodejs-ex-nodejs-yvrp",
222 "nodejs-ex-nodejs-abcd",
223 },
224 },
225 want: "nodejs-ex-nodejs-[a-z]{4}",
226 },
227 }
228
229 for _, tt := range tests {
230 t.Log("Running test: ", tt.testName)
231 t.Run(tt.testName, func(t *testing.T) {
232 name, err := dfutil.GetRandomName(tt.args.prefix, -1, tt.args.existList, 3)
233 if err != nil {
234 t.Errorf("failed to generate a random name. Error %v", err)
235 }
236
237 r, _ := regexp.Compile(tt.want)
238 match := r.MatchString(name)
239 if !match {
240 t.Errorf("Received name %s which does not match %s", name, tt.want)
241 }
242 })
243 }
244 }
245
246 func TestTruncateString(t *testing.T) {
247 tests := []struct {
248 testName string
249 str string
250 strLength int
251 appendStr bool
252 appendArr []string
253 want string
254 }{
255 {
256 testName: "Case: Truncate string to greater length",
257 str: "qw",
258 strLength: 4,
259 appendStr: false,
260 want: "qw",
261 },
262 {
263 testName: "Case: Truncate string to lesser length",
264 str: "rtyu",
265 strLength: 3,
266 appendStr: false,
267 want: "rty",
268 },
269 {
270 testName: "Case: Truncate string to -1 length",
271 str: "Odo",
272 strLength: -1,
273 appendStr: false,
274 want: "Odo",
275 },
276 {
277 testName: "Case: Trunicate string with 3 dots appended",
278 str: "rtyu",
279 strLength: 3,
280 appendStr: true,
281 appendArr: []string{"..."},
282 want: "rty...",
283 },
284 {
285 testName: "Case: Appends multiple if multiple args are provided",
286 str: "rtyu",
287 strLength: 3,
288 appendStr: true,
289 appendArr: []string{".", ".", "."},
290 want: "rty...",
291 },
292 {
293 testName: "Case: Does not append if length is lesser than max length",
294 str: "qw",
295 strLength: 4,
296 appendStr: true,
297 appendArr: []string{"..."},
298 want: "qw",
299 },
300 {
301 testName: "Case: Does not append if maxlength is -1",
302 str: "rtyu",
303 strLength: -1,
304 appendStr: true,
305 appendArr: []string{"..."},
306 want: "rtyu",
307 },
308 }
309
310 for _, tt := range tests {
311 t.Log("Running test: ", tt.testName)
312 t.Run(tt.testName, func(t *testing.T) {
313 var receivedStr string
314 if tt.appendStr {
315 receivedStr = TruncateString(tt.str, tt.strLength, tt.appendArr...)
316 } else {
317 receivedStr = TruncateString(tt.str, tt.strLength)
318 }
319 if tt.want != receivedStr {
320 t.Errorf("Truncated string %s is not same as %s", receivedStr, tt.want)
321 }
322 })
323 }
324 }
325
326 func TestGenerateRandomString(t *testing.T) {
327 tests := []struct {
328 testName string
329 strLength int
330 }{
331 {
332 testName: "Case: Generate random string of length 4",
333 strLength: 4,
334 },
335 {
336 testName: "Case: Generate random string of length 3",
337 strLength: 3,
338 },
339 }
340
341 for _, tt := range tests {
342 t.Log("Running test: ", tt.testName)
343 t.Run(tt.testName, func(t *testing.T) {
344 name := dfutil.GenerateRandomString(tt.strLength)
345 r, _ := regexp.Compile(fmt.Sprintf("[a-z]{%d}", tt.strLength))
346 match := r.MatchString(name)
347 if !match {
348 t.Errorf("Randomly generated string %s which does not match regexp %s", name, fmt.Sprintf("[a-z]{%d}", tt.strLength))
349 }
350 })
351 }
352 }
353
354 func TestGetAbsPath(t *testing.T) {
355 tests := []struct {
356 name string
357 path string
358 absPath string
359 wantErr bool
360 }{
361 {
362 name: "Case 1: Valid abs path resolution of `~`",
363 path: "~",
364 wantErr: false,
365 },
366 {
367 name: "Case 2: Valid abs path resolution of `.`",
368 path: ".",
369 wantErr: false,
370 },
371 }
372 for _, tt := range tests {
373 t.Log("Running test: ", tt.name)
374 t.Run(tt.name, func(t *testing.T) {
375 switch tt.path {
376 case "~":
377 if len(customHomeDir) > 0 {
378 tt.absPath = customHomeDir
379 } else {
380 usr, err := user.Current()
381 if err != nil {
382 t.Errorf("Failed to get absolute path corresponding to `~`. Error %v", err)
383 return
384 }
385 tt.absPath = usr.HomeDir
386 }
387
388 case ".":
389 absPath, err := os.Getwd()
390 if err != nil {
391 t.Errorf("Failed to get absolute path corresponding to `.`. Error %v", err)
392 return
393 }
394 tt.absPath = absPath
395 }
396 result, err := dfutil.GetAbsPath(tt.path)
397 if result != tt.absPath {
398 t.Errorf("Expected %v, got %v", tt.absPath, result)
399 }
400 if !tt.wantErr == (err != nil) {
401 t.Errorf("Expected error: %v got error %v", tt.wantErr, err)
402 }
403 })
404 }
405 }
406
407 func TestCheckPathExists(t *testing.T) {
408 tests := []struct {
409 fsProvider func() (filesystem.Filesystem, error)
410 fileName string
411 wantBool bool
412 }{
413 {
414 fsProvider: func() (filesystem.Filesystem, error) {
415 fakeFs := filesystem.NewFakeFs()
416 _, err := fakeFs.Create("my-file")
417 if err != nil {
418 return nil, err
419 }
420 return fakeFs, nil
421 },
422 fileName: "my-file",
423 wantBool: true,
424 },
425 {
426 fsProvider: func() (filesystem.Filesystem, error) {
427 return filesystem.NewFakeFs(), nil
428 },
429 fileName: "some-file-blah",
430 wantBool: false,
431 },
432 }
433
434 for _, tt := range tests {
435 fsys, err := tt.fsProvider()
436 if err != nil {
437 t.Fatal(err)
438 }
439 exists := CheckPathExists(fsys, tt.fileName)
440 if tt.wantBool != exists {
441 t.Errorf("the expected value of TestCheckPathExists function is different : %v, got: %v", tt.wantBool, exists)
442 }
443 }
444 }
445
446 func TestGetHostWithPort(t *testing.T) {
447
448 tests := []struct {
449 inputURL string
450 want string
451 wantErr bool
452 }{
453 {
454 inputURL: "https://example.com",
455 want: "example.com:443",
456 wantErr: false,
457 },
458 {
459 inputURL: "https://example.com:8443",
460 want: "example.com:8443",
461 wantErr: false,
462 },
463 {
464 inputURL: "http://example.com",
465 want: "example.com:80",
466 wantErr: false,
467 },
468 {
469 inputURL: "notexisting://example.com",
470 want: "",
471 wantErr: true,
472 },
473 {
474 inputURL: "http://127.0.0.1",
475 want: "127.0.0.1:80",
476 wantErr: false,
477 },
478 {
479 inputURL: "example.com:1234",
480 want: "",
481 wantErr: true,
482 },
483 }
484 for _, tt := range tests {
485 t.Run(fmt.Sprintf("Testing inputURL: %s", tt.inputURL), func(t *testing.T) {
486 got, err := dfutil.GetHostWithPort(tt.inputURL)
487 if (err != nil) != tt.wantErr {
488 t.Errorf("getHostWithPort() error = %v, wantErr %v", err, tt.wantErr)
489 return
490 }
491 if got != tt.want {
492 t.Errorf("getHostWithPort() = %v, want %v", got, tt.want)
493 }
494 })
495 }
496 }
497
498
499
500
501
502 func MakeFileWithContent(dir string, fileName string, content string) error {
503 file, err := os.Create(dir + string(os.PathSeparator) + fileName)
504 if err != nil {
505 return fmt.Errorf("error while creating file: %w", err)
506 }
507 defer file.Close()
508 _, err = file.WriteString(content)
509 if err != nil {
510 return fmt.Errorf("error while writing to file: %w", err)
511 }
512 return nil
513 }
514
515
516
517 func RemoveContentsFromDir(dir string) error {
518 files, err := filepath.Glob(filepath.Join(dir, "*"))
519 if err != nil {
520 return err
521 }
522 for _, file := range files {
523 err = os.RemoveAll(file)
524 if err != nil {
525 return err
526 }
527 }
528 return nil
529 }
530
531 func TestGetIgnoreRulesFromDirectory(t *testing.T) {
532 testDir := t.TempDir()
533 tests := []struct {
534 name string
535 directoryName string
536 filesToCreate []string
537 rulesOnGitIgnore string
538 rulesOnOdoIgnore string
539 wantRules []string
540 wantErr bool
541 }{
542 {
543 name: "test case 1: no odoignore and no gitignore",
544 directoryName: testDir,
545 filesToCreate: []string{""},
546 rulesOnGitIgnore: "",
547 rulesOnOdoIgnore: "",
548 wantRules: []string{".git"},
549 wantErr: false,
550 },
551 {
552 name: "test case 2: no odoignore but gitignore exists with no rules",
553 directoryName: testDir,
554 filesToCreate: []string{DotGitIgnoreFile},
555 rulesOnGitIgnore: "",
556 rulesOnOdoIgnore: "",
557 wantRules: []string{".git"},
558 wantErr: false,
559 },
560 {
561 name: "test case 3: no odoignore but gitignore exists with rules",
562 directoryName: testDir,
563 filesToCreate: []string{DotGitIgnoreFile},
564 rulesOnGitIgnore: "*.js\n\n/openshift/**/*.json\n/tests",
565 rulesOnOdoIgnore: "",
566 wantRules: []string{".git", "*.js", "/openshift/**/*.json", "/tests"},
567 wantErr: false,
568 },
569 {
570 name: "test case 4: odoignore exists with no rules",
571 directoryName: testDir,
572 filesToCreate: []string{".odoignore"},
573 rulesOnGitIgnore: "",
574 rulesOnOdoIgnore: "",
575 wantRules: []string{".git"},
576 wantErr: false,
577 },
578 {
579 name: "test case 5: odoignore exists with rules",
580 directoryName: testDir,
581 filesToCreate: []string{".odoignore"},
582 rulesOnGitIgnore: "",
583 rulesOnOdoIgnore: "*.json\n\n/openshift/**/*.js",
584 wantRules: []string{".git", "*.json", "/openshift/**/*.js"},
585 wantErr: false,
586 },
587 {
588 name: "test case 6: odoignore and gitignore both exists with rules",
589 directoryName: testDir,
590 filesToCreate: []string{DotGitIgnoreFile, ".odoignore"},
591 rulesOnGitIgnore: "/tests",
592 rulesOnOdoIgnore: "*.json\n\n/openshift/**/*.js",
593 wantRules: []string{".git", "*.json", "/openshift/**/*.js"},
594 wantErr: false,
595 },
596 {
597 name: "test case 7: no odoignore but gitignore exists with rules and comments",
598 directoryName: testDir,
599 filesToCreate: []string{DotGitIgnoreFile},
600 rulesOnGitIgnore: "*.js\n\n/openshift/**/*.json\n\n\n#/tests",
601 rulesOnOdoIgnore: "",
602 wantRules: []string{".git", "*.js", "/openshift/**/*.json"},
603 wantErr: false,
604 },
605 {
606 name: "test case 8: odoignore exists exists with rules and comments",
607 directoryName: testDir,
608 filesToCreate: []string{".odoignore"},
609 rulesOnOdoIgnore: "*.js\n\n\n/openshift/**/*.json\n\n\n#/tests\n/bin",
610 rulesOnGitIgnore: "",
611 wantRules: []string{".git", "*.js", "/openshift/**/*.json", "/bin"},
612 wantErr: false,
613 },
614 }
615
616 for _, tt := range tests {
617 for _, fileName := range tt.filesToCreate {
618 var err error
619 if fileName == DotGitIgnoreFile {
620 err = MakeFileWithContent(testDir, fileName, tt.rulesOnGitIgnore)
621 } else if fileName == ".odoignore" {
622 err = MakeFileWithContent(testDir, fileName, tt.rulesOnOdoIgnore)
623 }
624 if err != nil {
625 t.Fatal(err)
626 }
627 }
628
629 gotRules, err := dfutil.GetIgnoreRulesFromDirectory(testDir)
630
631 if err == nil && !tt.wantErr {
632 if diff := cmp.Diff(tt.wantRules, gotRules); diff != "" {
633 t.Errorf("dfutil.GetIgnoreRulesFromDirectory() wantRules mismatch (-want +got):\n%s", diff)
634 }
635 } else if err == nil && tt.wantErr {
636 t.Error("error was expected, but no error was returned")
637 } else if err != nil && !tt.wantErr {
638 t.Errorf("test failed, no error was expected, but got unexpected error: %s", err)
639 }
640 err = RemoveContentsFromDir(testDir)
641 if err != nil {
642 t.Fatal(err)
643 }
644 }
645 }
646
647 func TestGetAbsGlobExps(t *testing.T) {
648 tests := []struct {
649 testName string
650 directoryName string
651 inputRelativeGlobExps []string
652 expectedGlobExps []string
653 }{
654 {
655 testName: "test case 1: with a filename",
656 directoryName: "/home/redhat/nodejs-ex/",
657 inputRelativeGlobExps: []string{
658 "example.txt",
659 },
660 expectedGlobExps: []string{
661 "/home/redhat/nodejs-ex/example.txt",
662 },
663 },
664 {
665 testName: "test case 2: with a folder name",
666 directoryName: "/home/redhat/nodejs-ex/",
667 inputRelativeGlobExps: []string{
668 "example/",
669 },
670 expectedGlobExps: []string{
671 "/home/redhat/nodejs-ex/example",
672 },
673 },
674 }
675
676 for _, tt := range tests {
677 t.Run(tt.testName, func(t *testing.T) {
678 resultExps := dfutil.GetAbsGlobExps(tt.directoryName, tt.inputRelativeGlobExps)
679 if runtime.GOOS == "windows" {
680 for index, element := range resultExps {
681 resultExps[index] = filepath.ToSlash(element)
682 }
683 }
684
685 if diff := cmp.Diff(tt.expectedGlobExps, resultExps); diff != "" {
686 t.Errorf("dfutil.GetAbsGlobExps() expectedGlobExps mismatch (-want +got):\n%s", diff)
687 }
688 })
689 }
690 }
691
692 func TestGetSortedKeys(t *testing.T) {
693 tests := []struct {
694 testName string
695 input map[string]string
696 expected []string
697 }{
698 {
699 testName: "default",
700 input: map[string]string{"a": "av", "c": "cv", "b": "bv"},
701 expected: []string{"a", "b", "c"},
702 },
703 }
704
705 for _, tt := range tests {
706 t.Log("Running test: ", tt.testName)
707 t.Run(tt.testName, func(t *testing.T) {
708 actual := dfutil.GetSortedKeys(tt.input)
709 if diff := cmp.Diff(tt.expected, actual); diff != "" {
710 t.Errorf("dfutil.GetSortedKeys() mismatch (-want +got):\n%s", diff)
711 }
712 })
713 }
714 }
715
716 func TestGetSplitValuesFromStr(t *testing.T) {
717 tests := []struct {
718 testName string
719 input string
720 expected []string
721 }{
722 {
723 testName: "Empty string",
724 input: "",
725 expected: []string{},
726 },
727 {
728 testName: "Single value",
729 input: "s1",
730 expected: []string{"s1"},
731 },
732 {
733 testName: "Multiple values",
734 input: "s1, s2, s3 ",
735 expected: []string{"s1", "s2", "s3"},
736 },
737 }
738
739 for _, tt := range tests {
740 t.Log("Running test: ", tt.testName)
741 t.Run(tt.testName, func(t *testing.T) {
742 actual := dfutil.GetSplitValuesFromStr(tt.input)
743 if diff := cmp.Diff(tt.expected, actual); diff != "" {
744 t.Errorf("dfutil.GetSplitValuesFromStr() mismatch (-want +got):\n%s", diff)
745 }
746 })
747 }
748 }
749
750 func TestGetContainerPortsFromStrings(t *testing.T) {
751 tests := []struct {
752 name string
753 ports []string
754 containerPorts []corev1.ContainerPort
755 wantErr bool
756 }{
757 {
758 name: "with normal port values and normal protocol values in lowercase",
759 ports: []string{"8080/tcp", "9090/udp"},
760 containerPorts: []corev1.ContainerPort{
761 {
762 Name: "8080-tcp",
763 ContainerPort: 8080,
764 Protocol: corev1.ProtocolTCP,
765 },
766 {
767 Name: "9090-udp",
768 ContainerPort: 9090,
769 Protocol: corev1.ProtocolUDP,
770 },
771 },
772 wantErr: false,
773 },
774 {
775 name: "with normal port values and normal protocol values in mixed case",
776 ports: []string{"8080/TcP", "9090/uDp"},
777 containerPorts: []corev1.ContainerPort{
778 {
779 Name: "8080-tcp",
780 ContainerPort: 8080,
781 Protocol: corev1.ProtocolTCP,
782 },
783 {
784 Name: "9090-udp",
785 ContainerPort: 9090,
786 Protocol: corev1.ProtocolUDP,
787 },
788 },
789 wantErr: false,
790 },
791 {
792 name: "with normal port values and with one protocol value not mentioned",
793 ports: []string{"8080", "9090/Udp"},
794 containerPorts: []corev1.ContainerPort{
795 {
796 Name: "8080-tcp",
797 ContainerPort: 8080,
798 Protocol: corev1.ProtocolTCP,
799 },
800 {
801 Name: "9090-udp",
802 ContainerPort: 9090,
803 Protocol: corev1.ProtocolUDP,
804 },
805 },
806 wantErr: false,
807 },
808 {
809 name: "with normal port values and with one invalid protocol value",
810 ports: []string{"8080/blah", "9090/Udp"},
811 wantErr: true,
812 },
813 {
814 name: "with invalid port values and normal protocol",
815 ports: []string{"ads/Tcp", "9090/Udp"},
816 wantErr: true,
817 },
818 {
819 name: "with invalid port values and one missing protocol value",
820 ports: []string{"ads", "9090/Udp"},
821 wantErr: true,
822 },
823 }
824 for _, tt := range tests {
825 t.Run(tt.name, func(t *testing.T) {
826 ports, err := dfutil.GetContainerPortsFromStrings(tt.ports)
827 if err == nil && !tt.wantErr {
828 if diff := cmp.Diff(tt.containerPorts, ports); diff != "" {
829 t.Errorf("dfutil.GetContainerPortsFromStrings() containerPorts mismatch (-want +got):\n%s", diff)
830 }
831 } else if err == nil && tt.wantErr {
832 t.Error("error was expected, but no error was returned")
833 } else if err != nil && !tt.wantErr {
834 t.Errorf("test failed, no error was expected, but got unexpected error: %s", err)
835 }
836 })
837 }
838 }
839
840 func TestIsGlobExpMatch(t *testing.T) {
841
842 tests := []struct {
843 testName string
844 strToMatch string
845 globExps []string
846 want bool
847 wantErr bool
848 }{
849 {
850 testName: "Test glob matches",
851 strToMatch: "/home/redhat/nodejs-ex/.git",
852 globExps: []string{"/home/redhat/nodejs-ex/.git", "/home/redhat/nodejs-ex/tests/"},
853 want: true,
854 wantErr: false,
855 },
856 {
857 testName: "Test glob does not match",
858 strToMatch: "/home/redhat/nodejs-ex/gimmt.gimmt",
859 globExps: []string{"/home/redhat/nodejs-ex/.git/", "/home/redhat/nodejs-ex/tests/"},
860 want: false,
861 wantErr: false,
862 },
863 {
864 testName: "Test glob match files",
865 strToMatch: "/home/redhat/nodejs-ex/openshift/templates/example.json",
866 globExps: []string{"/home/redhat/nodejs-ex/*.json", "/home/redhat/nodejs-ex/tests/"},
867 want: true,
868 wantErr: false,
869 },
870 {
871 testName: "Test '**' glob matches",
872 strToMatch: "/home/redhat/nodejs-ex/openshift/templates/example.json",
873 globExps: []string{"/home/redhat/nodejs-ex/openshift/**/*.json"},
874 want: true,
875 wantErr: false,
876 },
877 {
878 testName: "Test '!' in glob matches",
879 strToMatch: "/home/redhat/nodejs-ex/openshift/templates/example.json",
880 globExps: []string{"/home/redhat/nodejs-ex/!*.json", "/home/redhat/nodejs-ex/tests/"},
881 want: false,
882 wantErr: false,
883 },
884 {
885 testName: "Test [ in glob matches",
886 strToMatch: "/home/redhat/nodejs-ex/openshift/templates/example.json",
887 globExps: []string{"/home/redhat/nodejs-ex/["},
888 want: false,
889 wantErr: true,
890 },
891 {
892 testName: "Test '#' comment glob matches",
893 strToMatch: "/home/redhat/nodejs-ex/openshift/templates/example.json",
894 globExps: []string{"#/home/redhat/nodejs-ex/openshift/**/*.json"},
895 want: false,
896 wantErr: false,
897 },
898 }
899
900 for _, tt := range tests {
901 t.Run(tt.testName, func(t *testing.T) {
902 matched, err := dfutil.IsGlobExpMatch(tt.strToMatch, tt.globExps)
903
904 if !tt.wantErr == (err != nil) {
905 t.Errorf("unexpected error %v, wantErr %v", err, tt.wantErr)
906 return
907 }
908
909 if tt.want != matched {
910 t.Errorf("expected %v, got %v", tt.want, matched)
911 }
912 })
913 }
914 }
915
916 func TestRemoveRelativePathFromFiles(t *testing.T) {
917 type args struct {
918 path string
919 input []string
920 output []string
921 }
922 tests := []struct {
923 name string
924 args args
925 wantErr bool
926 }{
927 {
928 name: "Case 1 - Remove the relative path from a list of files",
929 args: args{
930 path: "/foo/bar",
931 input: []string{"/foo/bar/1", "/foo/bar/2", "/foo/bar/3/", "/foo/bar/4/5/foo/bar"},
932 output: []string{"1", "2", "3", "4/5/foo/bar"},
933 },
934 wantErr: false,
935 },
936 {
937 name: "Case 2 - Fail on purpose with an invalid path",
938 args: args{
939 path: `..`,
940 input: []string{"foo", "bar"},
941 output: []string{},
942 },
943 wantErr: true,
944 },
945 }
946 for _, tt := range tests {
947 t.Run(tt.name, func(t *testing.T) {
948
949
950 output, err := dfutil.RemoveRelativePathFromFiles(tt.args.input, tt.args.path)
951 if runtime.GOOS == "windows" {
952 for index, element := range output {
953 output[index] = filepath.ToSlash(element)
954 }
955 }
956
957
958 if !tt.wantErr == (err != nil) {
959 t.Errorf("unexpected error %v, wantErr %v", err, tt.wantErr)
960 return
961 }
962
963 if diff := cmp.Diff(tt.args.output, output); diff != "" {
964 t.Errorf("dfutil.RemoveRelativePathFromFiles() output mismatch (-want +got):\n%s", diff)
965 }
966
967 })
968 }
969 }
970
971 func TestHTTPGetFreePort(t *testing.T) {
972 tests := []struct {
973 name string
974 wantErr bool
975 }{
976 {
977 name: "case 1: get a valid free port",
978 wantErr: false,
979 },
980 }
981 for _, tt := range tests {
982 t.Run(tt.name, func(t *testing.T) {
983 got, err := dfutil.HTTPGetFreePort()
984 if (err != nil) != tt.wantErr {
985 t.Errorf("HTTPGetFreePort() error = %v, wantErr %v", err, tt.wantErr)
986 return
987 }
988 addressLook := "localhost:" + strconv.Itoa(got)
989 listener, err := net.Listen("tcp", addressLook)
990 if err != nil {
991 t.Errorf("expected a free port, but listening failed cause: %v", err)
992 } else {
993 _ = listener.Close()
994 }
995 })
996 }
997 }
998
999 func TestGetRemoteFilesMarkedForDeletion(t *testing.T) {
1000 tests := []struct {
1001 name string
1002 files []string
1003 remotePath string
1004 want []string
1005 }{
1006 {
1007 name: "case 1: no files",
1008 files: []string{},
1009 remotePath: "/projects",
1010 want: nil,
1011 },
1012 {
1013 name: "case 2: one file",
1014 files: []string{"abc.txt"},
1015 remotePath: "/projects",
1016 want: []string{"/projects/abc.txt"},
1017 },
1018 {
1019 name: "case 3: multiple files",
1020 files: []string{"abc.txt", "def.txt", "hello.txt"},
1021 remotePath: "/projects",
1022 want: []string{"/projects/abc.txt", "/projects/def.txt", "/projects/hello.txt"},
1023 },
1024 {
1025 name: "case 4: remote path multiple folders",
1026 files: []string{"abc.txt", "def.txt", "hello.txt"},
1027 remotePath: "/test/folder",
1028 want: []string{"/test/folder/abc.txt", "/test/folder/def.txt", "/test/folder/hello.txt"},
1029 },
1030 }
1031 for _, tt := range tests {
1032 t.Run(tt.name, func(t *testing.T) {
1033 remoteFiles := dfutil.GetRemoteFilesMarkedForDeletion(tt.files, tt.remotePath)
1034 if diff := cmp.Diff(tt.want, remoteFiles); diff != "" {
1035 t.Errorf("dfutil.GetRemoteFilesMarkedForDeletion() mismatch (-want +got):\n%s", diff)
1036 }
1037 })
1038 }
1039 }
1040
1041 func TestHTTPGetRequest(t *testing.T) {
1042
1043 server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
1044
1045 _, err := rw.Write([]byte("OK"))
1046 if err != nil {
1047 t.Error(err)
1048 }
1049 }))
1050
1051 defer server.Close()
1052
1053 tests := []struct {
1054 name string
1055 url string
1056 want []byte
1057 }{
1058 {
1059 name: "Case 1: Input url is valid",
1060 url: server.URL,
1061
1062
1063 want: []byte{79, 75},
1064 },
1065 {
1066 name: "Case 2: Input url is invalid",
1067 url: "invalid",
1068 want: nil,
1069 },
1070 }
1071
1072 for _, tt := range tests {
1073 t.Run(tt.name, func(t *testing.T) {
1074 request := dfutil.HTTPRequestParams{
1075 URL: tt.url,
1076 }
1077 got, err := dfutil.HTTPGetRequest(request, 0)
1078
1079 if diff := cmp.Diff(tt.want, got); diff != "" {
1080 t.Errorf("dfutil.HTTPGetRequest() mismatch (-want +got):\n%s", diff)
1081 t.Logf("Error message is: %v", err)
1082 }
1083 })
1084 }
1085 }
1086
1087 func TestFilterIgnores(t *testing.T) {
1088 tests := []struct {
1089 name string
1090 changedFiles []string
1091 deletedFiles []string
1092 ignoredFiles []string
1093 wantChangedFiles []string
1094 wantDeletedFiles []string
1095 }{
1096 {
1097 name: "Case 1: No ignored files",
1098 changedFiles: []string{"hello.txt", "test.abc"},
1099 deletedFiles: []string{"one.txt", "two.txt"},
1100 ignoredFiles: []string{},
1101 wantChangedFiles: []string{"hello.txt", "test.abc"},
1102 wantDeletedFiles: []string{"one.txt", "two.txt"},
1103 },
1104 {
1105 name: "Case 2: One ignored file",
1106 changedFiles: []string{"hello.txt", "test.abc"},
1107 deletedFiles: []string{"one.txt", "two.txt"},
1108 ignoredFiles: []string{"hello.txt"},
1109 wantChangedFiles: []string{"test.abc"},
1110 wantDeletedFiles: []string{"one.txt", "two.txt"},
1111 },
1112 {
1113 name: "Case 3: Multiple ignored file",
1114 changedFiles: []string{"hello.txt", "test.abc"},
1115 deletedFiles: []string{"one.txt", "two.txt"},
1116 ignoredFiles: []string{"hello.txt", "two.txt"},
1117 wantChangedFiles: []string{"test.abc"},
1118 wantDeletedFiles: []string{"one.txt"},
1119 },
1120 {
1121 name: "Case 4: No changed or deleted files",
1122 changedFiles: []string{""},
1123 deletedFiles: []string{""},
1124 ignoredFiles: []string{"hello.txt", "two.txt"},
1125 wantChangedFiles: []string{""},
1126 wantDeletedFiles: []string{""},
1127 },
1128 }
1129
1130 for _, tt := range tests {
1131 t.Run(tt.name, func(t *testing.T) {
1132 filterChanged, filterDeleted := dfutil.FilterIgnores(tt.changedFiles, tt.deletedFiles, tt.ignoredFiles)
1133
1134 if diff := cmp.Diff(tt.wantChangedFiles, filterChanged); diff != "" {
1135 t.Errorf("dfutil.FilterIgnores() wantChangedFiles mismatch (-want +got):\n%s", diff)
1136 }
1137
1138 if diff := cmp.Diff(tt.wantDeletedFiles, filterDeleted); diff != "" {
1139 t.Errorf("dfutil.FilterIgnores() wantDeletedFiles mismatch (-want +got):\n%s", diff)
1140 }
1141 })
1142 }
1143 }
1144
1145 func TestDownloadFile(t *testing.T) {
1146
1147 server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
1148
1149 _, err := rw.Write([]byte("OK"))
1150 if err != nil {
1151 t.Error(err)
1152 }
1153 }))
1154
1155 defer server.Close()
1156
1157 tests := []struct {
1158 name string
1159 url string
1160 filepath string
1161 want []byte
1162 wantErr bool
1163 }{
1164 {
1165 name: "Case 1: Input url is valid",
1166 url: server.URL,
1167 filepath: "./test.yaml",
1168
1169
1170 want: []byte{79, 75},
1171 wantErr: false,
1172 },
1173 {
1174 name: "Case 2: Input url is invalid",
1175 url: "invalid",
1176 filepath: "./test.yaml",
1177 want: []byte{},
1178 wantErr: true,
1179 },
1180 {
1181 name: "Case 3: Input url is an empty string",
1182 url: "",
1183 filepath: "./test.yaml",
1184 want: []byte{},
1185 wantErr: true,
1186 },
1187 }
1188
1189 for _, tt := range tests {
1190 t.Run(tt.name, func(t *testing.T) {
1191 gotErr := false
1192 params := dfutil.DownloadParams{
1193 Request: dfutil.HTTPRequestParams{
1194 URL: tt.url,
1195 },
1196 Filepath: tt.filepath,
1197 }
1198 err := dfutil.DownloadFile(params)
1199 if err != nil {
1200 gotErr = true
1201 }
1202 if gotErr != tt.wantErr {
1203 t.Errorf("Failed to get expected error: %v", err)
1204 }
1205
1206 if !tt.wantErr {
1207 if err != nil {
1208 t.Errorf("Failed to download file with error %s", err)
1209 }
1210
1211 got, err := os.ReadFile(tt.filepath)
1212 if err != nil {
1213 t.Errorf("Failed to read file with error %s", err)
1214 }
1215
1216 if diff := cmp.Diff(tt.want, got); diff != "" {
1217 t.Errorf("dfutil.DownloadFile() mismatch (-want +got):\n%s", diff)
1218 }
1219
1220
1221 err = os.Remove(tt.filepath)
1222 if err != nil {
1223 t.Errorf("Failed to delete file with error %s", err)
1224 }
1225 }
1226 })
1227 }
1228 }
1229
1230 func TestValidateK8sResourceName(t *testing.T) {
1231 tests := []struct {
1232 name string
1233 key string
1234 value string
1235 want bool
1236 }{
1237 {
1238 name: "Case 1: Resource name is valid",
1239 key: "component name",
1240 value: "good-name",
1241 want: true,
1242 },
1243 {
1244 name: "Case 2: Resource name contains unsupported character",
1245 key: "component name",
1246 value: "BAD@name",
1247 want: false,
1248 },
1249 {
1250 name: "Case 3: Resource name contains all numeric values",
1251 key: "component name",
1252 value: "12345",
1253 want: false,
1254 },
1255 }
1256
1257 for _, tt := range tests {
1258 t.Run(tt.name, func(t *testing.T) {
1259 err := dfutil.ValidateK8sResourceName(tt.key, tt.value)
1260 got := err == nil
1261 if diff := cmp.Diff(tt.want, got); diff != "" {
1262 t.Errorf("dfutil.ValidateK8sResourceName() mismatch (-want +got):\n%s", diff)
1263 }
1264 })
1265 }
1266 }
1267
1268 func TestUnzip(t *testing.T) {
1269 tests := []struct {
1270 name string
1271 src string
1272 pathToUnzip string
1273 expectedFiles []string
1274 expectedError string
1275 }{
1276 {
1277 name: "Case 1: Invalid source zip",
1278 src: "../../tests/examples/source/devfiles/nodejs-zip/invalid.zip",
1279 pathToUnzip: "",
1280 expectedFiles: []string{},
1281 expectedError: "open ../../tests/examples/source/devfiles/nodejs-zip/invalid.zip:",
1282 },
1283 {
1284 name: "Case 2: Valid source zip, no pathToUnzip",
1285 src: "../../tests/examples/source/devfiles/nodejs-zip/master.zip",
1286 pathToUnzip: "",
1287 expectedFiles: []string{"package.json", "package-lock.json", "app", "app/app.js", DotGitIgnoreFile, "LICENSE", "README.md"},
1288 expectedError: "",
1289 },
1290 {
1291 name: "Case 3: Valid source zip with pathToUnzip",
1292 src: "../../tests/examples/source/devfiles/nodejs-zip/master.zip",
1293 pathToUnzip: "app",
1294 expectedFiles: []string{"app.js"},
1295 expectedError: "",
1296 },
1297 {
1298 name: "Case 4: Valid source zip with pathToUnzip - trailing /",
1299 src: "../../tests/examples/source/devfiles/nodejs-zip/master.zip",
1300 pathToUnzip: "app/",
1301 expectedFiles: []string{"app.js"},
1302 expectedError: "",
1303 },
1304 {
1305 name: "Case 5: Valid source zip with pathToUnzip - leading /",
1306 src: "../../tests/examples/source/devfiles/nodejs-zip/master.zip",
1307 pathToUnzip: "app/",
1308 expectedFiles: []string{"app.js"},
1309 expectedError: "",
1310 },
1311 {
1312 name: "Case 6: Valid source zip with pathToUnzip - leading and trailing /",
1313 src: "../../tests/examples/source/devfiles/nodejs-zip/master.zip",
1314 pathToUnzip: "/app/",
1315 expectedFiles: []string{"app.js"},
1316 expectedError: "",
1317 },
1318 {
1319 name: "Case 7: Valid source zip with pathToUnzip - pattern",
1320 src: "../../tests/examples/source/devfiles/nodejs-zip/master.zip",
1321 pathToUnzip: "p*",
1322 expectedFiles: []string{"package.json", "package-lock.json"},
1323 expectedError: "",
1324 },
1325 {
1326 name: "Case 8: Valid source zip with pathToUnzip - pattern and extension",
1327 src: "../../tests/examples/source/devfiles/nodejs-zip/master.zip",
1328 pathToUnzip: "*.json",
1329 expectedFiles: []string{"package.json", "package-lock.json"},
1330 expectedError: "",
1331 },
1332 }
1333
1334 for _, tt := range tests {
1335 t.Run(tt.name, func(t *testing.T) {
1336 dir := t.TempDir()
1337 t.Logf(dir)
1338
1339 _, err := Unzip(filepath.FromSlash(tt.src), dir, tt.pathToUnzip, filesystem.DefaultFs{})
1340 if err != nil {
1341 tt.expectedError = strings.ReplaceAll(tt.expectedError, "/", string(filepath.Separator))
1342 if !strings.HasPrefix(err.Error(), tt.expectedError) {
1343 t.Errorf("Got err: '%s'\n expected err: '%s'", err.Error(), tt.expectedError)
1344 }
1345 } else {
1346 for _, file := range tt.expectedFiles {
1347 if _, err := os.Stat(filepath.Join(dir, file)); os.IsNotExist(err) {
1348 t.Errorf("Expected file %s does not exist in directory after unzipping", file)
1349 }
1350 }
1351 }
1352 })
1353 }
1354 }
1355
1356 func TestIsValidProjectDir(t *testing.T) {
1357 tests := []struct {
1358 name string
1359 devfilePath string
1360 filesToCreate []string
1361 dirToCreate []string
1362 expectedError string
1363 }{
1364 {
1365 name: "Case 1: Empty Folder",
1366 devfilePath: "",
1367 filesToCreate: []string{},
1368 dirToCreate: []string{},
1369 expectedError: "",
1370 },
1371 {
1372 name: "Case 2: Folder contains devfile.yaml",
1373 devfilePath: "devfile.yaml",
1374 filesToCreate: []string{"devfile.yaml"},
1375 dirToCreate: []string{},
1376 expectedError: "",
1377 },
1378 {
1379 name: "Case 3: Folder contains a file which is not the devfile",
1380 devfilePath: "devfile.yaml",
1381 filesToCreate: []string{"file1.yaml"},
1382 dirToCreate: []string{},
1383 expectedError: "folder %s doesn't contain the devfile used",
1384 },
1385 {
1386 name: "Case 4: Folder contains a hidden file which is not the devfile",
1387 devfilePath: "devfile.yaml",
1388 filesToCreate: []string{".file1.yaml"},
1389 dirToCreate: []string{},
1390 expectedError: "folder %s doesn't contain the devfile used",
1391 },
1392 {
1393 name: "Case 5: Folder contains devfile.yaml and more files",
1394 devfilePath: "devfile.yaml",
1395 filesToCreate: []string{"devfile.yaml", "file1.yaml", "file2.yaml"},
1396 dirToCreate: []string{},
1397 expectedError: "folder %s is not empty. It can only contain the devfile used",
1398 },
1399 }
1400
1401 for _, tt := range tests {
1402 t.Run(tt.name, func(t *testing.T) {
1403 tmpDir := t.TempDir()
1404
1405 for _, f := range tt.filesToCreate {
1406 file := filepath.Join(tmpDir, f)
1407 if _, e := os.Create(file); e != nil {
1408 t.Errorf("Error creating file %s. Err: %s", file, e)
1409 }
1410 }
1411
1412 for _, d := range tt.dirToCreate {
1413 dir := filepath.Join(tmpDir, d)
1414 if e := os.Mkdir(dir, os.FileMode(0644)); e != nil {
1415 t.Errorf("Error creating dir %s. Err: %s", dir, e)
1416 }
1417 }
1418
1419 err := IsValidProjectDir(tmpDir, tt.devfilePath, filesystem.DefaultFs{})
1420 expectedError := tt.expectedError
1421 if expectedError != "" {
1422 expectedError = fmt.Sprintf(expectedError, tmpDir)
1423 }
1424
1425 if err != nil {
1426 if diff := cmp.Diff(expectedError, err.Error()); diff != "" {
1427 t.Errorf("IsValidProjectDir() mismatch (-want +got):\n%s", diff)
1428 }
1429 }
1430 })
1431 }
1432 }
1433
1434 func TestDownloadFileInMemory(t *testing.T) {
1435
1436 server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
1437
1438 _, err := rw.Write([]byte("OK"))
1439 if err != nil {
1440 t.Error(err)
1441 }
1442 }))
1443
1444 defer server.Close()
1445
1446 tests := []struct {
1447 name string
1448 url string
1449 want []byte
1450 }{
1451 {
1452 name: "Case 1: Input url is valid",
1453 url: server.URL,
1454 want: []byte{79, 75},
1455 },
1456 {
1457 name: "Case 2: Input url is invalid",
1458 url: "invalid",
1459 want: []byte(nil),
1460 },
1461 }
1462
1463 for _, tt := range tests {
1464 t.Run(tt.name, func(t *testing.T) {
1465 data, err := DownloadFileInMemory(dfutil.HTTPRequestParams{URL: tt.url})
1466 if tt.url != "invalid" && err != nil {
1467 t.Errorf("Failed to download file with error %s", err)
1468 }
1469
1470 if diff := cmp.Diff(tt.want, data); diff != "" {
1471 t.Errorf("DownloadFileInMemory() mismatch (-want +got):\n%s", diff)
1472 }
1473 })
1474 }
1475 }
1476
1477
1524
1525 func TestValidateURL(t *testing.T) {
1526 tests := []struct {
1527 name string
1528 url string
1529 wantErr bool
1530 }{
1531 {
1532 name: "Case 1: Valid URL",
1533 url: "http://www.example.com/",
1534 wantErr: false,
1535 },
1536 {
1537 name: "Valid URL, with port",
1538 url: "http://192.168.1.10:30741/",
1539 wantErr: false,
1540 },
1541 {
1542 name: "Valid URL, with port, login and password",
1543 url: "http://user:pass@192.168.1.10:30741/",
1544 wantErr: false,
1545 },
1546 {
1547 name: "Case 2: Invalid URL - No host",
1548 url: "http://",
1549 wantErr: true,
1550 },
1551 {
1552 name: "Case 3: Invalid URL - No scheme",
1553 url: "://www.example.com/",
1554 wantErr: true,
1555 },
1556 {
1557 name: "Case 4: Invalid URL - Host contains reserved character",
1558 url: "http://??##",
1559 wantErr: true,
1560 },
1561 {
1562 name: "Case 5: Invalid URL - Scheme contains reserved character",
1563 url: "$$$,,://www.example.com",
1564 wantErr: true,
1565 },
1566 }
1567
1568 for _, tt := range tests {
1569 t.Run(tt.name, func(t *testing.T) {
1570 gotErr := false
1571 got := ValidateURL(tt.url)
1572 if got != nil {
1573 gotErr = true
1574 }
1575
1576 if gotErr != tt.wantErr {
1577 t.Errorf("Got %v, want %v", got, tt.wantErr)
1578 }
1579 })
1580 }
1581 }
1582
1583 func TestValidateFile(t *testing.T) {
1584
1585 tempDir := t.TempDir()
1586 tempFile, err := os.CreateTemp(tempDir, "")
1587 if err != nil {
1588 t.Errorf("Failed to create temp file: %s, error: %v", tempFile.Name(), err)
1589 }
1590 defer tempFile.Close()
1591
1592 tests := []struct {
1593 name string
1594 filePath string
1595 wantErr bool
1596 }{
1597 {
1598 name: "Case 1: Valid file path",
1599 filePath: tempFile.Name(),
1600 wantErr: false,
1601 },
1602 {
1603 name: "Case 2: Invalid file path",
1604 filePath: "!@#",
1605 wantErr: true,
1606 },
1607 }
1608
1609 for _, tt := range tests {
1610 t.Run(tt.name, func(t *testing.T) {
1611 gotErr := false
1612 err := dfutil.ValidateFile(tt.filePath)
1613 if err != nil {
1614 gotErr = true
1615 }
1616 if gotErr != tt.wantErr {
1617 t.Errorf("Got error: %v, want error: %t", err, tt.wantErr)
1618 }
1619 })
1620 }
1621 }
1622
1623 func TestCopyFile(t *testing.T) {
1624
1625 tempDir := t.TempDir()
1626
1627
1628 tempFile, err := os.CreateTemp(tempDir, "")
1629 if err != nil {
1630 t.Errorf("Failed to create temp file: %s, error: %v", tempFile.Name(), err)
1631 }
1632 defer tempFile.Close()
1633
1634 srcPath := tempFile.Name()
1635 fakePath := "!@#/**"
1636 dstPath := filepath.Join(tempDir, "dstFile")
1637 info, _ := os.Stat(srcPath)
1638
1639 tests := []struct {
1640 name string
1641 srcPath string
1642 dstPath string
1643 wantErr bool
1644 }{
1645 {
1646 name: "Case 1: Copy successfully",
1647 srcPath: srcPath,
1648 dstPath: dstPath,
1649 wantErr: false,
1650 },
1651 {
1652 name: "Case 2: Invalid source path",
1653 srcPath: fakePath,
1654 dstPath: dstPath,
1655 wantErr: true,
1656 },
1657 {
1658 name: "Case 3: Invalid destination path",
1659 srcPath: srcPath,
1660 dstPath: fakePath,
1661 wantErr: true,
1662 },
1663 }
1664
1665 for _, tt := range tests {
1666 t.Run(tt.name, func(t *testing.T) {
1667 gotErr := false
1668 err = dfutil.CopyFile(tt.srcPath, tt.dstPath, info)
1669 if err != nil {
1670 gotErr = true
1671 }
1672
1673 if gotErr != tt.wantErr {
1674 t.Errorf("Got error: %v, want error: %t", err, tt.wantErr)
1675 }
1676 })
1677 }
1678 }
1679
1680 func TestPathEqual(t *testing.T) {
1681 currentDir, err := os.Getwd()
1682 if err != nil {
1683 t.Errorf("Can't get absolute path of current working directory with error: %v", err)
1684 }
1685 fileAbsPath := filepath.Join(currentDir, "file")
1686 fileRelPath := filepath.Join(".", "file")
1687
1688 tests := []struct {
1689 name string
1690 firstPath string
1691 secondPath string
1692 want bool
1693 }{
1694 {
1695 name: "Case 1: Two paths (two absolute paths) are equal",
1696 firstPath: fileAbsPath,
1697 secondPath: fileAbsPath,
1698 want: true,
1699 },
1700 {
1701 name: "Case 2: Two paths (one absolute path, one relative path) are equal",
1702 firstPath: fileAbsPath,
1703 secondPath: fileRelPath,
1704 want: true,
1705 },
1706 {
1707 name: "Case 3: Two paths are not equal",
1708 firstPath: fileAbsPath,
1709 secondPath: filepath.Join(fileAbsPath, "file"),
1710 want: false,
1711 },
1712 }
1713
1714 for _, tt := range tests {
1715 t.Run(tt.name, func(t *testing.T) {
1716 got := dfutil.PathEqual(tt.firstPath, tt.secondPath)
1717 if diff := cmp.Diff(tt.want, got); diff != "" {
1718 t.Errorf("dfutil.PathEqual() mismatch (-want +got):\n%s", diff)
1719 }
1720 })
1721 }
1722 }
1723
1724 func TestSliceContainsString(t *testing.T) {
1725 tests := []struct {
1726 name string
1727 stringVal string
1728 slice []string
1729 wantVal bool
1730 }{
1731 {
1732 name: "Case 1: string in valid slice",
1733 stringVal: "string",
1734 slice: []string{"string", "string2"},
1735 wantVal: true,
1736 },
1737 {
1738 name: "Case 2: string not in valid slice",
1739 stringVal: "string3",
1740 slice: []string{"string", "string2"},
1741 wantVal: false,
1742 },
1743 {
1744 name: "Case 3: string not in empty slice",
1745 stringVal: "string",
1746 slice: []string{},
1747 wantVal: false,
1748 },
1749 }
1750
1751 for _, tt := range tests {
1752 t.Run(tt.name, func(t *testing.T) {
1753 gotVal := sliceContainsString(tt.stringVal, tt.slice)
1754
1755 if diff := cmp.Diff(tt.wantVal, gotVal); diff != "" {
1756 t.Errorf("sliceContainsString() mismatch (-want +got):\n%s", diff)
1757 }
1758 })
1759 }
1760 }
1761
1762
1763 type FileType int
1764
1765 const (
1766
1767 RegularFile FileType = 0
1768
1769 Directory FileType = 1
1770 )
1771
1772
1773 type FileProperties struct {
1774 FilePath string
1775 FileType FileType
1776 }
1777
1778 func folderCheck(originalFolderMode os.FileMode, newFolderInfo os.FileInfo, path string) error {
1779 if originalFolderMode.String() != newFolderInfo.Mode().String() {
1780 return fmt.Errorf("folder %s created with wrong permission", path)
1781 }
1782 return nil
1783 }
1784
1785 func fileCheck(fs filesystem.Filesystem, originalFile filesystem.File, newFilePath string, newFileInfo os.FileInfo) error {
1786 originalFileData, err := fs.ReadFile(originalFile.Name())
1787 if err != nil {
1788 return err
1789 }
1790
1791 createdFileData, err := fs.ReadFile(newFilePath)
1792 if err != nil {
1793 return err
1794 }
1795
1796
1797 if string(createdFileData) == string(originalFileData) {
1798 originalInfo, err := fs.Stat(originalFile.Name())
1799 if err != nil {
1800 return err
1801 }
1802
1803
1804 if newFileInfo.Mode() != originalInfo.Mode() {
1805 return fmt.Errorf("file %s created with wrong permission", newFilePath)
1806 }
1807 } else {
1808 return fmt.Errorf("file %s created with wrong data", newFilePath)
1809 }
1810 return nil
1811 }
1812
1813 func setupFileTest(fs filesystem.Filesystem, sourceName string, filePaths []FileProperties) (map[string]filesystem.File, map[string]os.FileMode, error) {
1814
1815 fileMap := make(map[string]filesystem.File)
1816 folderMap := make(map[string]os.FileMode)
1817
1818 for i, path := range filePaths {
1819
1820 if path.FileType == RegularFile {
1821 file, err := fs.Create(path.FilePath)
1822 if err != nil {
1823 return nil, nil, err
1824 }
1825 _, err = file.Write([]byte("some text" + string(rune(i))))
1826 if err != nil {
1827 return nil, nil, err
1828 }
1829
1830 name, err := filepath.Rel(sourceName, file.Name())
1831 if err != nil {
1832 return nil, nil, err
1833 }
1834 fileMap[name] = file
1835 } else if path.FileType == Directory {
1836 permission := os.ModeDir + 0755
1837 err := fs.MkdirAll(path.FilePath, permission)
1838 if err != nil {
1839 return nil, nil, err
1840 }
1841
1842 name, err := filepath.Rel(sourceName, path.FilePath)
1843 if err != nil {
1844 return nil, nil, err
1845 }
1846 folderMap[name] = permission
1847 }
1848 }
1849
1850 return fileMap, folderMap, nil
1851 }
1852
1853 func TestCopyFileWithFS(t *testing.T) {
1854 fileName := "blah.js"
1855
1856 fs := filesystem.NewFakeFs()
1857
1858 sourceName := filepath.Join(os.TempDir(), "source")
1859 destinationDirName := filepath.Join(os.TempDir(), "destination")
1860
1861 filePaths := []FileProperties{
1862 {
1863 FilePath: sourceName,
1864 FileType: Directory,
1865 },
1866 {
1867 FilePath: filepath.Join(sourceName, fileName),
1868 FileType: RegularFile,
1869 },
1870 {
1871 FilePath: destinationDirName,
1872 FileType: Directory,
1873 },
1874 }
1875
1876 printError := func(err error) {
1877 t.Errorf("some error occured while procession file/folder: %v", err)
1878 }
1879
1880 type args struct {
1881 src string
1882 dst string
1883 fs filesystem.Filesystem
1884 }
1885 tests := []struct {
1886 name string
1887 args args
1888 wantErr bool
1889 }{
1890 {
1891 name: "case 1: normal file exists",
1892 args: args{
1893 src: filepath.Join(sourceName, fileName),
1894 dst: filepath.Join(destinationDirName, fileName),
1895 fs: fs,
1896 },
1897 },
1898 {
1899 name: "case 2: file doesn't exist",
1900 args: args{
1901 src: filepath.Join(sourceName, fileName) + "blah",
1902 dst: filepath.Join(destinationDirName, fileName),
1903 fs: fs,
1904 },
1905 wantErr: true,
1906 },
1907 }
1908 for _, tt := range tests {
1909 t.Run(tt.name, func(t *testing.T) {
1910 fileMap, _, err := setupFileTest(fs, sourceName, filePaths)
1911 if err != nil {
1912 t.Errorf("error while setting up test: %v", err)
1913 }
1914
1915 err = copyFileWithFs(tt.args.src, tt.args.dst, tt.args.fs)
1916 if (err != nil) != tt.wantErr {
1917 t.Errorf("MoveFile() error = %v, wantErr %v", err, tt.wantErr)
1918 }
1919
1920 if tt.wantErr {
1921 return
1922 }
1923
1924 files, err := fs.ReadDir(destinationDirName)
1925 if err != nil {
1926 t.Errorf("error occured while reading directory %s: %v", destinationDirName, err)
1927 }
1928
1929 found := false
1930 for _, file := range files {
1931
1932 relPath, err := filepath.Rel(destinationDirName, filepath.Join(destinationDirName, fileName))
1933 if err != nil {
1934 printError(err)
1935 break
1936 }
1937
1938 if originalFile, ok := fileMap[relPath]; ok {
1939 err := fileCheck(fs, originalFile, filepath.Join(destinationDirName, file.Name()), file)
1940 if err != nil {
1941 break
1942 }
1943 found = true
1944 } else {
1945 t.Errorf("extra file %s created", file.Name())
1946 }
1947 }
1948
1949 if !found && !tt.wantErr {
1950 t.Errorf("%s not created in directory %s", fileName, destinationDirName)
1951 }
1952
1953 _ = fs.RemoveAll(tt.args.src)
1954 _ = fs.RemoveAll(tt.args.dst)
1955 })
1956 }
1957 }
1958
1959 func TestCopyDirWithFS(t *testing.T) {
1960
1961 fs := filesystem.NewFakeFs()
1962
1963 sourceName := filepath.Join(os.TempDir(), "source")
1964 destinationName := filepath.Join(os.TempDir(), "destination")
1965
1966 filePaths := []FileProperties{
1967 {
1968 FilePath: sourceName,
1969 FileType: Directory,
1970 },
1971 {
1972 FilePath: filepath.Join(sourceName, "main"),
1973 FileType: Directory,
1974 },
1975 {
1976 FilePath: filepath.Join(sourceName, "blah.js"),
1977 FileType: RegularFile,
1978 },
1979 {
1980 FilePath: filepath.Join(sourceName, "main", "some-other-blah.js"),
1981 FileType: RegularFile,
1982 },
1983 }
1984
1985 printError := func(err error) {
1986 t.Errorf("some error occured while procession file/folder: %v", err)
1987 }
1988
1989 type args struct {
1990 src string
1991 dst string
1992 fs filesystem.Filesystem
1993 }
1994 tests := []struct {
1995 name string
1996 args args
1997 wantErr bool
1998 }{
1999 {
2000 name: "case 1: folder with a nested file and folder",
2001 args: args{
2002 src: sourceName,
2003 dst: destinationName,
2004 fs: fs,
2005 },
2006 },
2007 {
2008 name: "case 2: source folder doesn't exist",
2009 args: args{
2010 src: sourceName + "/extra",
2011 dst: destinationName,
2012 fs: fs,
2013 },
2014 wantErr: true,
2015 },
2016 }
2017 for _, tt := range tests {
2018 t.Run(tt.name, func(t *testing.T) {
2019 fileMap, folderMap, err := setupFileTest(fs, sourceName, filePaths)
2020 if err != nil {
2021 t.Errorf("error while setting up test: %v", err)
2022 }
2023
2024 err = CopyDirWithFS(tt.args.src, tt.args.dst, tt.args.fs)
2025 if (err != nil) != tt.wantErr {
2026 t.Errorf("MoveDir() error = %v, wantErr %v", err, tt.wantErr)
2027 }
2028
2029 if tt.wantErr && err != nil {
2030 return
2031 }
2032
2033 folderCount := 0
2034 fileCount := 0
2035
2036 err = fs.Walk(destinationName, func(path string, info os.FileInfo, err error) error {
2037 if err != nil {
2038 return err
2039 }
2040
2041 relPath, err := filepath.Rel(destinationName, path)
2042 if err != nil {
2043 printError(err)
2044 return err
2045 }
2046
2047 if info.IsDir() {
2048
2049
2050 if originalFolderMode, ok := folderMap[relPath]; ok {
2051 err := folderCheck(originalFolderMode, info, path)
2052 if err != nil {
2053 printError(err)
2054 return err
2055 }
2056 folderCount++
2057 } else {
2058 t.Errorf("extra folder %s created", path)
2059 }
2060 } else {
2061 if file, ok := fileMap[relPath]; ok {
2062 err := fileCheck(fs, file, path, info)
2063 if err != nil {
2064 printError(err)
2065 return err
2066 }
2067 fileCount++
2068 } else {
2069 t.Errorf("extra file %s created", path)
2070 }
2071 }
2072 return nil
2073 })
2074
2075 if err != nil {
2076 t.Errorf("unexpected error: %v", err)
2077 }
2078
2079 if folderCount != 2 {
2080 t.Errorf("some folder were not created")
2081 }
2082
2083 if fileCount != 2 {
2084 t.Errorf("some files were not created")
2085 }
2086
2087 _ = fs.RemoveAll(tt.args.src)
2088 _ = fs.RemoveAll(tt.args.dst)
2089 })
2090 }
2091 }
2092
2093 func TestCleanDir(t *testing.T) {
2094 fs := filesystem.NewFakeFs()
2095
2096 sourceName := filepath.Join(os.TempDir(), "source")
2097
2098 filePaths := []FileProperties{
2099 {
2100 FilePath: sourceName,
2101 FileType: Directory,
2102 },
2103 {
2104 FilePath: filepath.Join(sourceName, "main"),
2105 FileType: Directory,
2106 },
2107 {
2108 FilePath: filepath.Join(sourceName, "main", "src"),
2109 FileType: Directory,
2110 },
2111 {
2112 FilePath: filepath.Join(sourceName, "devfile.yaml"),
2113 FileType: RegularFile,
2114 },
2115 {
2116 FilePath: filepath.Join(sourceName, "preference.yaml"),
2117 FileType: RegularFile,
2118 },
2119 {
2120 FilePath: filepath.Join(sourceName, "blah.js"),
2121 FileType: RegularFile,
2122 },
2123 {
2124 FilePath: filepath.Join(sourceName, "main", "some-other-blah.js"),
2125 FileType: RegularFile,
2126 },
2127 {
2128 FilePath: filepath.Join(sourceName, "main", "src", "another-blah.js"),
2129 FileType: RegularFile,
2130 },
2131 }
2132
2133 type args struct {
2134 originalPath string
2135 leaveBehindFiles map[string]bool
2136 fs filesystem.Filesystem
2137 }
2138 tests := []struct {
2139 name string
2140 args args
2141 wantErr bool
2142 }{
2143 {
2144 name: "case 1: leave behind two files",
2145 args: args{
2146 originalPath: sourceName,
2147 fs: fs,
2148 leaveBehindFiles: map[string]bool{
2149 "devfile.yaml": true,
2150 "preference.yaml": true,
2151 },
2152 },
2153 },
2154 {
2155 name: "case 2: source doesn't exist",
2156 args: args{
2157 originalPath: sourceName + "blah",
2158 fs: fs,
2159 leaveBehindFiles: map[string]bool{
2160 "devfile.yaml": true,
2161 "preference.yaml": true,
2162 },
2163 },
2164 wantErr: true,
2165 },
2166 }
2167 for _, tt := range tests {
2168 t.Run(tt.name, func(t *testing.T) {
2169 _, _, err := setupFileTest(fs, sourceName, filePaths)
2170 if err != nil {
2171 t.Errorf("error while setting up test: %v", err)
2172 }
2173
2174 err = cleanDir(tt.args.originalPath, tt.args.leaveBehindFiles, tt.args.fs)
2175 if (err != nil) != tt.wantErr {
2176 t.Errorf("CleanDir() error = %v, wantErr %v", err, tt.wantErr)
2177 }
2178
2179 if err != nil && tt.wantErr {
2180 return
2181 }
2182
2183 files, err := fs.ReadDir(sourceName)
2184 if err != nil {
2185 t.Errorf("error occured while reading directory %s: %v", sourceName, err)
2186 }
2187
2188 found := 0
2189 for _, file := range files {
2190 if _, ok := tt.args.leaveBehindFiles[file.Name()]; !ok {
2191 t.Errorf("file %s isn't cleaned up", file.Name())
2192 } else {
2193 found++
2194 }
2195 }
2196
2197 if found != 2 {
2198 t.Errorf("some extra file were deleted")
2199 }
2200
2201 _ = fs.RemoveAll(tt.args.originalPath)
2202 })
2203 }
2204 }
2205
2206 func TestGitSubDir(t *testing.T) {
2207
2208 fs := filesystem.NewFakeFs()
2209
2210 sourceName := filepath.Join(os.TempDir(), "source")
2211 destinationName := filepath.Join(os.TempDir(), "destination")
2212
2213 filePaths := []FileProperties{
2214 {
2215 FilePath: sourceName,
2216 FileType: Directory,
2217 },
2218 {
2219 FilePath: filepath.Join(sourceName, "main"),
2220 FileType: Directory,
2221 },
2222 {
2223 FilePath: filepath.Join(sourceName, "blah.js"),
2224 FileType: RegularFile,
2225 },
2226 {
2227 FilePath: filepath.Join(sourceName, "main", "some-other-blah.js"),
2228 FileType: RegularFile,
2229 },
2230 {
2231 FilePath: filepath.Join(sourceName, "main", "test"),
2232 FileType: Directory,
2233 },
2234 {
2235 FilePath: filepath.Join(sourceName, "main", "test", "test.java"),
2236 FileType: RegularFile,
2237 },
2238 {
2239 FilePath: filepath.Join(sourceName, "main", "src", "java"),
2240 FileType: Directory,
2241 },
2242 {
2243 FilePath: filepath.Join(sourceName, "main", "src", "java", "main.java"),
2244 FileType: RegularFile,
2245 },
2246 {
2247 FilePath: filepath.Join(sourceName, "main", "src", "resources"),
2248 FileType: Directory,
2249 },
2250 {
2251 FilePath: filepath.Join(sourceName, "main", "src", "resources", "layout"),
2252 FileType: Directory,
2253 },
2254 {
2255 FilePath: filepath.Join(sourceName, "main", "src", "resources", "index.html"),
2256 FileType: RegularFile,
2257 },
2258 }
2259
2260 type args struct {
2261 destinationPath string
2262 srcPath string
2263 subDir string
2264 fs filesystem.Filesystem
2265 }
2266 tests := []struct {
2267 name string
2268 args args
2269 wantErr bool
2270 }{
2271 {
2272 name: "case 1: normal sub dir exist",
2273 args: args{
2274 srcPath: sourceName,
2275 destinationPath: destinationName,
2276 subDir: filepath.Join("main", "src"),
2277 fs: fs,
2278 },
2279 },
2280 {
2281 name: "case 2: sub dir doesn't exist",
2282 args: args{
2283 srcPath: sourceName,
2284 destinationPath: destinationName,
2285 subDir: filepath.Join("main", "blah"),
2286 fs: fs,
2287 },
2288 wantErr: true,
2289 },
2290 {
2291 name: "case 3: src doesn't exist",
2292 args: args{
2293 srcPath: sourceName + "blah",
2294 destinationPath: destinationName,
2295 subDir: filepath.Join("main", "src"),
2296 fs: fs,
2297 },
2298 wantErr: true,
2299 },
2300 }
2301 for _, tt := range tests {
2302 t.Run(tt.name, func(t *testing.T) {
2303 _, _, err := setupFileTest(fs, sourceName, filePaths)
2304 if err != nil {
2305 t.Errorf("error while setting up test: %v", err)
2306 }
2307
2308 err = gitSubDir(tt.args.srcPath, tt.args.destinationPath, tt.args.subDir, tt.args.fs)
2309 if (err != nil) != tt.wantErr {
2310 t.Errorf("GitSubDir() error = %v, wantErr %v", err, tt.wantErr)
2311 }
2312
2313 if tt.wantErr && err != nil {
2314 return
2315 }
2316
2317 pathsToValidate := map[string]bool{
2318 filepath.Join(tt.args.destinationPath, "java"): true,
2319 filepath.Join(tt.args.destinationPath, "java", "main.java"): true,
2320 filepath.Join(tt.args.destinationPath, "resources"): true,
2321 filepath.Join(tt.args.destinationPath, "resources", "layout"): true,
2322 filepath.Join(tt.args.destinationPath, "resources", "index.html"): true,
2323 }
2324
2325 pathsNotToBePresent := map[string]bool{
2326 filepath.Join(tt.args.destinationPath, "src"): true,
2327 filepath.Join(tt.args.destinationPath, "main"): true,
2328 }
2329
2330 found := 0
2331 notToBeFound := 0
2332 err = fs.Walk(tt.args.destinationPath, func(path string, info os.FileInfo, err error) error {
2333 if err != nil {
2334 return err
2335 }
2336
2337 if ok := pathsToValidate[path]; ok {
2338 found++
2339 }
2340
2341 if ok := pathsNotToBePresent[path]; ok {
2342 notToBeFound++
2343 }
2344 return nil
2345 })
2346 if err != nil {
2347 t.Errorf("unexpected error: %v", err)
2348 }
2349
2350 if found != 5 {
2351 t.Errorf("all files were not copied")
2352 }
2353
2354 if notToBeFound != 0 {
2355 t.Errorf("extra files were created")
2356 }
2357
2358 _, err = os.Stat(tt.args.srcPath)
2359 if !os.IsNotExist(err) {
2360 t.Errorf("src path was not deleted")
2361 }
2362
2363 _ = fs.RemoveAll(tt.args.srcPath)
2364 _ = fs.RemoveAll(tt.args.destinationPath)
2365 })
2366 }
2367 }
2368
2369 func TestGetCommandStringFromEnvs(t *testing.T) {
2370 type args struct {
2371 envVars []v1alpha2.EnvVar
2372 }
2373 tests := []struct {
2374 name string
2375 args args
2376 want string
2377 }{
2378 {
2379 name: "case 1: three envs given",
2380 args: args{
2381 envVars: []v1alpha2.EnvVar{
2382 {
2383 Name: "foo",
2384 Value: "bar",
2385 },
2386 {
2387 Name: "JAVA_HOME",
2388 Value: "/home/user/java",
2389 },
2390 {
2391 Name: "GOPATH",
2392 Value: "/home/user/go",
2393 },
2394 },
2395 },
2396 want: "export foo=\"bar\" JAVA_HOME=\"/home/user/java\" GOPATH=\"/home/user/go\"",
2397 },
2398 {
2399 name: "case 2: no envs given",
2400 args: args{
2401 envVars: []v1alpha2.EnvVar{},
2402 },
2403 want: "",
2404 },
2405 }
2406 for _, tt := range tests {
2407 t.Run(tt.name, func(t *testing.T) {
2408 if got := GetCommandStringFromEnvs(tt.args.envVars); got != tt.want {
2409 t.Errorf("GetCommandStringFromEnvs() = %v, want %v", got, tt.want)
2410 }
2411 })
2412 }
2413 }
2414
2415 func TestGetGitOriginPath(t *testing.T) {
2416 tempGitDirWithOrigin := t.TempDir()
2417
2418 repoWithOrigin, err := git.PlainInit(tempGitDirWithOrigin, true)
2419 if err != nil {
2420 t.Errorf("unexpected error %v", err)
2421 }
2422
2423 _, err = repoWithOrigin.CreateRemote(&config.RemoteConfig{
2424 Name: "origin",
2425 URLs: []string{"git@github.com:redhat-developer/odo.git"},
2426 })
2427 if err != nil {
2428 t.Errorf("unexpected error %v", err)
2429 }
2430
2431 tempGitDirWithoutOrigin := t.TempDir()
2432
2433 repoWithoutOrigin, err := git.PlainInit(tempGitDirWithoutOrigin, true)
2434 if err != nil {
2435 t.Errorf("unexpected error %v", err)
2436 }
2437
2438 _, err = repoWithoutOrigin.CreateRemote(&config.RemoteConfig{
2439 Name: "upstream",
2440 URLs: []string{"git@github.com:redhat-developer/odo.git"},
2441 })
2442 if err != nil {
2443 t.Errorf("unexpected error %v", err)
2444 }
2445
2446 type args struct {
2447 path string
2448 }
2449 tests := []struct {
2450 name string
2451 args args
2452 want string
2453 }{
2454 {
2455 name: "case 1: remote named origin exists",
2456 args: args{
2457 path: tempGitDirWithOrigin,
2458 },
2459 want: "git@github.com:redhat-developer/odo.git",
2460 },
2461 {
2462 name: "case 2: remote named origin doesn't exists",
2463 args: args{
2464 path: tempGitDirWithoutOrigin,
2465 },
2466 want: "",
2467 },
2468 {
2469 name: "case 3: not a git repo",
2470 args: args{
2471 path: "",
2472 },
2473 want: "",
2474 },
2475 }
2476 for _, tt := range tests {
2477 t.Run(tt.name, func(t *testing.T) {
2478 if got := GetGitOriginPath(tt.args.path); got != tt.want {
2479 t.Errorf("GetGitOriginPath() = %v, want %v", got, tt.want)
2480 }
2481 })
2482 }
2483 }
2484
2485 func TestConvertLabelsToSelector(t *testing.T) {
2486 cases := []struct {
2487 labels map[string]string
2488 want string
2489 }{
2490 {
2491 labels: map[string]string{
2492 "app": "app",
2493 "app.kubernetes.io/managed-by": "odo",
2494 "app.kubernetes.io/managed-by-version": "v2.1",
2495 },
2496 want: "app=app,app.kubernetes.io/managed-by=odo,app.kubernetes.io/managed-by-version=v2.1",
2497 },
2498 {
2499 labels: map[string]string{
2500 "app": "app",
2501 "app.kubernetes.io/managed-by": "!odo",
2502 "app.kubernetes.io/managed-by-version": "4.8",
2503 },
2504 want: "app=app,app.kubernetes.io/managed-by!=odo,app.kubernetes.io/managed-by-version=4.8",
2505 },
2506 {
2507 labels: map[string]string{
2508 "app.kubernetes.io/managed-by": "odo",
2509 },
2510 want: "app.kubernetes.io/managed-by=odo",
2511 },
2512 {
2513 labels: map[string]string{
2514 "app.kubernetes.io/managed-by": "!odo",
2515 },
2516 want: "app.kubernetes.io/managed-by!=odo",
2517 },
2518 }
2519
2520 for _, tt := range cases {
2521 got := ConvertLabelsToSelector(tt.labels)
2522 if got != tt.want {
2523 t.Errorf("got: %q\nwant:%q", got, tt.want)
2524 }
2525 }
2526 }
2527
2528 func TestNamespaceKubernetesObjectWithTrim(t *testing.T) {
2529 type args struct {
2530 componentName string
2531 applicationName string
2532 }
2533 tests := []struct {
2534 name string
2535 args args
2536 want string
2537 wantErr bool
2538 }{
2539 {
2540 name: "case 1: hyphenated name is less than 63 characters",
2541 args: args{
2542 componentName: "nodejs",
2543 applicationName: "app",
2544 },
2545 want: "nodejs-app",
2546 wantErr: false,
2547 },
2548 {
2549 name: "case 2: hyphenated name is more than 63 characters",
2550 args: args{
2551 componentName: "veryveryveryveryveryLongComponentName",
2552 applicationName: "veryveryveryveryveryveryLongAppName",
2553 },
2554 want: "veryveryveryveryveryLongCompone-veryveryveryveryveryveryLongApp",
2555 wantErr: false,
2556 },
2557 {
2558 name: "case 3: hyphenated name is equal to 63 characters",
2559 args: args{
2560 componentName: "veryveryveryveryLongComponentGo",
2561 applicationName: "veryveryveryveryLongAppNameInGo",
2562 },
2563 want: "veryveryveryveryLongComponentGo-veryveryveryveryLongAppNameInGo",
2564 wantErr: false,
2565 },
2566 {
2567 name: "case 4: component name is more than 63 characters",
2568 args: args{
2569 componentName: "123456789012345678901234567890123456789012345678901234567890ComponentName",
2570 applicationName: "app",
2571 },
2572 want: "12345678901234567890123456789012345678901234567890123456789-app",
2573 wantErr: false,
2574 },
2575 }
2576 for _, tt := range tests {
2577 t.Run(tt.name, func(t *testing.T) {
2578 got, err := NamespaceKubernetesObjectWithTrim(tt.args.componentName, tt.args.applicationName, 63)
2579 if (err != nil) != tt.wantErr {
2580 t.Errorf("NamespaceKubernetesObjectWithTrim() error = %v, wantErr %v", err, tt.wantErr)
2581 return
2582 }
2583 if got != tt.want {
2584 t.Errorf("NamespaceKubernetesObjectWithTrim() got = %v, want %v", got, tt.want)
2585 }
2586
2587 if len(got) > 63 {
2588 t.Errorf("got = %s should be less than or equal to 63 characters", got)
2589 }
2590 })
2591 }
2592 }
2593
2594 func TestSafeGetBool(t *testing.T) {
2595
2596 tests := []struct {
2597 name string
2598 arg *bool
2599 want bool
2600 }{
2601 {
2602 name: "case 1: nil pointer",
2603 arg: nil,
2604 want: false,
2605 },
2606 {
2607 name: "case 2: true",
2608 arg: GetBool(true),
2609 want: true,
2610 },
2611 {
2612 name: "case 3: false",
2613 arg: GetBool(false),
2614 want: false,
2615 },
2616 }
2617 for _, tt := range tests {
2618 t.Run(tt.name, func(t *testing.T) {
2619 if got := SafeGetBool(tt.arg); got != tt.want {
2620 t.Errorf("SafeGetBool() = %v, want %v", got, tt.want)
2621 }
2622 })
2623 }
2624 }
2625
2626 func TestDisplayLog(t *testing.T) {
2627 const compName = "my-comp"
2628 type args struct {
2629 input []string
2630 numLines int
2631 }
2632 for _, tt := range []struct {
2633 name string
2634 wantErr bool
2635 want []string
2636
2637 args
2638 }{
2639 {
2640 name: "numberOfLastLines==-1",
2641 args: args{
2642 input: []string{"a", "b", "c"},
2643 numLines: -1,
2644 },
2645 want: []string{"a\n", "b\n", "c\n"},
2646 },
2647 {
2648 name: "numberOfLastLines greater than total number of lines read",
2649 args: args{
2650 input: []string{"one-line"},
2651 numLines: 10,
2652 },
2653 want: []string{"one-line\n"},
2654 },
2655 } {
2656 t.Run(tt.name, func(t *testing.T) {
2657 var b bytes.Buffer
2658 for _, s := range tt.input {
2659 if _, err := b.WriteString(s + "\n"); err != nil {
2660 t.Errorf(" failed to write input data %q", s)
2661 return
2662 }
2663 }
2664 var w bytes.Buffer
2665 err := DisplayLog(false, io.NopCloser(&b), &w, compName, tt.numLines)
2666
2667 if tt.wantErr != (err != nil) {
2668 t.Errorf("expected %v, got %v", tt.wantErr, err)
2669 return
2670 }
2671
2672
2673 reader := bufio.NewReader(&w)
2674 var lines []string
2675 var line string
2676 for {
2677 line, err = reader.ReadString('\n')
2678 if err != nil {
2679 if err == io.EOF {
2680 break
2681 }
2682 t.Errorf("unexpected err while reading data: %v", err)
2683 return
2684 }
2685 lines = append(lines, line)
2686 }
2687 if diff := cmp.Diff(tt.want, lines); diff != "" {
2688 t.Errorf("DisplayLog() mismatch (-want +got):\n%s", diff)
2689 }
2690 })
2691 }
2692 }
2693
2694 func Test_addFileToIgnoreFile(t *testing.T) {
2695 type args struct {
2696 data string
2697 ignore string
2698 }
2699 tests := []struct {
2700 name string
2701 args args
2702 wantErr bool
2703 want string
2704 }{
2705 {
2706 name: ".odo already present as .odo",
2707 args: args{
2708 data: ".odo",
2709 ignore: ".odo",
2710 },
2711 want: ".odo",
2712 },
2713 {
2714 name: ".odo not present",
2715 args: args{
2716 data: `foo
2717 bar`,
2718 ignore: ".odo",
2719 },
2720 want: `foo
2721 bar
2722 .odo`,
2723 },
2724 }
2725 for _, tt := range tests {
2726 t.Run(tt.name, func(t *testing.T) {
2727 fs := filesystem.NewFakeFs()
2728 var data = []byte(tt.args.data)
2729 path := "/.gitignore"
2730 err := fs.WriteFile(path, data, 0644)
2731 if err != nil {
2732 t.Error(err)
2733 }
2734
2735 if err = addFileToIgnoreFile(path, tt.args.ignore, fs); (err != nil) != tt.wantErr {
2736 t.Errorf("addFileToIgnoreFile() error = %v, wantErr %v", err, tt.wantErr)
2737 }
2738 var content []byte
2739 content, err = fs.ReadFile(path)
2740 if err != nil {
2741 t.Error(err)
2742 }
2743 if string(content) != tt.want {
2744 t.Errorf("expected \n%s\ngot \n%s", tt.want, string(content))
2745 }
2746 })
2747 }
2748 }
2749
2750 func TestIsPortFree(t *testing.T) {
2751 type serverCloser interface {
2752 Close()
2753 }
2754 type args struct {
2755 port int
2756 portProvider func(address string) (int, serverCloser, error)
2757 address string
2758 }
2759 type test struct {
2760 name string
2761 args args
2762 want bool
2763 }
2764 tests := []test{
2765 {
2766 name: "negative port should return an error, handles as false",
2767 args: args{port: -10},
2768 want: false,
2769 },
2770 {
2771 name: "0 should always be free",
2772 args: args{port: 0},
2773 want: true,
2774 },
2775 {
2776 name: "random port bound on 127.0.0.1",
2777 args: args{
2778 portProvider: func(address string) (int, serverCloser, error) {
2779 s := httptest.NewServer(nil)
2780 _, p, err := net.SplitHostPort(strings.TrimPrefix(s.URL, "http://"))
2781 if err != nil {
2782 return 0, s, err
2783 }
2784 port, err := strconv.Atoi(p)
2785 if err != nil {
2786 return 0, s, err
2787 }
2788 return port, s, nil
2789 },
2790 },
2791 want: false,
2792 },
2793 {
2794 name: "random port bound on 127.0.0.1 and checking 0 as input",
2795 args: args{
2796 portProvider: func(address string) (int, serverCloser, error) {
2797 s := httptest.NewServer(nil)
2798 return 0, s, nil
2799 },
2800 },
2801 want: true,
2802 },
2803 {
2804 name: "random port bound on 0.0.0.0 and checking 0 as input",
2805 args: args{
2806 portProvider: func(address string) (int, serverCloser, error) {
2807
2808 l, err := net.Listen("tcp", fmt.Sprintf("%s:0", address))
2809 if err != nil {
2810 return 0, nil, err
2811 }
2812 s := &httptest.Server{
2813 Listener: l,
2814 Config: &http.Server{},
2815 }
2816 s.Start()
2817
2818 return 0, s, nil
2819 },
2820 address: "0.0.0.0",
2821 },
2822 want: true,
2823 },
2824 {
2825 name: "random port bound on 0.0.0.0",
2826 args: args{
2827 portProvider: func(address string) (int, serverCloser, error) {
2828
2829 l, err := net.Listen("tcp", fmt.Sprintf("%s:0", address))
2830 if err != nil {
2831 return 0, nil, err
2832 }
2833 s := &httptest.Server{
2834 Listener: l,
2835 Config: &http.Server{},
2836 }
2837 s.Start()
2838
2839 _, p, err := net.SplitHostPort(strings.TrimPrefix(s.URL, "http://"))
2840 if err != nil {
2841 return 0, s, err
2842 }
2843 port, err := strconv.Atoi(p)
2844 if err != nil {
2845 return 0, s, err
2846 }
2847 return port, s, nil
2848 },
2849 address: "0.0.0.0",
2850 },
2851 want: false,
2852 },
2853 }
2854
2855 for _, tt := range tests {
2856 t.Run(tt.name, func(t *testing.T) {
2857 port := tt.args.port
2858 var s serverCloser
2859 var err error
2860 if tt.args.portProvider != nil {
2861 port, s, err = tt.args.portProvider(tt.args.address)
2862 if s != nil {
2863 defer s.Close()
2864 }
2865 if err != nil {
2866 t.Errorf("error while computing port: %v", err)
2867 return
2868 }
2869 }
2870
2871 if got := IsPortFree(port, tt.args.address); got != tt.want {
2872 t.Errorf("IsPortFree() = %v, want %v", got, tt.want)
2873 }
2874 })
2875 }
2876
2877 }
2878
View as plain text