1 package libdevfile
2
3 import (
4 "testing"
5
6 "github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2"
7 "github.com/devfile/api/v2/pkg/attributes"
8 "github.com/devfile/api/v2/pkg/validation"
9 "github.com/devfile/library/v2/pkg/devfile"
10 "github.com/devfile/library/v2/pkg/devfile/parser"
11 context "github.com/devfile/library/v2/pkg/devfile/parser/context"
12 "github.com/devfile/library/v2/pkg/devfile/parser/data"
13 "github.com/devfile/library/v2/pkg/testingutil/filesystem"
14 "github.com/google/go-cmp/cmp"
15
16 "github.com/redhat-developer/odo/pkg/libdevfile/generator"
17
18 apiext "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
19 "k8s.io/utils/pointer"
20 )
21
22 func TestGetReferencedLocalFiles(t *testing.T) {
23
24 imageComponentNoDockerfile := generator.GetImageComponent(generator.ImageComponentParams{
25 Name: "image-component",
26 Image: v1alpha2.Image{
27 ImageName: "an-image-name",
28 },
29 })
30 imageComponentWithHTTPDockerfile := generator.GetImageComponent(generator.ImageComponentParams{
31 Name: "image-component",
32 Image: v1alpha2.Image{
33 ImageName: "an-image-name",
34 ImageUnion: v1alpha2.ImageUnion{
35 Dockerfile: &v1alpha2.DockerfileImage{
36 DockerfileSrc: v1alpha2.DockerfileSrc{
37 Uri: "http://example.com",
38 },
39 },
40 },
41 },
42 })
43 imageComponentWithLocalDockerfile := generator.GetImageComponent(generator.ImageComponentParams{
44 Name: "image-component",
45 Image: v1alpha2.Image{
46 ImageName: "an-image-name",
47 ImageUnion: v1alpha2.ImageUnion{
48 Dockerfile: &v1alpha2.DockerfileImage{
49 DockerfileSrc: v1alpha2.DockerfileSrc{
50 Uri: "path/to/Dockerfile",
51 },
52 },
53 },
54 },
55 })
56
57 kubeComponentInlined := generator.GetKubernetesComponent(generator.KubernetesComponentParams{
58 Name: "kube-component",
59 Kubernetes: &v1alpha2.KubernetesComponent{
60 K8sLikeComponent: v1alpha2.K8sLikeComponent{
61 K8sLikeComponentLocation: v1alpha2.K8sLikeComponentLocation{
62 Inlined: "",
63 },
64 },
65 },
66 })
67 kubeComponentHTTPUri := generator.GetKubernetesComponent(generator.KubernetesComponentParams{
68 Name: "kube-component",
69 Kubernetes: &v1alpha2.KubernetesComponent{
70 K8sLikeComponent: v1alpha2.K8sLikeComponent{
71 K8sLikeComponentLocation: v1alpha2.K8sLikeComponentLocation{
72 Uri: "http://example.com",
73 },
74 },
75 },
76 })
77 kubeComponentLocalUri := generator.GetKubernetesComponent(generator.KubernetesComponentParams{
78 Name: "kube-component",
79 Kubernetes: &v1alpha2.KubernetesComponent{
80 K8sLikeComponent: v1alpha2.K8sLikeComponent{
81 K8sLikeComponentLocation: v1alpha2.K8sLikeComponentLocation{
82 Uri: "path/to/manifest",
83 },
84 },
85 },
86 })
87
88 openshiftComponentInlined := generator.GetOpenshiftComponent(generator.OpenshiftComponentParams{
89 Name: "openshift-component",
90 Openshift: &v1alpha2.OpenshiftComponent{
91 K8sLikeComponent: v1alpha2.K8sLikeComponent{
92 K8sLikeComponentLocation: v1alpha2.K8sLikeComponentLocation{
93 Inlined: "",
94 },
95 },
96 },
97 })
98 openshiftComponentHTTPUri := generator.GetOpenshiftComponent(generator.OpenshiftComponentParams{
99 Name: "openshift-component",
100 Openshift: &v1alpha2.OpenshiftComponent{
101 K8sLikeComponent: v1alpha2.K8sLikeComponent{
102 K8sLikeComponentLocation: v1alpha2.K8sLikeComponentLocation{
103 Uri: "http://example.com",
104 },
105 },
106 },
107 })
108 openshiftComponentLocalUri := generator.GetOpenshiftComponent(generator.OpenshiftComponentParams{
109 Name: "openshift-component",
110 Openshift: &v1alpha2.OpenshiftComponent{
111 K8sLikeComponent: v1alpha2.K8sLikeComponent{
112 K8sLikeComponentLocation: v1alpha2.K8sLikeComponentLocation{
113 Uri: "path/to/manifest",
114 },
115 },
116 },
117 })
118
119 type args struct {
120 devfileObj func(fs filesystem.Filesystem) parser.DevfileObj
121 }
122 tests := []struct {
123 name string
124 args args
125 wantResult []string
126 wantErr bool
127 }{
128 {
129 name: "image without Dockerfile",
130 args: args{
131 devfileObj: func(fs filesystem.Filesystem) parser.DevfileObj {
132 dData, _ := data.NewDevfileData(string(data.APISchemaVersion200))
133 _ = dData.AddComponents([]v1alpha2.Component{imageComponentNoDockerfile})
134 return parser.DevfileObj{
135 Data: dData,
136 }
137 },
138 },
139 wantResult: []string{},
140 wantErr: false,
141 },
142 {
143 name: "image with HTTP Dockerfile",
144 args: args{
145 devfileObj: func(fs filesystem.Filesystem) parser.DevfileObj {
146 dData, _ := data.NewDevfileData(string(data.APISchemaVersion200))
147 _ = dData.AddComponents([]v1alpha2.Component{imageComponentWithHTTPDockerfile})
148 return parser.DevfileObj{
149 Data: dData,
150 }
151 },
152 },
153 wantResult: []string{},
154 wantErr: false,
155 },
156 {
157 name: "image with local Dockerfile",
158 args: args{
159 devfileObj: func(fs filesystem.Filesystem) parser.DevfileObj {
160 dData, _ := data.NewDevfileData(string(data.APISchemaVersion200))
161 _ = dData.AddComponents([]v1alpha2.Component{imageComponentWithLocalDockerfile})
162 return parser.DevfileObj{
163 Data: dData,
164 }
165 },
166 },
167 wantResult: []string{"path/to/Dockerfile"},
168 wantErr: false,
169 },
170
171 {
172 name: "inlined Kubernetes component",
173 args: args{
174 devfileObj: func(fs filesystem.Filesystem) parser.DevfileObj {
175 dData, _ := data.NewDevfileData(string(data.APISchemaVersion200))
176 _ = dData.AddComponents([]v1alpha2.Component{kubeComponentInlined})
177 return parser.DevfileObj{
178 Data: dData,
179 }
180 },
181 },
182 wantResult: []string{},
183 wantErr: false,
184 },
185 {
186 name: "Kubernetes component with HTTP uri",
187 args: args{
188 devfileObj: func(fs filesystem.Filesystem) parser.DevfileObj {
189 dData, _ := data.NewDevfileData(string(data.APISchemaVersion200))
190 _ = dData.AddComponents([]v1alpha2.Component{kubeComponentHTTPUri})
191 return parser.DevfileObj{
192 Data: dData,
193 }
194 },
195 },
196 wantResult: []string{},
197 wantErr: false,
198 },
199 {
200 name: "Kubernetes component with local uri",
201 args: args{
202 devfileObj: func(fs filesystem.Filesystem) parser.DevfileObj {
203 dData, _ := data.NewDevfileData(string(data.APISchemaVersion200))
204 _ = dData.AddComponents([]v1alpha2.Component{kubeComponentLocalUri})
205 return parser.DevfileObj{
206 Data: dData,
207 }
208 },
209 },
210 wantResult: []string{"path/to/manifest"},
211 wantErr: false,
212 },
213
214 {
215 name: "inlined Openshift component",
216 args: args{
217 devfileObj: func(fs filesystem.Filesystem) parser.DevfileObj {
218 dData, _ := data.NewDevfileData(string(data.APISchemaVersion200))
219 _ = dData.AddComponents([]v1alpha2.Component{openshiftComponentInlined})
220 return parser.DevfileObj{
221 Data: dData,
222 }
223 },
224 },
225 wantResult: []string{},
226 wantErr: false,
227 },
228 {
229 name: "Openshift component with HTTP uri",
230 args: args{
231 devfileObj: func(fs filesystem.Filesystem) parser.DevfileObj {
232 dData, _ := data.NewDevfileData(string(data.APISchemaVersion200))
233 _ = dData.AddComponents([]v1alpha2.Component{openshiftComponentHTTPUri})
234 return parser.DevfileObj{
235 Data: dData,
236 }
237 },
238 },
239 wantResult: []string{},
240 wantErr: false,
241 },
242 {
243 name: "Openshift component with local uri",
244 args: args{
245 devfileObj: func(fs filesystem.Filesystem) parser.DevfileObj {
246 dData, _ := data.NewDevfileData(string(data.APISchemaVersion200))
247 _ = dData.AddComponents([]v1alpha2.Component{openshiftComponentLocalUri})
248 return parser.DevfileObj{
249 Data: dData,
250 }
251 },
252 },
253 wantResult: []string{"path/to/manifest"},
254 wantErr: false,
255 },
256
257 {
258 name: "With parent Devfile, non flattened",
259 args: args{
260 devfileObj: func(fs filesystem.Filesystem) parser.DevfileObj {
261 parentData, _ := data.NewDevfileData(string(data.APISchemaVersion200))
262 parentObj := parser.DevfileObj{
263 Data: parentData,
264 Ctx: context.FakeContext(fs, "/path/to/parent/devfile.yaml"),
265 }
266 _ = parentObj.WriteYamlDevfile()
267
268 dData, _ := data.NewDevfileData(string(data.APISchemaVersion200))
269 dData.SetParent(&v1alpha2.Parent{
270 ImportReference: v1alpha2.ImportReference{
271 ImportReferenceUnion: v1alpha2.ImportReferenceUnion{
272 Uri: "/path/to/parent/devfile.yaml",
273 },
274 },
275 })
276 return parser.DevfileObj{
277 Data: dData,
278 }
279 },
280 },
281 wantResult: nil,
282 wantErr: true,
283 },
284 {
285 name: "With parent Devfile, flattened",
286 args: args{
287 devfileObj: func(fs filesystem.Filesystem) parser.DevfileObj {
288 obj, _, _ := devfile.ParseDevfileAndValidate(parser.ParserArgs{
289 Path: "testdata/child-devfile.yaml",
290 FlattenedDevfile: pointer.Bool(true),
291 })
292 return obj
293 },
294 },
295 wantResult: []string{
296 "manifest.yaml",
297 "parent/complete/parent-devfile.yaml",
298 },
299 wantErr: false,
300 },
301 {
302 name: "With parent Devfile containing only commands, flattened",
303 args: args{
304 devfileObj: func(fs filesystem.Filesystem) parser.DevfileObj {
305 obj, _, _ := devfile.ParseDevfileAndValidate(parser.ParserArgs{
306 Path: "testdata/child-devfile-components-only.yaml",
307 FlattenedDevfile: pointer.Bool(true),
308 })
309 return obj
310 },
311 },
312 wantResult: []string{
313 "manifest.yaml",
314 "parent/commands-only/parent-devfile-commands-only.yaml",
315 },
316 wantErr: false,
317 },
318 {
319 name: "With parent Devfile containing only components, flattened",
320 args: args{
321 devfileObj: func(fs filesystem.Filesystem) parser.DevfileObj {
322 obj, _, _ := devfile.ParseDevfileAndValidate(parser.ParserArgs{
323 Path: "testdata/child-devfile-commands-only.yaml",
324 FlattenedDevfile: pointer.Bool(true),
325 })
326 return obj
327 },
328 },
329 wantResult: []string{
330 "manifest.yaml",
331 "parent/components-only/parent-devfile-components-only.yaml",
332 },
333 wantErr: false,
334 },
335 {
336 name: "With empty parent Devfile, flattened. TODO find a way to detect the parent",
337 args: args{
338 devfileObj: func(fs filesystem.Filesystem) parser.DevfileObj {
339 obj, _, _ := devfile.ParseDevfileAndValidate(parser.ParserArgs{
340 Path: "testdata/child-devfile-complete.yaml",
341 FlattenedDevfile: pointer.Bool(true),
342 })
343 return obj
344 },
345 },
346 wantResult: []string{
347 "manifest.yaml",
348 },
349 wantErr: false,
350 },
351 }
352 for _, tt := range tests {
353 t.Run(tt.name, func(t *testing.T) {
354 fs := filesystem.NewFakeFs()
355 gotResult, err := GetReferencedLocalFiles(tt.args.devfileObj(fs))
356 if (err != nil) != tt.wantErr {
357 t.Errorf("GetReferencedLocalFiles() error = %v, wantErr %v", err, tt.wantErr)
358 return
359 }
360 if diff := cmp.Diff(tt.wantResult, gotResult); diff != "" {
361 t.Errorf("GetReferencedLocalFiles() wantResult mismatch (-want +got):\n%s", diff)
362 }
363 })
364 }
365 }
366
367 func Test_appendUriIfFile(t *testing.T) {
368 type args struct {
369 result map[string]struct{}
370 uri string
371 }
372 tests := []struct {
373 name string
374 args args
375 want map[string]struct{}
376 wantErr bool
377 }{
378 {
379 name: "empty uri",
380 args: args{
381 result: map[string]struct{}{},
382 uri: "",
383 },
384 want: map[string]struct{}{},
385 wantErr: false,
386 },
387 {
388 name: "http uri",
389 args: args{
390 result: map[string]struct{}{},
391 uri: "http://example.com",
392 },
393 want: map[string]struct{}{},
394 wantErr: false,
395 },
396 {
397 name: "file uri",
398 args: args{
399 result: map[string]struct{}{},
400 uri: "path/to/file",
401 },
402 want: map[string]struct{}{
403 "path/to/file": {},
404 },
405 wantErr: false,
406 },
407 }
408 for _, tt := range tests {
409 t.Run(tt.name, func(t *testing.T) {
410 got, err := appendUriIfFile(tt.args.result, tt.args.uri)
411 if (err != nil) != tt.wantErr {
412 t.Errorf("appendUriIfFile() error = %v, wantErr %v", err, tt.wantErr)
413 return
414 }
415 if diff := cmp.Diff(tt.want, got); diff != "" {
416 t.Errorf("appendUriIfFile() mismatch (-want +got):\n%s", diff)
417 }
418 })
419 }
420 }
421
422
452
453 func Test_getFromAttributes(t *testing.T) {
454 type args struct {
455 result map[string]struct{}
456 attributes attributes.Attributes
457 }
458 tests := []struct {
459 name string
460 args args
461 want map[string]struct{}
462 wantErr bool
463 }{
464 {
465 name: "uri is local file",
466 args: args{
467 result: map[string]struct{}{},
468 attributes: attributes.Attributes{
469 validation.ImportSourceAttribute: apiext.JSON{
470 Raw: []byte("uri: path/to/devfile.yaml"),
471 },
472 },
473 },
474 want: map[string]struct{}{
475 "path/to/devfile.yaml": {},
476 },
477 },
478 {
479 name: "uri is http file",
480 args: args{
481 result: map[string]struct{}{},
482 attributes: attributes.Attributes{
483 validation.ImportSourceAttribute: apiext.JSON{
484 Raw: []byte("uri: http://example.com/devfile.yaml"),
485 },
486 },
487 },
488 want: map[string]struct{}{},
489 },
490 {
491 name: "id and registryURL",
492 args: args{
493 result: map[string]struct{}{},
494 attributes: attributes.Attributes{
495 validation.ImportSourceAttribute: apiext.JSON{
496 Raw: []byte("id: my-id, registryURL: http://myregistry.com"),
497 },
498 },
499 },
500 want: map[string]struct{}{},
501 },
502 {
503 name: "name and namespace",
504 args: args{
505 result: map[string]struct{}{},
506 attributes: attributes.Attributes{
507 validation.ImportSourceAttribute: apiext.JSON{
508 Raw: []byte("name: aname, namespace: anamespace"),
509 },
510 },
511 },
512 want: map[string]struct{}{},
513 },
514 }
515 for _, tt := range tests {
516 t.Run(tt.name, func(t *testing.T) {
517 got, err := getFromAttributes(tt.args.result, tt.args.attributes)
518 if (err != nil) != tt.wantErr {
519 t.Errorf("getFromAttributes() error = %v, wantErr %v", err, tt.wantErr)
520 return
521 }
522 if diff := cmp.Diff(tt.want, got); diff != "" {
523 t.Errorf("getFromAttributes() mismatch (-want +got):\n%s", diff)
524 }
525 })
526 }
527 }
528
View as plain text