1
2
3
4 package framework_test
5
6 import (
7 "bytes"
8 "regexp"
9 "strings"
10 "testing"
11
12 "github.com/stretchr/testify/assert"
13 "github.com/stretchr/testify/require"
14 validationErrors "k8s.io/kube-openapi/pkg/validation/errors"
15 "k8s.io/kube-openapi/pkg/validation/spec"
16 "sigs.k8s.io/kustomize/kyaml/errors"
17 "sigs.k8s.io/kustomize/kyaml/fn/framework/frameworktestutil"
18 "sigs.k8s.io/kustomize/kyaml/fn/framework/parser"
19 "sigs.k8s.io/kustomize/kyaml/openapi"
20 "sigs.k8s.io/kustomize/kyaml/resid"
21 "sigs.k8s.io/kustomize/kyaml/yaml"
22
23 "sigs.k8s.io/kustomize/kyaml/fn/framework"
24 "sigs.k8s.io/kustomize/kyaml/kio"
25 )
26
27 func TestTemplateProcessor_ResourceTemplates(t *testing.T) {
28 type API struct {
29 Image string `json:"image" yaml:"image"`
30 }
31
32 p := framework.TemplateProcessor{
33 TemplateData: &API{},
34 ResourceTemplates: []framework.ResourceTemplate{{
35 Templates: parser.TemplateFiles("testdata/template-processor/templates/basic"),
36 }},
37 }
38
39 out := new(bytes.Buffer)
40 rw := &kio.ByteReadWriter{Reader: bytes.NewBufferString(`
41 apiVersion: config.kubernetes.io/v1
42 kind: ResourceList
43 items:
44 - apiVersion: v1
45 kind: Service
46 functionConfig:
47 image: baz
48 `),
49 Writer: out}
50
51 require.NoError(t, framework.Execute(p, rw))
52 require.Equal(t, strings.TrimSpace(`
53 apiVersion: config.kubernetes.io/v1
54 kind: ResourceList
55 items:
56 - apiVersion: v1
57 kind: Service
58 - apiVersion: apps/v1
59 kind: Deployment
60 metadata:
61 name: foo
62 namespace: bar
63 spec:
64 template:
65 spec:
66 containers:
67 - name: foo
68 image: baz
69 functionConfig:
70 image: baz
71 `), strings.TrimSpace(out.String()))
72 }
73
74 func TestTemplateProcessor_PatchTemplates(t *testing.T) {
75 type API struct {
76 Spec struct {
77 Replicas int `json:"replicas" yaml:"replicas"`
78 A string `json:"a" yaml:"a"`
79 } `json:"spec" yaml:"spec"`
80 }
81
82 config := &API{}
83 p := framework.TemplateProcessor{
84 TemplateData: config,
85 PatchTemplates: []framework.PatchTemplate{
86
87 &framework.ResourcePatchTemplate{
88 Templates: parser.TemplateFiles("testdata/template-processor/patches/basic"),
89 Selector: &framework.Selector{Names: []string{"foo"}},
90 },
91
92 &framework.ResourcePatchTemplate{
93 Selector: &framework.Selector{Names: []string{"{{.Spec.A}}"}, TemplateData: &config},
94 Templates: parser.TemplateStrings(`
95 metadata:
96 annotations:
97 baz: buz
98 `)},
99 },
100 }
101 out := new(bytes.Buffer)
102
103 rw := &kio.ByteReadWriter{Reader: bytes.NewBufferString(`
104 apiVersion: config.kubernetes.io/v1
105 kind: ResourceList
106 items:
107 - apiVersion: apps/v1
108 kind: Deployment
109 metadata:
110 name: foo
111 spec:
112 template:
113 spec:
114 containers:
115 - name: foo
116 image: baz
117 - apiVersion: apps/v1
118 kind: Deployment
119 metadata:
120 name: bar
121 spec:
122 template:
123 spec:
124 containers:
125 - name: foo
126 image: baz
127 functionConfig:
128 spec:
129 replicas: 5
130 a: bar
131 `),
132 Writer: out}
133
134 require.NoError(t, framework.Execute(p, rw))
135 require.Equal(t, strings.TrimSpace(`
136 apiVersion: config.kubernetes.io/v1
137 kind: ResourceList
138 items:
139 - apiVersion: apps/v1
140 kind: Deployment
141 metadata:
142 name: foo
143 spec:
144 template:
145 spec:
146 containers:
147 - name: foo
148 image: baz
149 replicas: 5
150 - apiVersion: apps/v1
151 kind: Deployment
152 metadata:
153 name: bar
154 annotations:
155 baz: buz
156 spec:
157 template:
158 spec:
159 containers:
160 - name: foo
161 image: baz
162 functionConfig:
163 spec:
164 replicas: 5
165 a: bar
166 `), strings.TrimSpace(out.String()))
167 }
168
169 func TestTemplateProcessor_ContainerPatchTemplates(t *testing.T) {
170 type API struct {
171 Spec struct {
172 Key string `json:"key" yaml:"key"`
173 Value string `json:"value" yaml:"value"`
174 A string `json:"a" yaml:"a"`
175 }
176 }
177
178 config := &API{}
179 p := framework.TemplateProcessor{
180 TemplateData: config,
181 PatchTemplates: []framework.PatchTemplate{
182
183 &framework.ContainerPatchTemplate{
184 Templates: parser.TemplateFiles("testdata/template-processor/container-patches"),
185 Selector: &framework.Selector{Names: []string{"foo"}},
186 },
187
188 &framework.ContainerPatchTemplate{
189 Selector: &framework.Selector{Names: []string{"{{.Spec.A}}"}, TemplateData: &config},
190 Templates: parser.TemplateStrings(`
191 env:
192 - name: Foo
193 value: Bar
194 `)},
195 },
196 }
197
198 out := new(bytes.Buffer)
199 rw := &kio.ByteReadWriter{Reader: bytes.NewBufferString(`
200 apiVersion: config.kubernetes.io/v1
201 kind: ResourceList
202 items:
203 - apiVersion: apps/v1
204 kind: Deployment
205 metadata:
206 name: foo
207 spec:
208 template:
209 spec:
210 containers:
211 - name: a
212 env:
213 - name: EXISTING
214 value: variable
215 - name: b
216 - name: c
217 - apiVersion: apps/v1
218 kind: Deployment
219 metadata:
220 name: bar
221 spec:
222 template:
223 spec:
224 containers:
225 - name: foo
226 image: baz
227 functionConfig:
228 spec:
229 key: Hello
230 value: World
231 a: bar
232 `),
233 Writer: out}
234
235 require.NoError(t, framework.Execute(p, rw))
236 require.Equal(t, strings.TrimSpace(`
237 apiVersion: config.kubernetes.io/v1
238 kind: ResourceList
239 items:
240 - apiVersion: apps/v1
241 kind: Deployment
242 metadata:
243 name: foo
244 spec:
245 template:
246 spec:
247 containers:
248 - name: a
249 env:
250 - name: EXISTING
251 value: variable
252 - name: Hello
253 value: World
254 - name: b
255 env:
256 - name: Hello
257 value: World
258 - name: c
259 env:
260 - name: Hello
261 value: World
262 - apiVersion: apps/v1
263 kind: Deployment
264 metadata:
265 name: bar
266 spec:
267 template:
268 spec:
269 containers:
270 - name: foo
271 image: baz
272 env:
273 - name: Foo
274 value: Bar
275 functionConfig:
276 spec:
277 key: Hello
278 value: World
279 a: bar
280 `), strings.TrimSpace(out.String()))
281 }
282
283 func TestTemplateProcessor_ContainerPatchTemplates_MultipleWorkloadKinds(t *testing.T) {
284 type API struct {
285 Spec struct {
286 Key string `json:"key" yaml:"key"`
287 Value string `json:"value" yaml:"value"`
288 A string `json:"a" yaml:"a"`
289 }
290 }
291 config := &API{}
292 p := framework.TemplateProcessor{
293 TemplateData: config,
294 ResourceTemplates: []framework.ResourceTemplate{{
295 Templates: parser.TemplateFiles("testdata/template-processor/templates/container-sources"),
296 }},
297 PatchTemplates: []framework.PatchTemplate{
298 &framework.ContainerPatchTemplate{
299 Templates: parser.TemplateFiles("testdata/template-processor/container-patches"),
300 },
301 },
302 }
303
304 out := new(bytes.Buffer)
305 rw := &kio.ByteReadWriter{Writer: out, Reader: bytes.NewBufferString(`
306 apiVersion: config.kubernetes.io/v1
307 kind: ResourceList
308 items: []
309 functionConfig:
310 spec:
311 key: Hello
312 value: World
313 a: bar
314 `)}
315
316 require.NoError(t, framework.Execute(p, rw))
317 resources, err := (&kio.ByteReader{Reader: out}).Read()
318 require.NoError(t, err)
319 envRegex := regexp.MustCompile(strings.TrimSpace(`
320 \s+ env:
321 \s+ - name: EXISTING
322 \s+ value: variable
323 \s+ - name: Hello
324 \s+ value: World
325 `))
326 require.Equal(t, 9, len(resources))
327 for i, r := range resources {
328 t.Run(r.GetKind(), func(t *testing.T) {
329 assert.Regexp(t, envRegex, resources[i].MustString())
330 })
331 }
332 }
333
334 func TestSimpleProcessor_Process_loads_config(t *testing.T) {
335 cfg := new(struct {
336 Value string `yaml:"value"`
337 })
338 p := framework.SimpleProcessor{
339 Filter: kio.FilterFunc(func(items []*yaml.RNode) ([]*yaml.RNode, error) {
340 if cfg.Value != "dataFromResourceList" {
341 return nil, errors.Errorf("got incorrect config value %q", cfg.Value)
342 }
343 return items, nil
344 }),
345 Config: &cfg,
346 }
347 rl := framework.ResourceList{
348 FunctionConfig: yaml.NewMapRNode(&map[string]string{
349 "value": "dataFromResourceList",
350 }),
351 }
352 require.NoError(t, p.Process(&rl))
353 }
354
355 func TestSimpleProcessor_Process_Error(t *testing.T) {
356 tests := []struct {
357 name string
358 filter kio.Filter
359 config interface{}
360 wantErr string
361 }{
362 {
363 name: "error when filter is nil",
364 config: map[string]string{},
365 filter: nil,
366 wantErr: "processing filter: ResourceList cannot run apply nil filter",
367 }, {
368 name: "no error when config is nil",
369 config: nil,
370 filter: kio.FilterFunc(func(items []*yaml.RNode) ([]*yaml.RNode, error) {
371 return items, nil
372 }),
373 wantErr: "",
374 },
375 {
376 name: "error in filter",
377 wantErr: "processing filter: err from filter",
378 filter: kio.FilterFunc(func(_ []*yaml.RNode) ([]*yaml.RNode, error) {
379 return nil, errors.Errorf("err from filter")
380 }),
381 },
382 }
383 for _, tt := range tests {
384 tt := tt
385 t.Run(tt.name, func(t *testing.T) {
386 p := framework.SimpleProcessor{
387 Filter: tt.filter,
388 Config: tt.config,
389 }
390 rl := framework.ResourceList{
391 FunctionConfig: yaml.NewMapRNode(&map[string]string{
392 "value": "dataFromResourceList",
393 }),
394 }
395 err := p.Process(&rl)
396 if tt.wantErr == "" {
397 require.NoError(t, err)
398 } else {
399 assert.EqualError(t, err, tt.wantErr)
400 }
401 })
402 }
403 }
404
405 func TestVersionedAPIProcessor_Process_Error(t *testing.T) {
406 tests := []struct {
407 name string
408 filterProvider framework.FilterProvider
409 apiVersion string
410 kind string
411 wantErr string
412 }{
413 {
414 name: "error in filter",
415 filterProvider: framework.FilterProviderFunc(func(_, _ string) (kio.Filter, error) {
416 return &framework.AndSelector{FailOnEmptyMatch: true}, nil
417 }),
418 wantErr: "selector did not select any items",
419 },
420 {
421 name: "error GVKFilterMap no filter for kind",
422 filterProvider: framework.GVKFilterMap{
423 "puppy": {
424 "pets.example.com/v1beta1": &framework.Selector{},
425 },
426 },
427 kind: "kitten",
428 apiVersion: "pets.example.com/v1beta1",
429 wantErr: "kind \"kitten\" is not supported",
430 },
431 {
432 name: "error GVKFilterMap no filter for version",
433 filterProvider: framework.GVKFilterMap{
434 "kitten": {
435 "pets.example.com/v1alpha1": &framework.Selector{},
436 },
437 },
438 kind: "kitten",
439 apiVersion: "pets.example.com/v1beta1",
440 wantErr: "apiVersion \"pets.example.com/v1beta1\" is not supported for kind \"kitten\"",
441 },
442 {
443 name: "error GVKFilterMap blank kind",
444 filterProvider: framework.GVKFilterMap{},
445 kind: "",
446 apiVersion: "pets.example.com/v1beta1",
447 wantErr: "unable to identify provider for resource: kind is required",
448 },
449 {
450 name: "error GVKFilterMap blank version",
451 filterProvider: framework.GVKFilterMap{},
452 kind: "kitten",
453 apiVersion: "",
454 wantErr: "unable to identify provider for resource: apiVersion is required",
455 },
456 }
457 for _, tt := range tests {
458 tt := tt
459 t.Run(tt.name, func(t *testing.T) {
460 p := framework.VersionedAPIProcessor{
461 FilterProvider: tt.filterProvider,
462 }
463 rl := framework.ResourceList{
464 FunctionConfig: yaml.NewMapRNode(&map[string]string{
465 "apiVersion": tt.apiVersion,
466 "kind": tt.kind,
467 }),
468 }
469 err := p.Process(&rl)
470 require.Error(t, err)
471 assert.Contains(t, err.Error(), tt.wantErr)
472 })
473 }
474 }
475
476 func TestTemplateProcessor_Process_Error(t *testing.T) {
477 tests := []struct {
478 name string
479 processor framework.TemplateProcessor
480 wantErr string
481 }{
482 {
483 name: "ResourcePatchTemplate is not a resource",
484 processor: framework.TemplateProcessor{
485 PatchTemplates: []framework.PatchTemplate{
486 &framework.ResourcePatchTemplate{
487 Templates: parser.TemplateStrings(`aString
488 another`),
489 }},
490 },
491 wantErr: `failed to parse rendered patch template into a resource:
492 001 aString
493 002 another
494 : wrong node kind: expected MappingNode but got ScalarNode: node contents:
495 aString another
496 `,
497 },
498 {
499 name: "ResourcePatchTemplate is invalid template",
500 processor: framework.TemplateProcessor{
501 PatchTemplates: []framework.PatchTemplate{
502 &framework.ResourcePatchTemplate{
503 Templates: parser.TemplateStrings("foo: {{ .OOPS }}"),
504 }},
505 },
506 wantErr: "can't evaluate field OOPS",
507 },
508 {
509 name: "ContainerPatchTemplate is not a resource",
510 processor: framework.TemplateProcessor{
511 PatchTemplates: []framework.PatchTemplate{
512 &framework.ContainerPatchTemplate{
513 Templates: parser.TemplateStrings(`aString
514 another`),
515 }},
516 },
517 wantErr: `failed to parse rendered patch template into a resource:
518 001 aString
519 002 another
520 : wrong node kind: expected MappingNode but got ScalarNode: node contents:
521 aString another
522 `,
523 },
524 {
525 name: "ContainerPatchTemplate is invalid template",
526 processor: framework.TemplateProcessor{
527 PatchTemplates: []framework.PatchTemplate{
528 &framework.ContainerPatchTemplate{
529 Templates: parser.TemplateStrings("foo: {{ .OOPS }}"),
530 }},
531 },
532 wantErr: "can't evaluate field OOPS",
533 },
534 {
535 name: "ResourceTemplate is not a resource",
536 processor: framework.TemplateProcessor{
537 ResourceTemplates: []framework.ResourceTemplate{{
538 Templates: parser.TemplateStrings(`aString
539 another`),
540 }},
541 },
542 wantErr: `failed to parse rendered template into a resource:
543 001 aString
544 002 another
545 : wrong node kind: expected MappingNode but got ScalarNode: node contents:
546 aString another
547 `,
548 },
549 {
550 name: "ResourceTemplate is invalid template",
551 processor: framework.TemplateProcessor{
552 ResourceTemplates: []framework.ResourceTemplate{{
553 Templates: parser.TemplateStrings("foo: {{ .OOPS }}"),
554 }},
555 },
556 wantErr: "can't evaluate field OOPS",
557 },
558 }
559 for _, tt := range tests {
560 tt := tt
561 t.Run(tt.name, func(t *testing.T) {
562 rl := framework.ResourceList{
563 Items: []*yaml.RNode{
564 yaml.MustParse(`
565 kind: Deployment
566 apiVersion: apps/v1
567 metadata:
568 name: foo
569 spec:
570 replicas: 5
571 template:
572 spec:
573 containers:
574 - name: foo
575 `),
576 },
577 FunctionConfig: yaml.NewMapRNode(&map[string]string{
578 "value": "dataFromResourceList",
579 }),
580 }
581 tt.processor.TemplateData = new(struct {
582 Value string `yaml:"value"`
583 })
584 err := tt.processor.Process(&rl)
585 require.Error(t, err)
586 assert.Contains(t, err.Error(), tt.wantErr)
587 })
588 }
589 }
590
591 func TestTemplateProcessor_AdditionalSchemas(t *testing.T) {
592 p := framework.TemplateProcessor{
593 AdditionalSchemas: parser.SchemaFiles("testdata/template-processor/schemas"),
594 ResourceTemplates: []framework.ResourceTemplate{{
595 Templates: parser.TemplateFiles("testdata/template-processor/templates/custom-resource/foo.template.yaml"),
596 }},
597 PatchTemplates: []framework.PatchTemplate{
598 &framework.ResourcePatchTemplate{
599 Templates: parser.TemplateFiles("testdata/template-processor/patches/custom-resource/patch.template.yaml")},
600 },
601 }
602 out := new(bytes.Buffer)
603
604 rw := &kio.ByteReadWriter{Reader: bytes.NewBufferString(`
605 apiVersion: config.kubernetes.io/v1
606 kind: ResourceList
607 items:
608 - apiVersion: example.com/v1
609 kind: Foo
610 metadata:
611 name: source
612 spec:
613 targets:
614 - app: C
615 size: medium
616 `),
617 Writer: out}
618 require.NoError(t, framework.Execute(p, rw))
619 require.Equal(t, strings.TrimSpace(`
620 apiVersion: config.kubernetes.io/v1
621 kind: ResourceList
622 items:
623 - apiVersion: example.com/v1
624 kind: Foo
625 metadata:
626 name: source
627 spec:
628 targets:
629 - app: C
630 size: large
631 type: Ruby
632 - app: B
633 size: small
634 - apiVersion: example.com/v1
635 kind: Foo
636 metadata:
637 name: example
638 spec:
639 targets:
640 - app: A
641 type: Go
642 size: small
643 - app: B
644 type: Go
645 size: small
646 - app: C
647 type: Ruby
648 size: large
649 `), strings.TrimSpace(out.String()))
650 found := openapi.SchemaForResourceType(yaml.TypeMeta{
651 APIVersion: "example.com/v1",
652 Kind: "Foo",
653 })
654 require.Nil(t, found, "openAPI schema was not reset")
655 }
656
657 func TestTemplateProcessor_Validator(t *testing.T) {
658
659
660 p := func() framework.ResourceListProcessor {
661 return &framework.VersionedAPIProcessor{FilterProvider: framework.GVKFilterMap{
662 "JavaSpringBoot": {
663 "example.com/v1alpha1": &v1alpha1JavaSpringBoot{},
664 }}}
665 }
666 c := frameworktestutil.ProcessorResultsChecker{
667 TestDataDirectory: "testdata/validation",
668 Processor: p,
669 }
670 c.Assert(t)
671 }
672
673 type jsonTagTest struct {
674 Name string `json:"name"`
675 Test bool `json:"test"`
676 }
677
678 type yamlTagTest struct {
679 Name string `yaml:"name"`
680 Test bool `yaml:"test"`
681 }
682
683 type customErrorTest struct {
684 v1alpha1JavaSpringBoot
685 }
686
687 func (e customErrorTest) Schema() (*spec.Schema, error) {
688 return e.v1alpha1JavaSpringBoot.Schema()
689 }
690
691 func (e customErrorTest) Validate() error {
692 return errors.Errorf("Custom errors:\n- first error\n- second error")
693 }
694
695 type errorMergeTest struct {
696 v1alpha1JavaSpringBoot
697 }
698
699 func (e errorMergeTest) Schema() (*spec.Schema, error) {
700 return e.v1alpha1JavaSpringBoot.Schema()
701 }
702
703 func (e errorMergeTest) Validate() error {
704 if strings.HasSuffix(e.Spec.Image, "latest") {
705 return validationErrors.CompositeValidationError(errors.Errorf("spec.image cannot be tagged :latest"))
706 }
707 return nil
708 }
709
710 func (a schemaProviderOnlyTest) Schema() (*spec.Schema, error) {
711 schema, err := framework.SchemaFromFunctionDefinition(resid.NewGvk("example.com", "v1alpha1", "JavaSpringBoot"), javaSpringBootDefinition)
712 return schema, errors.WrapPrefixf(err, "parsing JavaSpringBoot schema")
713 }
714
715 type schemaProviderOnlyTest struct {
716 Metadata Metadata `yaml:"metadata" json:"metadata"`
717 Spec v1alpha1JavaSpringBootSpec `yaml:"spec" json:"spec"`
718 }
719
720 func TestLoadFunctionConfig(t *testing.T) {
721 tests := []struct {
722 name string
723 src *yaml.RNode
724 api interface{}
725 want interface{}
726 wantErrMsgs []string
727 }{
728 {
729 name: "combines schema-based and non-composite custom errors",
730 src: yaml.MustParse(`
731 apiVersion: example.com/v1alpha1
732 kind: JavaSpringBoot
733 spec:
734 replicas: 11
735 domain: foo.myco.io
736 image: nginx:latest
737 `),
738 api: &customErrorTest{},
739 wantErrMsgs: []string{
740 "validation failure list:",
741 "spec.replicas in body should be less than or equal to 9",
742 "spec.domain in body should match 'example\\.com$'",
743 `Custom errors:
744 - first error
745 - second error`,
746 },
747 },
748 {
749 name: "merges schema-based errors with custom composite errors",
750 src: yaml.MustParse(`
751 apiVersion: example.com/v1alpha1
752 kind: JavaSpringBoot
753 spec:
754 replicas: 11
755 domain: foo.myco.io
756 image: nginx:latest
757 `),
758 api: &errorMergeTest{},
759 wantErrMsgs: []string{"validation failure list:",
760 "spec.replicas in body should be less than or equal to 9",
761 "spec.domain in body should match 'example\\.com$'",
762 "spec.image cannot be tagged :latest"},
763 },
764 {
765 name: "schema errors only",
766 src: yaml.MustParse(`
767 apiVersion: example.com/v1alpha1
768 kind: JavaSpringBoot
769 spec:
770 replicas: 11
771 `),
772 api: &errorMergeTest{},
773 wantErrMsgs: []string{
774 `validation failure list:
775 spec.replicas in body should be less than or equal to 9`,
776 },
777 }, {
778 name: "schema provider only",
779 src: yaml.MustParse(`
780 apiVersion: example.com/v1alpha1
781 kind: JavaSpringBoot
782 spec:
783 replicas: 11
784 `),
785 api: &schemaProviderOnlyTest{},
786 wantErrMsgs: []string{
787 `validation failure list:
788 spec.replicas in body should be less than or equal to 9`,
789 },
790 },
791 {
792 name: "custom errors only",
793 src: yaml.MustParse(`
794 apiVersion: example.com/v1alpha1
795 kind: JavaSpringBoot
796 spec:
797 image: nginx:latest
798 `),
799 api: &errorMergeTest{},
800 wantErrMsgs: []string{
801 `validation failure list:
802 spec.image cannot be tagged :latest`},
803 },
804 {
805 name: "both custom and schema error hooks defined, but no errors produced",
806 src: yaml.MustParse(`
807 apiVersion: example.com/v1alpha1
808 kind: JavaSpringBoot
809 spec:
810 image: nginx:1.0
811 replicas: 3
812 domain: bar.example.com
813 `),
814 api: &errorMergeTest{},
815 want: &errorMergeTest{v1alpha1JavaSpringBoot: v1alpha1JavaSpringBoot{
816 Spec: v1alpha1JavaSpringBootSpec{Replicas: 3, Domain: "bar.example.com", Image: "nginx:1.0"}},
817 },
818 },
819 {
820 name: "successfully loads types that include fields only tagged with json markers",
821 src: yaml.MustParse(`
822 name: tester
823 test: true
824 `),
825 api: &jsonTagTest{},
826 want: &jsonTagTest{Name: "tester", Test: true},
827 },
828 {
829 name: "successfully loads types that include fields only tagged with yaml markers",
830 src: yaml.MustParse(`
831 name: tester
832 test: true
833 `),
834 api: &yamlTagTest{},
835 want: &yamlTagTest{Name: "tester", Test: true},
836 },
837 }
838
839 for _, tt := range tests {
840 t.Run(tt.name, func(t *testing.T) {
841 err := framework.LoadFunctionConfig(tt.src, tt.api)
842 if len(tt.wantErrMsgs) == 0 {
843 require.NoError(t, err)
844 require.Equal(t, tt.want, tt.api)
845 } else {
846 require.Error(t, err)
847 for _, msg := range tt.wantErrMsgs {
848 require.Contains(t, err.Error(), msg)
849 }
850 }
851 })
852 }
853 }
854
View as plain text