1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package validate
16
17 import (
18 "testing"
19
20 "github.com/stretchr/testify/assert"
21 kubeopenapierrors "k8s.io/kube-openapi/pkg/validation/errors"
22 "k8s.io/kube-openapi/pkg/validation/spec"
23 "k8s.io/kube-openapi/pkg/validation/strfmt"
24 )
25
26 func itemsFixture() map[string]interface{} {
27 return map[string]interface{}{
28 "type": "array",
29 "items": "dummy",
30 }
31 }
32
33 func expectAllValid(t *testing.T, ov ValueValidator, dataValid, dataInvalid map[string]interface{}) {
34 res := ov.Validate(dataValid)
35 assert.Equal(t, 0, len(res.Errors))
36
37 res = ov.Validate(dataInvalid)
38 assert.Equal(t, 0, len(res.Errors))
39 }
40
41 func expectOnlyInvalid(t *testing.T, ov ValueValidator, dataValid, dataInvalid map[string]interface{}) {
42 res := ov.Validate(dataValid)
43 assert.Equal(t, 0, len(res.Errors))
44
45 res = ov.Validate(dataInvalid)
46 assert.NotEqual(t, 0, len(res.Errors))
47 }
48
49 func TestItemsMustBeTypeArray(t *testing.T) {
50 ov := new(objectValidator)
51 dataValid := itemsFixture()
52 dataInvalid := map[string]interface{}{
53 "type": "object",
54 "items": "dummy",
55 }
56 expectAllValid(t, ov, dataValid, dataInvalid)
57 }
58
59 func TestItemsMustHaveType(t *testing.T) {
60 ov := new(objectValidator)
61 dataValid := itemsFixture()
62 dataInvalid := map[string]interface{}{
63 "items": "dummy",
64 }
65 expectAllValid(t, ov, dataValid, dataInvalid)
66 }
67
68 func TestTypeArrayMustHaveItems(t *testing.T) {
69 ov := new(objectValidator)
70 dataValid := itemsFixture()
71 dataInvalid := map[string]interface{}{
72 "type": "array",
73 "key": "dummy",
74 }
75 expectAllValid(t, ov, dataValid, dataInvalid)
76 }
77
78
79
80
81 func TestObjectValidator_EdgeCases(t *testing.T) {
82 s := objectValidator{}
83 s.SetPath("path")
84 assert.Equal(t, "path", s.Path)
85 }
86
87 func TestMinPropertiesMaxPropertiesDontShortCircuit(t *testing.T) {
88 s := objectValidator{
89 In: "body",
90 Path: "some.path[5]",
91 KnownFormats: strfmt.Default,
92 MinProperties: ptr(int64(20)),
93 MaxProperties: ptr(int64(0)),
94 Properties: map[string]spec.Schema{
95 "intField": {
96 SchemaProps: spec.SchemaProps{
97 Type: spec.StringOrArray{"integer"},
98 },
99 },
100 "requiredField": {
101 SchemaProps: spec.SchemaProps{
102 Type: spec.StringOrArray{"string"},
103 },
104 },
105 },
106 Required: []string{"requiredField"},
107 AdditionalProperties: &spec.SchemaOrBool{
108 Allows: true,
109 Schema: &spec.Schema{
110 SchemaProps: spec.SchemaProps{
111 Type: spec.StringOrArray{"string"},
112 Pattern: "^20[0-9][0-9]",
113 },
114 },
115 },
116 Options: SchemaValidatorOptions{
117 NewValidatorForIndex: func(index int, schema *spec.Schema, rootSchema interface{}, root string, formats strfmt.Registry, opts ...Option) ValueValidator {
118 return NewSchemaValidator(schema, rootSchema, root, formats, opts...)
119 },
120 NewValidatorForField: func(field string, schema *spec.Schema, rootSchema interface{}, root string, formats strfmt.Registry, opts ...Option) ValueValidator {
121 return NewSchemaValidator(schema, rootSchema, root, formats, opts...)
122 },
123 },
124 }
125
126 obj := map[string]interface{}{
127 "field": "hello, world",
128 }
129 res := s.Validate(obj)
130
131 assert.ElementsMatch(t, []*kubeopenapierrors.Validation{
132 kubeopenapierrors.TooFewProperties(s.Path, s.In, *s.MinProperties, int64(len(obj))),
133 kubeopenapierrors.TooManyProperties(s.Path, s.In, *s.MaxProperties, int64(len(obj))),
134 kubeopenapierrors.FailedPattern(s.Path+"."+"field", s.In, s.AdditionalProperties.Schema.Pattern, "hello, world"),
135 kubeopenapierrors.Required(s.Path+"."+"requiredField", s.In),
136 }, res.Errors)
137
138 obj = map[string]interface{}{
139 "field": "hello, world",
140 "field2": "hello, other world",
141 "field3": "hello, third world",
142 "intField": "a string",
143 }
144 res = s.Validate(obj)
145
146 assert.ElementsMatch(t, []*kubeopenapierrors.Validation{
147 kubeopenapierrors.TooFewProperties(s.Path, s.In, *s.MinProperties, int64(len(obj))),
148 kubeopenapierrors.TooManyProperties(s.Path, s.In, *s.MaxProperties, int64(len(obj))),
149 kubeopenapierrors.FailedPattern(s.Path+"."+"field", s.In, s.AdditionalProperties.Schema.Pattern, "hello, world"),
150 kubeopenapierrors.FailedPattern(s.Path+"."+"field2", s.In, s.AdditionalProperties.Schema.Pattern, "hello, other world"),
151 kubeopenapierrors.FailedPattern(s.Path+"."+"field3", s.In, s.AdditionalProperties.Schema.Pattern, "hello, third world"),
152 kubeopenapierrors.InvalidType(s.Path+"."+"intField", s.In, "integer", "string"),
153 kubeopenapierrors.Required(s.Path+"."+"requiredField", s.In),
154 }, res.Errors)
155 }
156
157 func ptr[T any](v T) *T {
158 return &v
159 }
160
View as plain text