1 package registry
2
3 import (
4 "context"
5 "errors"
6 "fmt"
7 "io/fs"
8 "net/http"
9 "net/http/httptest"
10 "os"
11 "path/filepath"
12 "runtime"
13 "sort"
14 "strings"
15 "testing"
16
17 devfilev1 "github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2"
18
19 "github.com/golang/mock/gomock"
20 "github.com/google/go-cmp/cmp"
21 "github.com/google/go-cmp/cmp/cmpopts"
22
23 "github.com/redhat-developer/odo/pkg/api"
24 "github.com/redhat-developer/odo/pkg/config"
25 envcontext "github.com/redhat-developer/odo/pkg/config/context"
26 "github.com/redhat-developer/odo/pkg/kclient"
27 "github.com/redhat-developer/odo/pkg/preference"
28 "github.com/redhat-developer/odo/pkg/testingutil/filesystem"
29 )
30
31 func TestGetDevfileRegistries(t *testing.T) {
32 tempConfigFile, err := os.CreateTemp("", "odoconfig")
33 if err != nil {
34 t.Fatal("Fail to create temporary config file")
35 }
36 defer os.Remove(tempConfigFile.Name())
37 defer tempConfigFile.Close()
38 _, err = tempConfigFile.Write([]byte(
39 `kind: Preference
40 apiversion: odo.openshift.io/v1alpha1
41 OdoSettings:
42 RegistryList:
43 - Name: DefaultDevfileRegistry
44 URL: https://registry.devfile.io
45 - Name: CheDevfileRegistry
46 URL: https://che-devfile-registry.openshift.io/`,
47 ))
48 if err != nil {
49 t.Error(err)
50 }
51 tempConfigFileName := tempConfigFile.Name()
52
53 tests := []struct {
54 name string
55 registryName string
56 kclient func(ctrl *gomock.Controller) kclient.ClientInterface
57 want []api.Registry
58 wantErr bool
59 }{
60 {
61 name: "Case 1: Test get all devfile registries",
62 registryName: "",
63 want: []api.Registry{
64 {
65 Name: "CheDevfileRegistry",
66 URL: "https://che-devfile-registry.openshift.io/",
67 Secure: false,
68 },
69 {
70 Name: "DefaultDevfileRegistry",
71 URL: "https://registry.devfile.io",
72 Secure: false,
73 },
74 },
75 },
76 {
77 name: "Case 2: Test get specific devfile registry",
78 registryName: "CheDevfileRegistry",
79 want: []api.Registry{
80 {
81 Name: "CheDevfileRegistry",
82 URL: "https://che-devfile-registry.openshift.io/",
83 Secure: false,
84 },
85 },
86 },
87 {
88 name: "with devfileRegistrylists in cluster",
89 kclient: func(ctrl *gomock.Controller) kclient.ClientInterface {
90 result := kclient.NewMockClientInterface(ctrl)
91 list := []api.Registry{
92 {
93 Name: "secure-name",
94 URL: "secure-url",
95 Secure: true,
96 },
97 {
98 Name: "unsecure-name",
99 URL: "unsecure-url",
100 Secure: false,
101 },
102 }
103 result.EXPECT().GetRegistryList().Return(list, nil)
104 return result
105 },
106 want: []api.Registry{
107 {
108 Name: "secure-name",
109 URL: "secure-url",
110 Secure: true,
111 },
112 {
113 Name: "unsecure-name",
114 URL: "unsecure-url",
115 Secure: false,
116 },
117 {
118 Name: "CheDevfileRegistry",
119 URL: "https://che-devfile-registry.openshift.io/",
120 Secure: false,
121 },
122 {
123 Name: "DefaultDevfileRegistry",
124 URL: "https://registry.devfile.io",
125 Secure: false,
126 },
127 },
128 },
129 {
130 name: "error getting devfileRegistrylists from cluster",
131 kclient: func(ctrl *gomock.Controller) kclient.ClientInterface {
132 result := kclient.NewMockClientInterface(ctrl)
133 result.EXPECT().GetRegistryList().Return(nil, errors.New("an error"))
134 return result
135 },
136 want: []api.Registry{
137 {
138 Name: "CheDevfileRegistry",
139 URL: "https://che-devfile-registry.openshift.io/",
140 Secure: false,
141 },
142 {
143 Name: "DefaultDevfileRegistry",
144 URL: "https://registry.devfile.io",
145 Secure: false,
146 },
147 },
148 },
149 }
150
151 for _, tt := range tests {
152 t.Run(tt.name, func(t *testing.T) {
153 ctx := context.Background()
154 ctx = envcontext.WithEnvConfig(ctx, config.Configuration{
155 Globalodoconfig: &tempConfigFileName,
156 })
157
158 ctrl := gomock.NewController(t)
159
160 prefClient, _ := preference.NewClient(ctx)
161 var kc kclient.ClientInterface
162 if tt.kclient != nil {
163 kc = tt.kclient(ctrl)
164 }
165 catClient := NewRegistryClient(filesystem.NewFakeFs(), prefClient, kc)
166 got, err := catClient.GetDevfileRegistries(tt.registryName)
167
168 if tt.wantErr != (err != nil) {
169 t.Errorf("error = %v, wantErr %v", err, tt.wantErr)
170 }
171
172 if diff := cmp.Diff(tt.want, got); diff != "" {
173 t.Errorf("RegistryClient.GetDevfileRegistries() mismatch (-want +got):\n%s", diff)
174 }
175 })
176 }
177 }
178
179 func TestListDevfileStacks(t *testing.T) {
180
181
182 server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
183
184 _, err := rw.Write([]byte(
185 `
186 [
187 {
188 "name": "nodejs",
189 "displayName": "NodeJS Angular Web Application",
190 "description": "Stack for developing NodeJS Angular Web Application",
191 "tags": [
192 "NodeJS",
193 "Angular",
194 "Alpine"
195 ],
196 "language": "nodejs",
197 "icon": "/images/angular.svg",
198 "globalMemoryLimit": "2686Mi",
199 "links": {
200 "self": "/devfiles/angular/devfile.yaml"
201 }
202 },
203 {
204 "name": "python",
205 "displayName": "Python",
206 "description": "Python Stack with Python 3.7",
207 "tags": [
208 "Python",
209 "pip"
210 ],
211 "architectures": [
212 "amd64",
213 "ppc64le",
214 "s390x"
215 ],
216 "language": "python",
217 "icon": "/images/foobar.svg",
218 "globalMemoryLimit": "2686Mi",
219 "links": {
220 "self": "/devfiles/python/devfile.yaml"
221 }
222 }
223 ]
224 `,
225 ))
226 if err != nil {
227 t.Error(err)
228 }
229 }))
230
231 defer server.Close()
232
233 const registryName = "TestRegistry"
234 tests := []struct {
235 name string
236 registryName string
237 devfileName string
238 filter string
239 want DevfileStackList
240 }{
241 {
242 name: "Case 1: Test getting ALL registries and looking for nodejs",
243 registryName: "",
244 want: DevfileStackList{
245 DevfileRegistries: []api.Registry{
246 {
247 Name: "TestRegistry",
248 URL: server.URL,
249 Secure: false,
250 },
251 },
252 Items: []api.DevfileStack{
253 {
254 Name: "nodejs",
255 DisplayName: "NodeJS Angular Web Application",
256 Description: "Stack for developing NodeJS Angular Web Application",
257 Registry: api.Registry{
258 Name: registryName,
259 URL: server.URL,
260 },
261 Language: "nodejs",
262 Tags: []string{"NodeJS", "Angular", "Alpine"},
263 },
264 {
265 Name: "python",
266 DisplayName: "Python",
267 Description: "Python Stack with Python 3.7",
268 Registry: api.Registry{
269 Name: registryName,
270 URL: server.URL,
271 },
272 Language: "python",
273 Tags: []string{"Python", "pip"},
274 Architectures: []string{"amd64", "ppc64le", "s390x"},
275 },
276 },
277 },
278 },
279 {
280 name: "Case 2: Test getting from only one specific devfile and from a specific registry",
281 registryName: "TestRegistry",
282 devfileName: "nodejs",
283 want: DevfileStackList{
284 DevfileRegistries: []api.Registry{
285 {
286 Name: "TestRegistry",
287 URL: server.URL,
288 Secure: false,
289 },
290 },
291 Items: []api.DevfileStack{
292 {
293 Name: "nodejs",
294 DisplayName: "NodeJS Angular Web Application",
295 Description: "Stack for developing NodeJS Angular Web Application",
296 Registry: api.Registry{
297 Name: registryName,
298 URL: server.URL,
299 },
300 Language: "nodejs",
301 Tags: []string{"NodeJS", "Angular", "Alpine"},
302 },
303 },
304 },
305 },
306 {
307 name: "Case 3: Test getting a devfile using a filter from the description",
308 registryName: "TestRegistry",
309 filter: "Python Stack",
310 want: DevfileStackList{
311 DevfileRegistries: []api.Registry{
312 {
313 Name: "TestRegistry",
314 URL: server.URL,
315 Secure: false,
316 },
317 },
318 Items: []api.DevfileStack{
319 {
320 Name: "python",
321 DisplayName: "Python",
322 Description: "Python Stack with Python 3.7",
323 Registry: api.Registry{
324 Name: registryName,
325 URL: server.URL,
326 },
327 Language: "python",
328 Tags: []string{"Python", "pip"},
329 Architectures: []string{"amd64", "ppc64le", "s390x"},
330 },
331 },
332 },
333 },
334 {
335 name: "Case 3.2: Test getting a devfile using a filter from the architectures",
336 registryName: "TestRegistry",
337 filter: "s390",
338 want: DevfileStackList{
339 DevfileRegistries: []api.Registry{
340 {
341 Name: "TestRegistry",
342 URL: server.URL,
343 Secure: false,
344 },
345 },
346 Items: []api.DevfileStack{
347
348
349 {
350 Name: "nodejs",
351 DisplayName: "NodeJS Angular Web Application",
352 Description: "Stack for developing NodeJS Angular Web Application",
353 Registry: api.Registry{
354 Name: registryName,
355 URL: server.URL,
356 },
357 Language: "nodejs",
358 Tags: []string{"NodeJS", "Angular", "Alpine"},
359 },
360 {
361 Name: "python",
362 DisplayName: "Python",
363 Description: "Python Stack with Python 3.7",
364 Registry: api.Registry{
365 Name: registryName,
366 URL: server.URL,
367 },
368 Language: "python",
369 Tags: []string{"Python", "pip"},
370 Architectures: []string{"amd64", "ppc64le", "s390x"},
371 },
372 },
373 },
374 },
375 {
376 name: "Case 3.3: Test getting a devfile using a filter not matching name, description or architectures",
377 registryName: "TestRegistry",
378 filter: "some-random-string",
379 want: DevfileStackList{
380 DevfileRegistries: []api.Registry{
381 {
382 Name: "TestRegistry",
383 URL: server.URL,
384 Secure: false,
385 },
386 },
387 },
388 },
389 {
390 name: "Case 4: Expect nothing back if registry is not found",
391 registryName: "Foobar",
392 want: DevfileStackList{},
393 },
394 }
395
396 for _, tt := range tests {
397 t.Run(tt.name, func(t *testing.T) {
398 ctrl := gomock.NewController(t)
399 prefClient := preference.NewMockClient(ctrl)
400 prefClient.EXPECT().RegistryList().Return([]api.Registry{
401 {
402 Name: "TestRegistry",
403 URL: server.URL,
404 },
405 }).AnyTimes()
406
407 catClient := NewRegistryClient(filesystem.NewFakeFs(), prefClient, nil)
408 ctx := context.Background()
409 ctx = envcontext.WithEnvConfig(ctx, config.Configuration{})
410 got, err := catClient.ListDevfileStacks(ctx, tt.registryName, tt.devfileName, tt.filter, false, false)
411 if err != nil {
412 t.Error(err)
413 }
414
415 if diff := cmp.Diff(tt.want, got, cmpopts.EquateEmpty()); diff != "" {
416 t.Errorf("RegistryClient.ListDevfileStacks() mismatch (-want +got):\n%s", diff)
417 }
418 })
419 }
420 }
421
422 func TestGetRegistryDevfiles(t *testing.T) {
423 const registryName = "some registry"
424 const (
425 v1IndexResponse = `
426 [
427 {
428 "name": "nodejs",
429 "displayName": "NodeJS Angular Web Application",
430 "description": "Stack for developing NodeJS Angular Web Application",
431 "version": "1.2.3",
432 "tags": [
433 "NodeJS",
434 "Angular",
435 "Alpine"
436 ],
437 "language": "nodejs",
438 "icon": "/images/angular.svg",
439 "globalMemoryLimit": "2686Mi",
440 "links": {
441 "self": "/devfiles/angular/devfile.yaml"
442 }
443 },
444 {
445 "name": "python",
446 "displayName": "Python Application",
447 "description": "Stack for developing a Python Web Application",
448 "version": "2.3.4",
449 "tags": ["Python"],
450 "language": "python",
451 "architectures": [
452 "amd64",
453 "ppc64le"
454 ],
455 "links": {
456 "self": "/devfiles/python/devfile.yaml"
457 }
458 }
459 ]
460 `
461 v2IndexResponse = `
462 [
463 {
464 "name": "go",
465 "displayName": "Go Runtime",
466 "description": "Go is an open source programming language that makes it easy to build simple, reliable, and efficient software.",
467 "type": "stack",
468 "tags": [
469 "Go"
470 ],
471 "icon": "https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/golang.svg",
472 "projectType": "Go",
473 "language": "Go",
474 "provider": "Red Hat",
475 "versions": [
476 {
477 "version": "2.0.0",
478 "schemaVersion": "2.2.0",
479 "description": "Go is an open source programming language that makes it easy to build simple, reliable, and efficient software.",
480 "tags": [
481 "Go"
482 ],
483 "icon": "https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/golang.svg",
484 "links": {
485 "self": "devfile-catalog/go:2.0.0"
486 },
487 "resources": [
488 "devfile.yaml"
489 ],
490 "starterProjects": [
491 "go-starter"
492 ]
493 },
494 {
495 "version": "1.0.2",
496 "schemaVersion": "2.1.0",
497 "default": true,
498 "description": "Go is an open source programming language that makes it easy to build simple, reliable, and efficient software.",
499 "tags": [
500 "Go"
501 ],
502 "icon": "https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/golang.svg",
503 "links": {
504 "self": "devfile-catalog/go:1.0.2"
505 },
506 "resources": [
507 "devfile.yaml"
508 ],
509 "starterProjects": [
510 "go-starter"
511 ]
512 }
513 ]
514 },
515 {
516 "name": "python",
517 "displayName": "Python Application",
518 "description": "Python Stack",
519 "type": "stack",
520 "tags": [
521 "Python"
522 ],
523 "architectures": [
524 "amd64",
525 "ppc64le"
526 ],
527 "projectType": "Python",
528 "language": "Python",
529 "versions": [
530 {
531 "version": "2.3.4",
532 "schemaVersion": "2.2.0",
533 "description": "Python stack.",
534 "tags": [
535 "Python"
536 ],
537 "icon": "https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/python.svg",
538 "links": {
539 "self": "devfile-catalog/python:2.0.0"
540 },
541 "resources": [
542 "devfile.yaml"
543 ],
544 "starterProjects": [
545 "python-starter"
546 ]
547 },
548 {
549 "version": "1.2.3",
550 "schemaVersion": "2.1.0",
551 "default": true,
552 "description": "Python stack.",
553 "tags": [
554 "Python"
555 ],
556 "icon": "https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/python.svg",
557 "links": {
558 "self": "devfile-catalog/python:2.0.0"
559 },
560 "resources": [
561 "devfile.yaml"
562 ],
563 "starterProjects": [
564 "python-starter"
565 ]
566 }
567 ]
568 }
569 ]
570 `
571 )
572
573 type test struct {
574 name string
575 registryServerProvider func(t *testing.T) (*httptest.Server, string)
576 wantErr bool
577 wantProvider func(registryUrl string) []api.DevfileStack
578 }
579 tests := []test{
580 {
581 name: "GitHub-based registry: github.com",
582 registryServerProvider: func(t *testing.T) (*httptest.Server, string) {
583 return nil, "https://github.com/redhat-developer/odo"
584 },
585 wantErr: true,
586 },
587 {
588 name: "GitHub-based registry: raw.githubusercontent.com",
589 registryServerProvider: func(t *testing.T) (*httptest.Server, string) {
590 return nil, "https://raw.githubusercontent.com/redhat-developer/odo"
591 },
592 wantErr: true,
593 },
594 {
595 name: "GitHub-based registry: *.github.com",
596 registryServerProvider: func(t *testing.T) (*httptest.Server, string) {
597 return nil, "https://redhat-developer.github.com/odo"
598 },
599 wantErr: true,
600 },
601 {
602 name: "GitHub-based registry: *.raw.githubusercontent.com",
603 registryServerProvider: func(t *testing.T) (*httptest.Server, string) {
604 return nil, "https://redhat-developer.raw.githubusercontent.com/odo"
605 },
606 wantErr: true,
607 },
608 {
609 name: "Devfile registry server: client error (4xx)",
610 registryServerProvider: func(t *testing.T) (*httptest.Server, string) {
611 server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
612 rw.WriteHeader(http.StatusNotFound)
613 }))
614 return server, server.URL
615 },
616 wantErr: true,
617 },
618 {
619 name: "Devfile registry server: server error (5xx)",
620 registryServerProvider: func(t *testing.T) (*httptest.Server, string) {
621 server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
622 rw.WriteHeader(http.StatusInternalServerError)
623 }))
624 return server, server.URL
625 },
626 wantErr: true,
627 },
628 {
629 name: "Devfile registry: only /index",
630 registryServerProvider: func(t *testing.T) (*httptest.Server, string) {
631 server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
632 if req.URL.Path != "/index" {
633 rw.WriteHeader(http.StatusNotFound)
634 return
635 }
636 _, err := rw.Write([]byte(v1IndexResponse))
637 if err != nil {
638 t.Error(err)
639 }
640 }))
641 return server, server.URL
642 },
643 wantProvider: func(registryUrl string) []api.DevfileStack {
644 return []api.DevfileStack{
645 {
646 Name: "nodejs",
647 DisplayName: "NodeJS Angular Web Application",
648 Description: "Stack for developing NodeJS Angular Web Application",
649 Registry: api.Registry{Name: registryName, URL: registryUrl},
650 Language: "nodejs",
651 Tags: []string{"NodeJS", "Angular", "Alpine"},
652 DefaultVersion: "1.2.3",
653 },
654 {
655 Name: "python",
656 DisplayName: "Python Application",
657 Description: "Stack for developing a Python Web Application",
658 Registry: api.Registry{Name: registryName, URL: registryUrl},
659 Language: "python",
660 Tags: []string{"Python"},
661 Architectures: []string{"amd64", "ppc64le"},
662 DefaultVersion: "2.3.4",
663 },
664 }
665 },
666 },
667 {
668 name: "Devfile registry: only /v2index",
669 registryServerProvider: func(t *testing.T) (*httptest.Server, string) {
670 server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
671 if req.URL.Path != "/v2index" {
672 rw.WriteHeader(http.StatusNotFound)
673 return
674 }
675 _, err := rw.Write([]byte(v2IndexResponse))
676 if err != nil {
677 t.Error(err)
678 }
679 }))
680 return server, server.URL
681 },
682 wantProvider: func(registryUrl string) []api.DevfileStack {
683 return []api.DevfileStack{
684 {
685 Name: "go",
686 DisplayName: "Go Runtime",
687 Description: "Go is an open source programming language that makes it easy to build simple, reliable, and efficient software.",
688 Registry: api.Registry{Name: registryName, URL: registryUrl},
689 Language: "Go",
690 ProjectType: "Go",
691 Tags: []string{"Go"},
692 DefaultVersion: "1.0.2",
693 DefaultStarterProjects: []string{"go-starter"},
694 Versions: []api.DevfileStackVersion{
695 {Version: "1.0.2", IsDefault: true, SchemaVersion: "2.1.0", StarterProjects: []string{"go-starter"}},
696 {Version: "2.0.0", IsDefault: false, SchemaVersion: "2.2.0", StarterProjects: []string{"go-starter"}},
697 },
698 },
699 {
700 Name: "python",
701 DisplayName: "Python Application",
702 Description: "Python Stack",
703 Registry: api.Registry{Name: registryName, URL: registryUrl},
704 Language: "Python",
705 ProjectType: "Python",
706 Tags: []string{"Python"},
707 DefaultVersion: "1.2.3",
708 DefaultStarterProjects: []string{"python-starter"},
709 Versions: []api.DevfileStackVersion{
710 {Version: "1.2.3", IsDefault: true, SchemaVersion: "2.1.0", StarterProjects: []string{"python-starter"}},
711 {Version: "2.3.4", IsDefault: false, SchemaVersion: "2.2.0", StarterProjects: []string{"python-starter"}},
712 },
713 Architectures: []string{"amd64", "ppc64le"},
714 },
715 }
716 },
717 },
718 {
719 name: "Devfile registry: both /index and /v2index => v2index has precedence",
720 registryServerProvider: func(t *testing.T) (*httptest.Server, string) {
721 server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
722 var resp string
723 switch req.URL.Path {
724 case "/index":
725 resp = v1IndexResponse
726 case "/v2index":
727 resp = v2IndexResponse
728 }
729 if resp == "" {
730 rw.WriteHeader(http.StatusNotFound)
731 return
732 }
733 _, err := rw.Write([]byte(resp))
734 if err != nil {
735 t.Error(err)
736 }
737 }))
738 return server, server.URL
739 },
740 wantProvider: func(registryUrl string) []api.DevfileStack {
741 return []api.DevfileStack{
742 {
743 Name: "go",
744 DisplayName: "Go Runtime",
745 Description: "Go is an open source programming language that makes it easy to build simple, reliable, and efficient software.",
746 Registry: api.Registry{Name: registryName, URL: registryUrl},
747 Language: "Go",
748 ProjectType: "Go",
749 Tags: []string{"Go"},
750 DefaultVersion: "1.0.2",
751 DefaultStarterProjects: []string{"go-starter"},
752 Versions: []api.DevfileStackVersion{
753 {Version: "1.0.2", IsDefault: true, SchemaVersion: "2.1.0", StarterProjects: []string{"go-starter"}},
754 {Version: "2.0.0", IsDefault: false, SchemaVersion: "2.2.0", StarterProjects: []string{"go-starter"}},
755 },
756 },
757 {
758 Name: "python",
759 DisplayName: "Python Application",
760 Description: "Python Stack",
761 Registry: api.Registry{Name: registryName, URL: registryUrl},
762 Language: "Python",
763 ProjectType: "Python",
764 Tags: []string{"Python"},
765 Architectures: []string{"amd64", "ppc64le"},
766 DefaultVersion: "1.2.3",
767 DefaultStarterProjects: []string{"python-starter"},
768 Versions: []api.DevfileStackVersion{
769 {Version: "1.2.3", IsDefault: true, SchemaVersion: "2.1.0", StarterProjects: []string{"python-starter"}},
770 {Version: "2.3.4", IsDefault: false, SchemaVersion: "2.2.0", StarterProjects: []string{"python-starter"}},
771 },
772 },
773 }
774 },
775 },
776 }
777
778 for _, tt := range tests {
779 t.Run(tt.name, func(t *testing.T) {
780 ctx := envcontext.WithEnvConfig(context.Background(), config.Configuration{})
781 server, url := tt.registryServerProvider(t)
782 if server != nil {
783 defer server.Close()
784 }
785
786 got, err := getRegistryStacks(ctx, api.Registry{Name: registryName, URL: url})
787
788 if tt.wantErr != (err != nil) {
789 t.Errorf("error = %v, wantErr %v", err, tt.wantErr)
790 }
791
792 if tt.wantProvider != nil {
793 want := tt.wantProvider(url)
794 if diff := cmp.Diff(want, got); diff != "" {
795 t.Errorf("getRegistryStacks() mismatch (-want +got):\n%s", diff)
796 t.Logf("Error message is: %v", err)
797 }
798 }
799 })
800 }
801 }
802
803 func TestRegistryClient_DownloadStarterProject(t *testing.T) {
804 setupFS := func(contextDir string, fs filesystem.Filesystem) {
805 directoriesToBeCreated := []string{"kubernetes", "docker"}
806 for _, dirToBeCreated := range directoriesToBeCreated {
807 dirName := filepath.Join(contextDir, dirToBeCreated)
808 err := fs.MkdirAll(dirName, os.FileMode(0750))
809 if err != nil {
810 t.Errorf("failed to create %s; cause: %s", dirName, err)
811 }
812 }
813
814 filesToBeCreated := []string{"devfile.yaml", "kubernetes/deploy.yaml", "docker/Dockerfile"}
815 for _, fileToBeCreated := range filesToBeCreated {
816 fileName := filepath.Join(contextDir, fileToBeCreated)
817 _, err := fs.Create(fileName)
818 if err != nil {
819 t.Errorf("failed to create %s; cause: %s", fileName, err)
820 }
821 }
822 }
823
824 getZipFilePath := func(name string) string {
825
826 _, filename, _, _ := runtime.Caller(0)
827
828 return filepath.Join(filepath.Dir(filename), "..", "..", "tests", "examples", filepath.Join("source", "devfiles", "zips", name))
829 }
830 type fields struct {
831 fsys filesystem.Filesystem
832 preferenceClient preference.Client
833 kubeClient kclient.ClientInterface
834 }
835 type args struct {
836 starterProject *devfilev1.StarterProject
837 decryptedToken string
838 contextDir string
839 verbose bool
840 }
841 tests := []struct {
842 name string
843 fields fields
844 args args
845 want []string
846 wantContainsDevfile bool
847 wantErr bool
848 }{
849
850 {
851 name: "Starter project has a Devfile",
852 fields: fields{
853 fsys: filesystem.NewFakeFs(),
854 },
855 args: args{
856 starterProject: &devfilev1.StarterProject{
857 Name: "starter-project-with-devfile",
858 ProjectSource: devfilev1.ProjectSource{
859 SourceType: "",
860 Zip: &devfilev1.ZipProjectSource{
861 CommonProjectSource: devfilev1.CommonProjectSource{},
862 Location: fmt.Sprintf("file://%s", getZipFilePath("starterproject-with-devfile.zip")),
863 },
864 },
865 },
866 },
867 want: []string{"devfile.yaml", "docker", filepath.Join("docker", "Dockerfile"), "README.md", "main.go", "go.mod", "someFile.txt"},
868 wantErr: false,
869 wantContainsDevfile: true,
870 },
871 {
872 name: "Starter project has conflicting files",
873 fields: fields{
874 fsys: filesystem.NewFakeFs(),
875 },
876 args: args{
877 starterProject: &devfilev1.StarterProject{
878 Name: "starter-project-with-conflicting-files",
879 ProjectSource: devfilev1.ProjectSource{
880 SourceType: "",
881 Zip: &devfilev1.ZipProjectSource{
882 CommonProjectSource: devfilev1.CommonProjectSource{},
883 Location: fmt.Sprintf("file://%s", getZipFilePath("starterproject-with-conflicts.zip")),
884 },
885 },
886 },
887 },
888 want: []string{"devfile.yaml", "docker", filepath.Join("docker", "Dockerfile"), "kubernetes", filepath.Join("kubernetes", "deploy.yaml"),
889 CONFLICT_DIR_NAME, filepath.Join(CONFLICT_DIR_NAME, "kubernetes"), filepath.Join(CONFLICT_DIR_NAME, "kubernetes", "deploy.yaml"),
890 filepath.Join(CONFLICT_DIR_NAME, "main.go"), filepath.Join(CONFLICT_DIR_NAME, "go.mod"), filepath.Join(CONFLICT_DIR_NAME, "README.md"), filepath.Join(CONFLICT_DIR_NAME, "someFile.txt")},
891 wantErr: false,
892 },
893 {
894 name: "Starter project has conflicting files and an empty dir",
895 fields: fields{
896 fsys: filesystem.NewFakeFs(),
897 },
898 args: args{
899 starterProject: &devfilev1.StarterProject{
900 Name: "starter-project-with-conflicting-files-and-empty-dir",
901 ProjectSource: devfilev1.ProjectSource{
902 SourceType: "",
903 Zip: &devfilev1.ZipProjectSource{
904 CommonProjectSource: devfilev1.CommonProjectSource{},
905 Location: fmt.Sprintf("file://%s", getZipFilePath("starterproject-with-conflicts-and-empty-dir.zip")),
906 },
907 },
908 },
909 },
910 want: []string{"devfile.yaml", "docker", filepath.Join("docker", "Dockerfile"), "kubernetes", filepath.Join("kubernetes", "deploy.yaml"),
911 filepath.Join(CONFLICT_DIR_NAME, "kubernetes"), CONFLICT_DIR_NAME, filepath.Join(CONFLICT_DIR_NAME, "docker"), filepath.Join(CONFLICT_DIR_NAME, "docker", "Dockerfile"),
912 filepath.Join(CONFLICT_DIR_NAME, "main.go"), filepath.Join(CONFLICT_DIR_NAME, "go.mod"), filepath.Join(CONFLICT_DIR_NAME, "README.md")},
913 wantErr: false,
914 },
915 {
916 name: "Starter project does not have any conflicting files",
917 fields: fields{
918 fsys: filesystem.NewFakeFs(),
919 },
920 args: args{
921 starterProject: &devfilev1.StarterProject{
922 Name: "starter-project-with-no-conflicting-files",
923 ProjectSource: devfilev1.ProjectSource{
924 SourceType: "",
925 Zip: &devfilev1.ZipProjectSource{
926 CommonProjectSource: devfilev1.CommonProjectSource{},
927 Location: fmt.Sprintf("file://%s", getZipFilePath("starterproject-with-no-conflicts.zip")),
928 },
929 },
930 },
931 },
932 want: []string{"devfile.yaml", "docker", filepath.Join("docker", "Dockerfile"), "kubernetes", filepath.Join("kubernetes", "deploy.yaml"), "README.md", "main.go", "go.mod"},
933 wantErr: false,
934 },
935 {
936 name: "Starter project does not have any conflicting files but has empty dir",
937 fields: fields{
938 fsys: filesystem.NewFakeFs(),
939 },
940 args: args{
941 starterProject: &devfilev1.StarterProject{
942 Name: "starter-project-with-no-conflicting-files-and-empty-dir",
943 ProjectSource: devfilev1.ProjectSource{
944 SourceType: "",
945 Zip: &devfilev1.ZipProjectSource{
946 CommonProjectSource: devfilev1.CommonProjectSource{},
947 Location: fmt.Sprintf("file://%s", getZipFilePath("starterproject-with-no-conflicts-and-empty-dir.zip")),
948 },
949 },
950 },
951 },
952 want: []string{"devfile.yaml", "docker", filepath.Join("docker", "Dockerfile"), "kubernetes", filepath.Join("kubernetes", "deploy.yaml"), "README.md", "main.go", "go.mod"},
953 wantErr: false,
954 },
955 }
956 for _, tt := range tests {
957 t.Run(tt.name, func(t *testing.T) {
958 contextDir, ferr := tt.fields.fsys.TempDir("", "downloadstarterproject")
959 if ferr != nil {
960 t.Errorf("failed to create temp dir; cause: %s", ferr)
961 }
962 tt.args.contextDir = contextDir
963
964 setupFS(tt.args.contextDir, tt.fields.fsys)
965
966 o := RegistryClient{
967 fsys: tt.fields.fsys,
968 preferenceClient: tt.fields.preferenceClient,
969 kubeClient: tt.fields.kubeClient,
970 }
971 gotContainsDevfile, gotErr := o.DownloadStarterProject(tt.args.starterProject, tt.args.decryptedToken, tt.args.contextDir, tt.args.verbose)
972 if (gotErr != nil) != tt.wantErr {
973 t.Errorf("DownloadStarterProject() error = %v, wantErr %v", gotErr, tt.wantErr)
974 return
975 }
976 if tt.wantContainsDevfile != gotContainsDevfile {
977 t.Errorf("DownloadStarterProject() containsDevfile = %v, want = %v", gotContainsDevfile, tt.wantContainsDevfile)
978 return
979 }
980 var got []string
981 err := o.fsys.Walk(contextDir, func(path string, info fs.FileInfo, err error) error {
982 path = strings.TrimPrefix(path, contextDir)
983 path = strings.TrimPrefix(path, string(os.PathSeparator))
984 if path != "" {
985 got = append(got, path)
986 }
987 return nil
988 })
989 if err != nil {
990 t.Errorf("failed to walk %s; cause:%s", contextDir, err.Error())
991 return
992 }
993 sort.Strings(got)
994 sort.Strings(tt.want)
995 if diff := cmp.Diff(got, tt.want); diff != "" {
996 t.Errorf("DownloadStarterProject() mismatch (-want +got):\n%s", diff)
997 }
998 })
999 }
1000 }
1001
View as plain text