1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package validate
16
17 import (
18 "encoding/json"
19 "net/http"
20 "os"
21 "path/filepath"
22 "strings"
23 "testing"
24
25 "github.com/go-openapi/swag"
26 "github.com/stretchr/testify/assert"
27 "github.com/stretchr/testify/require"
28 "k8s.io/kube-openapi/pkg/validation/spec"
29 "k8s.io/kube-openapi/pkg/validation/strfmt"
30 )
31
32
33 type schemaTestT struct {
34 Description string `json:"description"`
35 Schema *spec.Schema `json:"schema"`
36 Tests []struct {
37 Description string `json:"description"`
38 Data interface{} `json:"data"`
39 Valid bool `json:"valid"`
40 }
41 }
42
43 var jsonSchemaFixturesPath = filepath.Join("fixtures", "jsonschema_suite")
44 var schemaFixturesPath = filepath.Join("fixtures", "schemas")
45 var formatFixturesPath = filepath.Join("fixtures", "formats")
46
47 func enabled() []string {
48
49 return []string{
50 "minLength",
51 "maxLength",
52 "pattern",
53 "type",
54 "minimum",
55 "maximum",
56 "multipleOf",
57 "enum",
58 "default",
59 "dependencies",
60 "items",
61 "maxItems",
62 "maxProperties",
63 "minItems",
64 "minProperties",
65 "patternProperties",
66 "required",
67 "additionalItems",
68 "uniqueItems",
69 "properties",
70 "additionalProperties",
71 "allOf",
72 "not",
73 "oneOf",
74 "anyOf",
75 "ref",
76 "definitions",
77 "refRemote",
78 "format",
79 }
80 }
81
82 var optionalFixtures = []string{
83
84
85
86
87
88 }
89
90 var extendedFixtures = []string{
91 "extended-format",
92 }
93
94 func isEnabled(nm string) bool {
95 return swag.ContainsStringsCI(enabled(), nm)
96 }
97
98 func isOptionalEnabled(nm string) bool {
99 return swag.ContainsStringsCI(optionalFixtures, nm)
100 }
101
102 func isExtendedEnabled(nm string) bool {
103 return swag.ContainsStringsCI(extendedFixtures, nm)
104 }
105
106 func TestJSONSchemaSuite(t *testing.T) {
107
108 go func() {
109 err := http.ListenAndServe("localhost:1234", http.FileServer(http.Dir(jsonSchemaFixturesPath+"/remotes")))
110 if err != nil {
111 panic(err.Error())
112 }
113 }()
114
115 files, err := os.ReadDir(jsonSchemaFixturesPath)
116 if err != nil {
117 t.Fatal(err)
118 }
119
120 for _, f := range files {
121 if f.IsDir() {
122 continue
123 }
124 fileName := f.Name()
125 t.Run(fileName, func(t *testing.T) {
126 t.Parallel()
127 specName := strings.TrimSuffix(fileName, filepath.Ext(fileName))
128 if !isEnabled(specName) {
129 t.Logf("WARNING: fixture from jsonschema-test-suite not enabled: %s", specName)
130 return
131 }
132 t.Log("Running " + specName)
133 b, _ := os.ReadFile(filepath.Join(jsonSchemaFixturesPath, fileName))
134 doTestSchemaSuite(t, b)
135 })
136 }
137 }
138
139 func TestSchemaFixtures(t *testing.T) {
140 files, err := os.ReadDir(schemaFixturesPath)
141 if err != nil {
142 t.Fatal(err)
143 }
144
145 for _, f := range files {
146 if f.IsDir() {
147 continue
148 }
149 fileName := f.Name()
150 t.Run(fileName, func(t *testing.T) {
151 t.Parallel()
152 specName := strings.TrimSuffix(fileName, filepath.Ext(fileName))
153 t.Log("Running " + specName)
154 b, _ := os.ReadFile(filepath.Join(schemaFixturesPath, fileName))
155 doTestSchemaSuite(t, b)
156 })
157 }
158 }
159
160 func TestOptionalJSONSchemaSuite(t *testing.T) {
161 jsonOptionalSchemaFixturesPath := filepath.Join(jsonSchemaFixturesPath, "optional")
162 files, err := os.ReadDir(jsonOptionalSchemaFixturesPath)
163 if err != nil {
164 t.Fatal(err)
165 }
166
167 for _, f := range files {
168 if f.IsDir() {
169 continue
170 }
171 fileName := f.Name()
172 t.Run(fileName, func(t *testing.T) {
173 t.Parallel()
174 specName := strings.TrimSuffix(fileName, filepath.Ext(fileName))
175 if !isOptionalEnabled(specName) {
176 t.Logf("INFO: fixture from jsonschema-test-suite [optional] not enabled: %s", specName)
177 return
178 }
179 t.Log("Running [optional] " + specName)
180 b, _ := os.ReadFile(filepath.Join(jsonOptionalSchemaFixturesPath, fileName))
181 doTestSchemaSuite(t, b)
182 })
183 }
184 }
185
186
187 func TestFormat_JSONSchemaExtended(t *testing.T) {
188 jsonFormatSchemaFixturesPath := filepath.Join(formatFixturesPath)
189 files, err := os.ReadDir(jsonFormatSchemaFixturesPath)
190 if err != nil {
191 t.Fatal(err)
192 }
193
194 for _, f := range files {
195 if f.IsDir() {
196 continue
197 }
198 fileName := f.Name()
199 t.Run(fileName, func(t *testing.T) {
200 t.Parallel()
201 specName := strings.TrimSuffix(fileName, filepath.Ext(fileName))
202 if !isExtendedEnabled(specName) {
203 t.Logf("INFO: fixture from extended tests suite [formats] not enabled: %s", specName)
204 return
205 }
206 t.Log("Running [extended formats] " + specName)
207 b, _ := os.ReadFile(filepath.Join(jsonFormatSchemaFixturesPath, fileName))
208 doTestSchemaSuite(t, b)
209 })
210 }
211 }
212
213 func doTestSchemaSuite(t *testing.T, doc []byte) {
214
215 var testDescriptions []schemaTestT
216 eru := json.Unmarshal(doc, &testDescriptions)
217 require.NoError(t, eru)
218
219 for _, testDescription := range testDescriptions {
220 b, _ := testDescription.Schema.MarshalJSON()
221 tmpFile, err := os.CreateTemp(os.TempDir(), "validate-test")
222 assert.NoError(t, err)
223 _, _ = tmpFile.Write(b)
224 tmpFile.Close()
225 defer func() { _ = os.Remove(tmpFile.Name()) }()
226
227 validator := NewSchemaValidator(testDescription.Schema, nil, "data", strfmt.Default)
228 for _, test := range testDescription.Tests {
229 result := validator.Validate(test.Data)
230 assert.NotNil(t, result, test.Description+" should validate")
231
232 if test.Valid {
233 assert.Empty(t, result.Errors, test.Description+" should not have errors")
234 } else {
235 assert.NotEmpty(t, result.Errors, test.Description+" should have errors")
236 }
237 }
238 }
239 }
240
View as plain text