1
2
3
4 package yaml_test
5
6 import (
7 "fmt"
8 "testing"
9
10 "github.com/stretchr/testify/assert"
11 "github.com/stretchr/testify/require"
12 "sigs.k8s.io/kustomize/kyaml/errors"
13 . "sigs.k8s.io/kustomize/kyaml/yaml"
14 yaml "sigs.k8s.io/yaml/goyaml.v3"
15 )
16
17 const (
18 NodeSampleData = `n: o
19 a: b
20 c: d
21 `
22 )
23
24 func TestResourceNode_SetValue(t *testing.T) {
25 instance := *NewScalarRNode("foo")
26 instanceCopy := instance
27 instance.SetYNode(&yaml.Node{Kind: yaml.ScalarNode, Value: "bar"})
28 assert.Equal(t, `bar
29 `, assertNoErrorString(t)(instanceCopy.String()))
30 assert.Equal(t, `bar
31 `, assertNoErrorString(t)(instance.String()))
32
33 instance = *NewScalarRNode("foo")
34 instanceCopy = instance
35 instance.SetYNode(nil)
36 instance.SetYNode(&yaml.Node{Kind: yaml.ScalarNode, Value: "bar"})
37 assert.Equal(t, `foo
38 `, assertNoErrorString(t)(instanceCopy.String()))
39 assert.Equal(t, `bar
40 `, assertNoErrorString(t)(instance.String()))
41 }
42
43 func TestAppend(t *testing.T) {
44 node, err := Parse(NodeSampleData)
45 require.NoError(t, err)
46 rn, err := node.Pipe(Append(NewScalarRNode("").YNode()))
47 if assert.Error(t, err) {
48 assert.Contains(t, err.Error(), "wrong node kind")
49 }
50 assert.Nil(t, rn)
51
52 s := `- a
53 - b
54 `
55 node, err = Parse(s)
56 require.NoError(t, err)
57 rn, err = node.Pipe(Append())
58 require.NoError(t, err)
59 assert.Nil(t, rn)
60 }
61
62 func TestGetElementByIndex(t *testing.T) {
63 node, err := Parse(`
64 - 0
65 - 1
66 - 2
67 `)
68 require.NoError(t, err)
69
70 rn, err := node.Pipe(GetElementByIndex(0))
71 require.NoError(t, err)
72 assert.Equal(t, "0\n", assertNoErrorString(t)(rn.String()))
73
74 rn, err = node.Pipe(GetElementByIndex(2))
75 require.NoError(t, err)
76 assert.Equal(t, "2\n", assertNoErrorString(t)(rn.String()))
77
78 rn, err = node.Pipe(GetElementByIndex(-1))
79 require.NoError(t, err)
80 assert.Equal(t, "2\n", assertNoErrorString(t)(rn.String()))
81 }
82
83 func TestGetElementByKey(t *testing.T) {
84 node, err := Parse(`
85 - b: c
86 - i
87 - d: e
88 - f: g
89 - f: h
90 `)
91 require.NoError(t, err)
92
93 rn, err := node.Pipe(GetElementByKey("b"))
94 require.NoError(t, err)
95 assert.Equal(t, "b: c\n", assertNoErrorString(t)(rn.String()))
96
97 rn, err = node.Pipe(GetElementByKey("f"))
98 require.NoError(t, err)
99 assert.Equal(t, "f: g\n", assertNoErrorString(t)(rn.String()))
100 }
101
102 func TestElementSetter(t *testing.T) {
103 orig := MustParse(`
104 - a: b
105 - scalarValue
106 - c: d
107 # null will be removed
108 - null
109 `)
110
111
112 node := orig.Copy()
113
114 rn, err := node.Pipe(ElementSetter{Keys: []string{"a"}, Values: []string{"b"}})
115 require.NoError(t, err)
116 assert.Nil(t, rn)
117 assert.Equal(t, `- scalarValue
118 - c: d
119 `, assertNoErrorString(t)(node.String()))
120
121 node = orig.Copy()
122
123 rn, err = node.Pipe(ElementSetter{Keys: []string{"a"}, Values: []string{"zebra"}})
124 require.NoError(t, err)
125 assert.Nil(t, rn)
126 assert.Equal(t, `- a: b
127 - scalarValue
128 - c: d
129 `, assertNoErrorString(t)(node.String()))
130
131 node = orig.Copy()
132
133 _, err = node.Pipe(ElementSetter{Keys: []string{"a"}})
134 require.NoError(t, err)
135 assert.Equal(t, `[]
136 `, assertNoErrorString(t)(node.String()))
137
138 _, err = node.Pipe(ElementSetter{Values: []string{"b"}})
139 require.NoError(t, err)
140 assert.Equal(t, `[]
141 `, assertNoErrorString(t)(node.String()))
142
143 node = MustParse(`
144 - a: b
145 - c: d
146 `)
147
148
149 rn, err = node.Pipe(ElementSetter{Keys: []string{"a"}})
150 require.NoError(t, err)
151 assert.Nil(t, rn)
152 assert.Equal(t, `[]
153 `, assertNoErrorString(t)(node.String()))
154
155 node = MustParse(`
156 - a: b
157 - c: d
158 `)
159
160
161 _, err = node.Pipe(ElementSetter{Values: []string{"b"}})
162 assert.EqualError(t, err, `wrong node kind: expected ScalarNode but got MappingNode: node contents:
163 a: b
164 `)
165
166 node = MustParse(`
167 - a
168 - b
169 `)
170
171
172 rn, err = node.Pipe(ElementSetter{Values: []string{"b"}})
173 require.NoError(t, err)
174 assert.Nil(t, rn)
175 assert.Equal(t, `- a
176 `, assertNoErrorString(t)(node.String()))
177
178 node = orig.Copy()
179
180 newElement := NewMapRNode(&map[string]string{
181 "e": "f",
182 })
183 rn, err = node.Pipe(ElementSetter{
184 Keys: []string{"a"},
185 Values: []string{"b"},
186 Element: newElement.YNode(),
187 })
188 require.NoError(t, err)
189 assert.Equal(t, rn, newElement)
190 assert.Equal(t, `- e: f
191 - scalarValue
192 - c: d
193 `, assertNoErrorString(t)(node.String()))
194
195 node = orig.Copy()
196
197 newElement = NewScalarRNode("foo")
198 rn, err = node.Pipe(ElementSetter{
199 Keys: []string{"a"},
200 Values: []string{"b"},
201 Element: newElement.YNode(),
202 })
203 require.NoError(t, err)
204 assert.Equal(t, rn, newElement)
205 assert.Equal(t, `- foo
206 - scalarValue
207 - c: d
208 `, assertNoErrorString(t)(node.String()))
209
210 node = orig.Copy()
211
212
213 newElement = NewMapRNode(&map[string]string{
214 "e": "f",
215 })
216 rn, err = node.Pipe(ElementSetter{
217 Keys: []string{"x"},
218 Values: []string{"y"},
219 Element: newElement.YNode(),
220 })
221 require.NoError(t, err)
222 assert.Equal(t, rn, newElement)
223 assert.Equal(t, `- a: b
224 - scalarValue
225 - c: d
226 - e: f
227 `, assertNoErrorString(t)(node.String()))
228 }
229
230 func TestElementSetterMultipleKeys(t *testing.T) {
231 orig := MustParse(`
232 - a: b
233 c: d
234 - scalarValue
235 - e: f
236 # null will be removed
237 - null
238 `)
239
240
241 node := orig.Copy()
242
243
244 rn, err := node.Pipe(ElementSetter{
245 Keys: []string{"a"},
246 Values: []string{"b"},
247 })
248 require.NoError(t, err)
249 assert.Nil(t, rn)
250 assert.Equal(t, `- scalarValue
251 - e: f
252 `, assertNoErrorString(t)(node.String()))
253
254 node = orig.Copy()
255
256
257 rn, err = node.Pipe(ElementSetter{
258 Keys: []string{"a", "c"},
259 Values: []string{"b", "d"},
260 })
261 require.NoError(t, err)
262 assert.Nil(t, rn)
263 assert.Equal(t, `- scalarValue
264 - e: f
265 `, assertNoErrorString(t)(node.String()))
266
267 node = orig.Copy()
268
269
270
271 rn, err = node.Pipe(ElementSetter{
272 Keys: []string{"a", "c"},
273 Values: []string{"b", "wrong value"},
274 })
275 require.NoError(t, err)
276 assert.Nil(t, rn)
277 assert.Equal(t, `- a: b
278 c: d
279 - scalarValue
280 - e: f
281 `, assertNoErrorString(t)(node.String()))
282
283 node = orig.Copy()
284
285
286 newElement := NewMapRNode(&map[string]string{
287 "g": "h",
288 })
289 rn, err = node.Pipe(ElementSetter{
290 Keys: []string{"a"},
291 Values: []string{"b"},
292 Element: newElement.YNode(),
293 })
294 require.NoError(t, err)
295 assert.Equal(t, rn, newElement)
296 assert.Equal(t, `- g: h
297 - scalarValue
298 - e: f
299 `, assertNoErrorString(t)(node.String()))
300
301 node = orig.Copy()
302
303
304 newElement = NewMapRNode(&map[string]string{
305 "g": "h",
306 })
307 rn, err = node.Pipe(ElementSetter{
308 Keys: []string{"a", "c"},
309 Values: []string{"b", "d"},
310 Element: newElement.YNode(),
311 })
312 require.NoError(t, err)
313 assert.Equal(t, rn, newElement)
314 assert.Equal(t, `- g: h
315 - scalarValue
316 - e: f
317 `, assertNoErrorString(t)(node.String()))
318
319 node = orig.Copy()
320
321
322 newElement = NewScalarRNode("foo")
323 rn, err = node.Pipe(ElementSetter{
324 Keys: []string{"a", "c"},
325 Values: []string{"b", "d"},
326 Element: newElement.YNode(),
327 })
328 require.NoError(t, err)
329 assert.Equal(t, rn, newElement)
330 assert.Equal(t, `- foo
331 - scalarValue
332 - e: f
333 `, assertNoErrorString(t)(node.String()))
334
335 node = orig.Copy()
336
337
338
339 newElement = NewMapRNode(&map[string]string{
340 "g": "h",
341 })
342 rn, err = node.Pipe(ElementSetter{
343 Keys: []string{"a", "c"},
344 Values: []string{"b", "wrong value"},
345 Element: newElement.YNode(),
346 })
347 require.NoError(t, err)
348 assert.Equal(t, rn, newElement)
349 assert.Equal(t, `- a: b
350 c: d
351 - scalarValue
352 - e: f
353 - g: h
354 `, assertNoErrorString(t)(node.String()))
355 }
356
357 func TestElementMatcherWithNoValue(t *testing.T) {
358 node, err := Parse(`
359 - a: c
360 - b: ""
361 `)
362 require.NoError(t, err)
363
364 rn, err := node.Pipe(ElementMatcher{Keys: []string{"b"}})
365 require.NoError(t, err)
366 assert.Equal(t, "b: \"\"\n", assertNoErrorString(t)(rn.String()))
367
368 rn, err = node.Pipe(ElementMatcher{Keys: []string{"a"}})
369 require.NoError(t, err)
370 assert.Nil(t, rn)
371
372 rn, err = node.Pipe(ElementMatcher{Keys: []string{"a"}, MatchAnyValue: true})
373 require.NoError(t, err)
374 assert.Equal(t, "a: c\n", assertNoErrorString(t)(rn.String()))
375
376 _, err = node.Pipe(ElementMatcher{Keys: []string{"a"}, Values: []string{"c"}, MatchAnyValue: true})
377 require.Errorf(t, err, "Values must be empty when MatchAnyValue is set to true")
378 }
379
380 func TestElementMatcherMultipleKeys(t *testing.T) {
381 node, err := Parse(`
382 - a: b
383 c: d
384 - e: f
385 `)
386 require.NoError(t, err)
387
388
389 rn, err := node.Pipe(MatchElementList(
390 []string{"a", "c"},
391 []string{"b", "d"},
392 ))
393 require.NoError(t, err)
394 assert.NotEmpty(t, rn)
395
396
397 rn, err = node.Pipe(MatchElementList(
398 []string{"a", "c"},
399 []string{"b", "f"},
400 ))
401 require.NoError(t, err)
402 assert.Nil(t, rn)
403
404
405 rn, err = node.Pipe(MatchElementList(
406 []string{"e"},
407 []string{"f"},
408 ))
409 require.NoError(t, err)
410 assert.NotEmpty(t, rn)
411
412
413 rn, err = node.Pipe(MatchElementList(
414 []string{"e"},
415 []string{"g"},
416 ))
417 require.NoError(t, err)
418 assert.Nil(t, rn)
419 }
420
421 func TestClearField_Fn(t *testing.T) {
422 node, err := Parse(NodeSampleData)
423 require.NoError(t, err)
424 rn, err := node.Pipe(FieldClearer{Name: "a"})
425 require.NoError(t, err)
426 assert.Equal(t, "n: o\nc: d\n", assertNoErrorString(t)(node.String()))
427 assert.Equal(t, "b\n", assertNoErrorString(t)(rn.String()))
428
429 node, err = Parse(NodeSampleData)
430 require.NoError(t, err)
431 rn, err = node.Pipe(FieldClearer{Name: "n"})
432 require.NoError(t, err)
433 assert.Equal(t, "a: b\nc: d\n", assertNoErrorString(t)(node.String()))
434 assert.Equal(t, "o\n", assertNoErrorString(t)(rn.String()))
435
436 node, err = Parse(NodeSampleData)
437 require.NoError(t, err)
438 rn, err = node.Pipe(FieldClearer{Name: "c"})
439 require.NoError(t, err)
440 assert.Equal(t, "n: o\na: b\n", assertNoErrorString(t)(node.String()))
441 assert.Equal(t, "d\n", assertNoErrorString(t)(rn.String()))
442
443 s := `n: o
444 a: b
445 `
446 node, err = Parse(s)
447 require.NoError(t, err)
448 rn, err = node.Pipe(FieldClearer{Name: "o"})
449 require.NoError(t, err)
450 assert.Nil(t, rn)
451 assert.Equal(t, "n: o\na: b\n", assertNoErrorString(t)(node.String()))
452
453 s = `- a
454 - b
455 `
456 node, err = Parse(s)
457 require.NoError(t, err)
458 rn, err = node.Pipe(FieldClearer{Name: "a"})
459 if assert.Error(t, err) {
460 assert.Contains(t, err.Error(), "wrong node kind")
461 }
462 assert.Nil(t, rn)
463 assert.Equal(t, s, assertNoErrorString(t)(node.String()))
464
465
466 s = `n:
467 k: v
468 a: b
469 c: d
470 `
471 node, err = Parse(s)
472 require.NoError(t, err)
473 rn, err = node.Pipe(FieldClearer{Name: "n", IfEmpty: true})
474 require.NoError(t, err)
475 assert.Equal(t, "n:\n k: v\na: b\nc: d\n", assertNoErrorString(t)(node.String()))
476 assert.Equal(t, "", assertNoErrorString(t)(rn.String()))
477
478
479 s = `n: {}
480 a: b
481 c: d
482 `
483 node, err = Parse(s)
484 require.NoError(t, err)
485 rn, err = node.Pipe(FieldClearer{Name: "n", IfEmpty: true})
486 require.NoError(t, err)
487 assert.Equal(t, "a: b\nc: d\n", assertNoErrorString(t)(node.String()))
488 assert.Equal(t, "{}\n", assertNoErrorString(t)(rn.String()))
489 }
490
491 var s = `n: o
492 a:
493 l: m
494 b:
495 - f: g
496 - c: e
497 - h: i
498 r: s
499 `
500
501 func TestLookup_Fn_create(t *testing.T) {
502
503 node, err := Parse(s)
504 require.NoError(t, err)
505 rn, err := node.Pipe(PathGetter{
506 Path: []string{"a", "b", "[c=d]", "t", "f", "[=h]"},
507 Create: yaml.ScalarNode,
508 })
509 require.NoError(t, err)
510 assert.Equal(t, `n: o
511 a:
512 l: m
513 b:
514 - f: g
515 - c: e
516 - h: i
517 - c: d
518 t:
519 f:
520 - h
521 r: s
522 `, assertNoErrorString(t)(node.String()))
523 assert.Equal(t, `h
524 `, assertNoErrorString(t)(rn.String()))
525 }
526
527 func TestLookup_Fn_create2(t *testing.T) {
528 node, err := Parse(s)
529 require.NoError(t, err)
530 rn, err := node.Pipe(PathGetter{
531 Path: []string{"a", "b", "[c=d]", "t", "f"},
532 Create: yaml.SequenceNode,
533 })
534 require.NoError(t, err)
535 assert.Equal(t, `n: o
536 a:
537 l: m
538 b:
539 - f: g
540 - c: e
541 - h: i
542 - c: d
543 t:
544 f: []
545 r: s
546 `, assertNoErrorString(t)(node.String()))
547 assert.Equal(t, `[]
548 `, assertNoErrorString(t)(rn.String()))
549 }
550
551 func TestLookup_Fn_create3(t *testing.T) {
552 node, err := Parse(s)
553 require.NoError(t, err)
554 rn, err := node.Pipe(LookupCreate(yaml.MappingNode, "a", "b", "[c=d]", "t"))
555 require.NoError(t, err)
556 assert.Equal(t, `n: o
557 a:
558 l: m
559 b:
560 - f: g
561 - c: e
562 - h: i
563 - c: d
564 t: {}
565 r: s
566 `, assertNoErrorString(t)(node.String()))
567 assert.Equal(t, `{}
568 `, assertNoErrorString(t)(rn.String()))
569 }
570
571 func TestLookupCreate_4(t *testing.T) {
572 node, err := Parse(`
573 a: {}
574 `)
575 require.NoError(t, err)
576 rn, err := node.Pipe(
577 LookupCreate(yaml.MappingNode, "a", "b", "[c=d]", "t", "f", "[=h]"))
578
579 node.YNode().Style = yaml.FlowStyle
580 require.NoError(t, err)
581 assert.Equal(t, "{a: {b: [{c: d, t: {f: [h]}}]}}\n", assertNoErrorString(t)(node.String()))
582 assert.Equal(t, "h\n", assertNoErrorString(t)(rn.String()))
583 }
584
585 func TestLookup_Fn_create_with_wildcard_error(t *testing.T) {
586 node, err := Parse(s)
587 require.NoError(t, err)
588 _, err = node.Pipe(LookupCreate(yaml.MappingNode, "a", "b", "*", "t"))
589 require.Error(t, err, "wildcard is not supported in PathGetter")
590 }
591
592 func TestLookup(t *testing.T) {
593 s := `n: o
594 a:
595 l: m
596 b:
597 - f: g
598 - c: e
599 - c: d
600 t:
601 u: v
602 f:
603 - g
604 - h
605 - i
606 j: k
607 - h: i
608 p: q
609 r: s
610 `
611 node, err := Parse(s)
612 require.NoError(t, err)
613
614
615 rn, err := node.Pipe(Lookup("a", "b", "[c=d]", "t", "f", "[=h]"))
616 require.NoError(t, err)
617 assert.Equal(t, s, assertNoErrorString(t)(node.String()))
618 assert.Equal(t, `h
619 `, assertNoErrorString(t)(rn.String()))
620
621
622 rn, err = node.Pipe(Lookup("a", "b", "[c=d]", "t", "f"))
623 require.NoError(t, err)
624 assert.Equal(t, s, assertNoErrorString(t)(node.String()))
625 assert.Equal(t, `- g
626 - h
627 - i
628 `, assertNoErrorString(t)(rn.String()))
629
630 rn, err = node.Pipe(Lookup("a", "b", "[c=d]", "t"))
631 require.NoError(t, err)
632 assert.Equal(t, s, assertNoErrorString(t)(node.String()))
633 assert.Equal(t, `u: v
634 f:
635 - g
636 - h
637 - i
638 `, assertNoErrorString(t)(rn.String()))
639
640 rn, err = node.Pipe(Lookup("a", "b", "[c=d]"))
641 require.NoError(t, err)
642 assert.Equal(t, s, assertNoErrorString(t)(node.String()))
643 assert.Equal(t, `c: d
644 t:
645 u: v
646 f:
647 - g
648 - h
649 - i
650 j: k
651 `, assertNoErrorString(t)(rn.String()))
652
653 rn, err = node.Pipe(Lookup("a", "b"))
654 require.NoError(t, err)
655 assert.Equal(t, s, assertNoErrorString(t)(node.String()))
656 assert.Equal(t, `- f: g
657 - c: e
658 - c: d
659 t:
660 u: v
661 f:
662 - g
663 - h
664 - i
665 j: k
666 - h: i
667 p: q
668 `, assertNoErrorString(t)(rn.String()))
669
670 rn, err = node.Pipe(Lookup("a", "b", "0"))
671 require.NoError(t, err)
672 assert.Equal(t, s, assertNoErrorString(t)(node.String()))
673 assert.Equal(t, `f: g
674 `, assertNoErrorString(t)(rn.String()))
675
676 rn, err = node.Pipe(Lookup("a", "b", "-", "h"))
677 require.NoError(t, err)
678 assert.Equal(t, s, assertNoErrorString(t)(node.String()))
679 assert.Equal(t, `i
680 `, assertNoErrorString(t)(rn.String()))
681
682 rn, err = node.Pipe(Lookup("l"))
683 require.NoError(t, err)
684 assert.Equal(t, s, assertNoErrorString(t)(node.String()))
685 assert.Nil(t, rn)
686
687 rn, err = node.Pipe(Lookup("zzz"))
688 require.NoError(t, err)
689 assert.Equal(t, s, assertNoErrorString(t)(node.String()))
690 assert.Nil(t, rn)
691
692 rn, err = node.Pipe(Lookup("[a=b]"))
693 require.Error(t, err)
694 assert.Equal(t, s, assertNoErrorString(t)(node.String()))
695 assert.Nil(t, rn)
696
697 rn, err = node.Pipe(Lookup("a", "b", "f"))
698 require.Error(t, err)
699 assert.Equal(t, s, assertNoErrorString(t)(node.String()))
700 assert.Nil(t, rn)
701
702 rn, err = node.Pipe(Lookup("a", "b", "c=zzz"))
703 require.Error(t, err)
704 assert.Equal(t, s, assertNoErrorString(t)(node.String()))
705 assert.Nil(t, rn)
706
707 rn, err = node.Pipe(Lookup(" ", "a", "", "b", " ", "[c=d]", "\n", "t", "\t", "f", " ", "[=h]", " "))
708 require.NoError(t, err)
709 assert.Equal(t, s, assertNoErrorString(t)(node.String()))
710 assert.Equal(t, `h
711 `, assertNoErrorString(t)(rn.String()))
712
713 rn, err = node.Pipe(Lookup(" ", "a", "", "b", " ", "[]"))
714 require.Error(t, err)
715 assert.Nil(t, rn)
716
717 rn, err = node.Pipe(Lookup("a", "b", "[c=d]", "t", "f", "[=c]"))
718 require.NoError(t, err)
719 assert.Equal(t, s, assertNoErrorString(t)(node.String()))
720 assert.Nil(t, rn)
721
722 rn, err = node.Pipe(Lookup("a", "b", "[z=z]"))
723 require.NoError(t, err)
724 assert.Equal(t, s, assertNoErrorString(t)(node.String()))
725 assert.Nil(t, rn)
726
727 rn, err = node.Pipe(Lookup("a", "b", "-1"))
728 require.Errorf(t, err, "array index -1 cannot be negative")
729 assert.Equal(t, s, assertNoErrorString(t)(node.String()))
730 assert.Nil(t, rn)
731
732 rn, err = node.Pipe(Lookup("a", "b", "99"))
733 require.NoError(t, err)
734 assert.Equal(t, s, assertNoErrorString(t)(node.String()))
735 assert.Nil(t, rn)
736 }
737
738 func TestLookupFirstMatch(t *testing.T) {
739 tests := []struct {
740 name string
741 paths [][]string
742 wantPath []string
743 }{
744 {
745 name: "finds path that exists",
746 paths: [][]string{{"spec", "jobTemplate", "spec", "template", "spec", "containers"}},
747 wantPath: []string{"spec", "jobTemplate", "spec", "template", "spec", "containers"},
748 },
749 {
750 name: "chooses first path when multiple exist: containers example",
751 paths: ConventionalContainerPaths,
752 wantPath: []string{"spec", "template", "spec", "containers"},
753 },
754 {
755 name: "chooses first path when multiple exist: annotations example",
756 paths: [][]string{
757 {"metadata", "annotations", "example.kustomize.io/new"},
758 {"metadata", "annotations", "example.kustomize.io/deprecated"},
759 },
760 wantPath: []string{"metadata", "annotations", "example.kustomize.io/new"},
761 },
762 {
763 name: "returns nil when path does not exist",
764 paths: [][]string{
765 {"metadata", "annotations", "example.kustomize.io/does-not-exist"},
766 {"metadata", "annotations", "example.kustomize.io/also-not-exist"},
767 },
768 wantPath: nil,
769 },
770 }
771 for _, tt := range tests {
772 s := `
773 apiVersion: example.kustomize.io/v1
774 kind: Custom
775 metadata:
776 annotations:
777 example.kustomize.io/deprecated: foo
778 example.kustomize.io/new: foo
779 spec:
780 template:
781 spec:
782 containers:
783 - name: foo
784 jobTemplate:
785 spec:
786 template:
787 spec:
788 containers:
789 - name: foo
790 `
791 resource := MustParse(s)
792 t.Run(tt.name, func(t *testing.T) {
793 result, err := LookupFirstMatch(tt.paths).Filter(resource)
794 require.NoError(t, err)
795 if tt.wantPath != nil {
796 assert.Equal(t, tt.wantPath, result.FieldPath())
797 } else {
798 assert.Nil(t, result)
799 }
800 })
801 }
802 }
803
804 func TestMapEntrySetter(t *testing.T) {
805 withStyle := func(rn *RNode, style yaml.Style) *RNode {
806 rn.YNode().Style = style
807 return rn
808 }
809 testCases := []struct {
810 desc string
811 input string
812 setter MapEntrySetter
813 expected string
814 expectedErr error
815 }{
816 {
817 desc: "it should override Key's value map entry",
818 input: "foo: baz\n",
819 setter: MapEntrySetter{
820 Key: NewScalarRNode("foo"),
821 Value: NewScalarRNode("bar"),
822 },
823 expected: "foo: bar\n",
824 },
825 {
826 desc: "it should override Name's map entry",
827 input: "foo: baz\n",
828 setter: MapEntrySetter{
829 Name: "foo",
830 Key: NewScalarRNode("bar"),
831 Value: NewScalarRNode("baz"),
832 },
833 expected: "bar: baz\n",
834 },
835 {
836 desc: "it should insert new map entry",
837 input: "foo: baz\n",
838 setter: MapEntrySetter{
839 Key: NewScalarRNode("bar"),
840 Value: NewScalarRNode("42"),
841 },
842 expected: "foo: baz\nbar: 42\n",
843 },
844 {
845 desc: "it should override the style",
846 input: "foo: baz\n",
847 setter: MapEntrySetter{
848 Key: withStyle(NewScalarRNode("foo"), yaml.DoubleQuotedStyle),
849 Value: withStyle(NewScalarRNode("bar"), yaml.SingleQuotedStyle),
850 },
851 expected: `"foo": 'bar'` + "\n",
852 },
853 {
854 desc: "it should return error on sequence nodes",
855 input: "- foo: baz\n",
856 setter: MapEntrySetter{
857 Key: NewScalarRNode("foo"),
858 Value: NewScalarRNode("bar"),
859 },
860 expectedErr: errors.Errorf(`wrong node kind: expected MappingNode but got SequenceNode: node contents:
861 - foo: baz
862 `),
863 },
864 }
865 for _, tc := range testCases {
866 t.Run(tc.desc, func(t *testing.T) {
867 node, err := Parse(tc.input)
868 require.NoError(t, err)
869 k, err := tc.setter.Filter(node)
870 if tc.expectedErr == nil {
871 require.NoError(t, err)
872 assert.Equal(t, tc.expected, assertNoErrorString(t)(node.String()))
873 assert.Equal(t, tc.expected, assertNoErrorString(t)(k.String()))
874 } else {
875 assert.NotNil(t, err)
876 assert.Equal(t, tc.expectedErr.Error(), err.Error())
877 }
878 })
879 }
880 }
881
882 func TestFieldSetter(t *testing.T) {
883
884 node, err := Parse(`
885 foo: baz
886 `)
887 require.NoError(t, err)
888 instance := FieldSetter{
889 Name: "foo",
890 Value: NewScalarRNode("bar"),
891 }
892 k, err := instance.Filter(node)
893 require.NoError(t, err)
894 assert.Equal(t, `foo: bar
895 `, assertNoErrorString(t)(node.String()))
896 assert.Equal(t, `bar
897 `, assertNoErrorString(t)(k.String()))
898
899
900 node, err = Parse(`
901 foo: baz
902 `)
903 require.NoError(t, err)
904 instance = FieldSetter{
905 Name: "bar",
906 Value: NewScalarRNode("buz"),
907 }
908 k, err = instance.Filter(node)
909 require.NoError(t, err)
910 assert.Equal(t, `foo: baz
911 bar: buz
912 `, assertNoErrorString(t)(node.String()))
913 assert.Equal(t, `buz
914 `, assertNoErrorString(t)(k.String()))
915
916
917 node, err = Parse(`
918 foo: baz
919 bar: buz
920 `)
921 require.NoError(t, err)
922 instance = FieldSetter{
923 Name: "foo",
924 }
925 k, err = instance.Filter(node)
926 require.NoError(t, err)
927 assert.Equal(t, `bar: buz
928 `, assertNoErrorString(t)(node.String()))
929 assert.Equal(t, `baz
930 `, assertNoErrorString(t)(k.String()))
931
932
933 node, err = Parse(`
934 foo
935 `)
936 require.NoError(t, err)
937 instance = FieldSetter{}
938 k, err = instance.Filter(node)
939 require.NoError(t, err)
940 assert.Equal(t, `foo
941 `, assertNoErrorString(t)(node.String()))
942 assert.Equal(t, `foo
943 `, assertNoErrorString(t)(k.String()))
944
945
946 node, err = Parse(`
947 -a
948 -b
949 `)
950 require.NoError(t, err)
951 instance = FieldSetter{
952 Name: "foo",
953 Value: NewScalarRNode("v"),
954 }
955 k, err = instance.Filter(node)
956 if assert.Error(t, err) {
957 assert.Contains(t, err.Error(), "wrong node kind")
958 }
959 assert.Nil(t, k)
960 }
961
962 func TestFieldSetterNumberInKeyRegression(t *testing.T) {
963 node := NewMapRNode(&map[string]string{"river": "mississippi"})
964
965 k, err := FieldSetter{
966 Name: "forty 2",
967 Value: NewScalarRNode("number key one"),
968 }.Filter(node)
969 require.NoError(t, err)
970 assert.Equal(t, `number key one
971 `, assertNoErrorString(t)(k.String()))
972
973 k, err = FieldSetter{
974 Name: "fortytwo",
975 Value: NewScalarRNode("number key two"),
976 }.Filter(node)
977 require.NoError(t, err)
978 assert.Equal(t, `number key two
979 `, assertNoErrorString(t)(k.String()))
980
981 k, err = FieldSetter{
982 Name: "42",
983 Value: NewScalarRNode("number key three"),
984 }.Filter(node)
985 require.NoError(t, err)
986 assert.Equal(t, `number key three
987 `, assertNoErrorString(t)(k.String()))
988
989 assert.Equal(t, `river: mississippi
990 forty 2: number key one
991 fortytwo: number key two
992 42: number key three
993 `, assertNoErrorString(t)(node.String()))
994 }
995
996 func TestSet_Fn(t *testing.T) {
997 node, err := Parse(`
998 foo: baz
999 `)
1000 require.NoError(t, err)
1001 k, err := node.Pipe(Get("foo"), Set(NewScalarRNode("bar")))
1002 require.NoError(t, err)
1003 assert.Equal(t, `foo: bar
1004 `, assertNoErrorString(t)(node.String()))
1005 assert.Equal(t, `bar
1006 `, assertNoErrorString(t)(k.String()))
1007
1008 node, err = Parse(`
1009 foo: baz
1010 `)
1011 require.NoError(t, err)
1012 _, err = node.Pipe(Set(NewScalarRNode("bar")))
1013 if !assert.Error(t, err) {
1014 return
1015 }
1016 assert.Contains(t, err.Error(), "wrong node kind")
1017 assert.Equal(t, `foo: baz
1018 `, assertNoErrorString(t)(node.String()))
1019 }
1020
1021 func TestErrorIfInvalid(t *testing.T) {
1022 err := ErrorIfInvalid(
1023 NewRNode(&yaml.Node{Kind: yaml.SequenceNode}), yaml.SequenceNode)
1024 require.NoError(t, err)
1025
1026
1027 err = ErrorIfInvalid(&RNode{}, yaml.SequenceNode)
1028 if !assert.NoError(t, err) {
1029 t.FailNow()
1030 }
1031
1032 err = ErrorIfInvalid(NewRNode(&Node{Content: []*yaml.Node{{Value: "hello"}}}), yaml.SequenceNode)
1033 if !assert.Error(t, err) {
1034 t.FailNow()
1035 }
1036 assert.Contains(t, err.Error(), "wrong node kind")
1037
1038 err = ErrorIfInvalid(NewRNode(&yaml.Node{}), yaml.SequenceNode)
1039 if assert.Error(t, err) {
1040 assert.Contains(t, err.Error(), "wrong node kind")
1041 }
1042 err = ErrorIfInvalid(NewRNode(&yaml.Node{}), yaml.MappingNode)
1043 if assert.Error(t, err) {
1044 assert.Contains(t, err.Error(), "wrong node kind")
1045 }
1046
1047 err = ErrorIfInvalid(NewRNode(&yaml.Node{
1048 Kind: yaml.MappingNode,
1049 Content: []*yaml.Node{{}, {}},
1050 }), yaml.MappingNode)
1051 require.NoError(t, err)
1052
1053 err = ErrorIfInvalid(NewRNode(&yaml.Node{}), yaml.SequenceNode)
1054 if assert.Error(t, err) {
1055 assert.Contains(t, err.Error(), "wrong node kind")
1056 }
1057
1058 err = ErrorIfInvalid(NewRNode(&yaml.Node{
1059 Kind: yaml.MappingNode,
1060 Content: []*yaml.Node{{}},
1061 }), yaml.MappingNode)
1062 if assert.Error(t, err) {
1063 assert.Contains(t, err.Error(), "even length")
1064 }
1065 }
1066
1067 func TestSplitIndexNameValue(t *testing.T) {
1068 k, v, err := SplitIndexNameValue("")
1069 if assert.Error(t, err) {
1070 assert.Contains(t, err.Error(), "fieldName=fieldValue")
1071 }
1072 assert.Equal(t, "", k)
1073 assert.Equal(t, "", v)
1074
1075 k, v, err = SplitIndexNameValue("a=b")
1076 require.NoError(t, err)
1077 assert.Equal(t, "a", k)
1078 assert.Equal(t, "b", v)
1079
1080 k, v, err = SplitIndexNameValue("=b")
1081 require.NoError(t, err)
1082 assert.Equal(t, "", k)
1083 assert.Equal(t, "b", v)
1084
1085 k, v, err = SplitIndexNameValue("a=b=c")
1086 require.NoError(t, err)
1087 assert.Equal(t, "a", k)
1088 assert.Equal(t, "b=c", v)
1089
1090 k, v, err = SplitIndexNameValue("=-jar")
1091 require.NoError(t, err)
1092 assert.Equal(t, "", k)
1093 assert.Equal(t, "-jar", v)
1094 }
1095
1096 type filter struct {
1097 fn func(object *RNode) (*RNode, error)
1098 }
1099
1100 func (c filter) Filter(object *RNode) (*RNode, error) {
1101 return c.fn(object)
1102 }
1103
1104 func TestResourceNode_Pipe(t *testing.T) {
1105 var r0, r1, r2, r3 *RNode
1106 var called []string
1107
1108
1109 _, err := r0.Pipe(FieldMatcher{Name: "foo"})
1110 require.NoError(t, err)
1111
1112 r0, r1, r2, r3 = &RNode{}, &RNode{}, &RNode{}, &RNode{}
1113
1114 v, err := r0.Pipe(
1115 filter{fn: func(object *RNode) (*RNode, error) {
1116 assert.True(t, r0 == object)
1117 called = append(called, "a")
1118 return r1, nil
1119 }},
1120 filter{fn: func(object *RNode) (*RNode, error) {
1121 assert.True(t, object == r1, "function arg doesn't match last function output")
1122 called = append(called, "b")
1123 return r2, nil
1124 }},
1125 filter{fn: func(object *RNode) (*RNode, error) {
1126 assert.True(t, object == r2, "function arg doesn't match last function output")
1127 return r3, nil
1128 }},
1129 )
1130 assert.True(t, v == r3, "expected r3")
1131 assert.Nil(t, err)
1132 assert.Equal(t, called, []string{"a", "b"})
1133
1134
1135 called = []string{}
1136 v, err = r0.Pipe(
1137 filter{fn: func(object *RNode) (*RNode, error) {
1138 assert.True(t, r0 == object)
1139 called = append(called, "a")
1140 return r1, nil
1141 }},
1142 filter{fn: func(object *RNode) (*RNode, error) {
1143 assert.True(t, object == r1, "function arg doesn't match last function output")
1144 called = append(called, "b")
1145 return nil, nil
1146 }},
1147 filter{fn: func(object *RNode) (*RNode, error) {
1148 assert.Fail(t, "function should be run after error")
1149 return nil, nil
1150 }},
1151 )
1152 assert.Nil(t, v)
1153 assert.Nil(t, err)
1154 assert.Equal(t, called, []string{"a", "b"})
1155
1156
1157 called = []string{}
1158 v, err = r0.Pipe(
1159 filter{fn: func(object *RNode) (*RNode, error) {
1160 assert.True(t, r0 == object)
1161 called = append(called, "a")
1162 return r1, nil
1163 }},
1164 filter{fn: func(object *RNode) (*RNode, error) {
1165 assert.True(t, object == r1, "function arg doesn't match last function output")
1166 called = append(called, "b")
1167 return r1, fmt.Errorf("expected-error")
1168 }},
1169 filter{fn: func(object *RNode) (*RNode, error) {
1170 assert.Fail(t, "function should be run after error")
1171 return nil, nil
1172 }},
1173 )
1174 assert.True(t, v == r1, "expected r1 as value")
1175 assert.EqualError(t, err, "expected-error")
1176 assert.Equal(t, called, []string{"a", "b"})
1177 }
1178
1179 func TestClearAnnotation(t *testing.T) {
1180
1181 r0 := assertNoError(t)(Parse(`apiVersion: apps/v1
1182 kind: Deployment
1183 metadata:
1184 annotations:
1185 z: y
1186 a.b.c: d.e.f
1187 s: t
1188 `))
1189
1190 rn := assertNoError(t)(r0.Pipe(ClearAnnotation("a.b.c")))
1191 assert.Equal(t, "d.e.f\n", assertNoErrorString(t)(rn.String()))
1192 assert.Equal(t, `apiVersion: apps/v1
1193 kind: Deployment
1194 metadata:
1195 annotations:
1196 z: y
1197 s: t
1198 `, assertNoErrorString(t)(r0.String()))
1199 }
1200
1201 func TestGetAnnotation(t *testing.T) {
1202 r0 := assertNoError(t)(Parse(`apiVersion: apps/v1
1203 kind: Deployment
1204 metadata:
1205 labels:
1206 app: java
1207 annotations:
1208 a.b.c: d.e.f
1209 g: h
1210 i: j
1211 k: l
1212 name: app`))
1213
1214 rn := assertNoError(t)(
1215 r0.Pipe(GetAnnotation("a.b.c")))
1216 assert.Equal(t, "d.e.f\n", assertNoErrorString(t)(rn.String()))
1217 }
1218
1219 func TestSetAnnotation_Fn(t *testing.T) {
1220
1221 r0 := assertNoError(t)(Parse(`apiVersion: apps/v1
1222 kind: Deployment`))
1223
1224 rn := assertNoError(t)(r0.Pipe(SetAnnotation("a.b.c", "d.e.f")))
1225 assert.Equal(t, "'d.e.f'\n", assertNoErrorString(t)(rn.String()))
1226 assert.Equal(t, `apiVersion: apps/v1
1227 kind: Deployment
1228 metadata:
1229 annotations:
1230 a.b.c: 'd.e.f'
1231 `, assertNoErrorString(t)(r0.String()))
1232 }
1233
1234 func TestUpdateAnnotation_Fn(t *testing.T) {
1235
1236 r0 := assertNoError(t)(Parse(`apiVersion: apps/v1
1237 kind: Deployment
1238 metadata:
1239 annotations:
1240 a.b.c: "h.i.j"
1241 `))
1242
1243 rn := assertNoError(t)(r0.Pipe(SetAnnotation("a.b.c", "d.e.f")))
1244 assert.Equal(t, "\"d.e.f\"\n", assertNoErrorString(t)(rn.String()))
1245 assert.Equal(t, `apiVersion: apps/v1
1246 kind: Deployment
1247 metadata:
1248 annotations:
1249 a.b.c: "d.e.f"
1250 `, assertNoErrorString(t)(r0.String()))
1251 }
1252
1253 func TestRNode_GetMeta(t *testing.T) {
1254 s := `apiVersion: v1/apps
1255 kind: Deployment
1256 metadata:
1257 name: foo
1258 namespace: bar
1259 labels:
1260 kl: vl
1261 annotations:
1262 ka: va
1263 `
1264 node, err := Parse(s)
1265 if !assert.NoError(t, err) {
1266 return
1267 }
1268 meta, err := node.GetMeta()
1269 if !assert.NoError(t, err) {
1270 return
1271 }
1272 assert.Equal(t, ResourceMeta{
1273 TypeMeta: TypeMeta{
1274 Kind: "Deployment",
1275 APIVersion: "v1/apps",
1276 },
1277 ObjectMeta: ObjectMeta{
1278 NameMeta: NameMeta{
1279 Name: "foo",
1280 Namespace: "bar",
1281 },
1282 Annotations: map[string]string{
1283 "ka": "va",
1284 },
1285 Labels: map[string]string{
1286 "kl": "vl",
1287 },
1288 },
1289 }, meta)
1290 }
1291
1292 func assertNoError(t *testing.T) func(o *RNode, err error) *RNode {
1293 t.Helper()
1294 return func(o *RNode, err error) *RNode {
1295 require.NoError(t, err)
1296 return o
1297 }
1298 }
1299
1300 func assertNoErrorString(t *testing.T) func(string, error) string {
1301 t.Helper()
1302 return func(s string, err error) string {
1303 require.NoError(t, err)
1304 return s
1305 }
1306 }
1307
View as plain text