Skip to content

Commit c0729c6

Browse files
committed
schema: add/update schema validation tests.
Add explicit empty ({}) JSON test data. Add a few basic schema validation unit tests. Signed-off-by: Krisztian Litkey <[email protected]>
1 parent b3e367e commit c0729c6

File tree

2 files changed

+378
-0
lines changed

2 files changed

+378
-0
lines changed

schema/schema_test.go

Lines changed: 377 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,377 @@
1+
/*
2+
Copyright © 2022 The CDI Authors
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package schema_test
18+
19+
import (
20+
"bytes"
21+
"io"
22+
"io/fs"
23+
"io/ioutil"
24+
"os"
25+
"path/filepath"
26+
"testing"
27+
28+
"github.com/stretchr/testify/require"
29+
30+
"github.com/container-orchestrated-devices/container-device-interface/pkg/cdi"
31+
"github.com/container-orchestrated-devices/container-device-interface/schema"
32+
)
33+
34+
var (
35+
unloadable = map[string]bool{
36+
"empty.json": true,
37+
}
38+
39+
none = schema.NopSchema()
40+
)
41+
42+
func TestLoad(t *testing.T) {
43+
type testCase struct {
44+
testName string
45+
schemaName string
46+
}
47+
for _, tc := range []*testCase{
48+
{
49+
testName: "builtin schema",
50+
schemaName: "builtin",
51+
},
52+
{
53+
testName: "externally loaded schema.json",
54+
schemaName: "file://./schema.json",
55+
},
56+
{
57+
testName: "disabled/none schema",
58+
schemaName: "none",
59+
},
60+
} {
61+
t.Run(tc.testName, func(t *testing.T) {
62+
scm, err := schema.Load(tc.schemaName)
63+
require.NoError(t, err)
64+
require.NotNil(t, scm)
65+
})
66+
}
67+
}
68+
69+
func TestValidateFile(t *testing.T) {
70+
type testCase struct {
71+
testName string
72+
schemaName string
73+
}
74+
for _, tc := range []*testCase{
75+
{
76+
testName: "builtin schema",
77+
schemaName: "builtin",
78+
},
79+
{
80+
testName: "externally loaded schema.json",
81+
schemaName: "file://./schema.json",
82+
},
83+
{
84+
testName: "disabled/none schema",
85+
schemaName: "none",
86+
},
87+
} {
88+
t.Run(tc.testName, func(t *testing.T) {
89+
scm := loadSchema(t, tc.schemaName)
90+
91+
scanAndValidate(t, scm, "./testdata/good", true, validateFile)
92+
scanAndValidate(t, scm, "./testdata/bad", false, validateFile)
93+
old := schema.Get()
94+
schema.Set(scm)
95+
scanAndValidate(t, nil, "./testdata/good", true, validateFile)
96+
scanAndValidate(t, nil, "./testdata/bad", false, validateFile)
97+
schema.Set(old)
98+
})
99+
}
100+
}
101+
102+
func TestValidateData(t *testing.T) {
103+
type testCase struct {
104+
testName string
105+
schemaName string
106+
}
107+
for _, tc := range []*testCase{
108+
{
109+
testName: "builtin schema",
110+
schemaName: "builtin",
111+
},
112+
{
113+
testName: "externally loaded schema.json",
114+
schemaName: "file://./schema.json",
115+
},
116+
{
117+
testName: "disabled/none schema",
118+
schemaName: "none",
119+
},
120+
} {
121+
t.Run(tc.testName, func(t *testing.T) {
122+
scm := loadSchema(t, tc.schemaName)
123+
124+
scanAndValidate(t, scm, "./testdata/good", true, validateData)
125+
scanAndValidate(t, scm, "./testdata/bad", false, validateData)
126+
old := schema.Get()
127+
schema.Set(scm)
128+
scanAndValidate(t, nil, "./testdata/good", true, validateData)
129+
scanAndValidate(t, nil, "./testdata/bad", false, validateData)
130+
schema.Set(old)
131+
})
132+
}
133+
}
134+
135+
func TestValidateReader(t *testing.T) {
136+
type testCase struct {
137+
testName string
138+
schemaName string
139+
}
140+
for _, tc := range []*testCase{
141+
{
142+
testName: "builtin schema",
143+
schemaName: "builtin",
144+
},
145+
{
146+
testName: "externally loaded schema.json",
147+
schemaName: "file://./schema.json",
148+
},
149+
{
150+
testName: "disabled/none schema",
151+
schemaName: "none",
152+
},
153+
} {
154+
t.Run(tc.testName, func(t *testing.T) {
155+
scm := loadSchema(t, tc.schemaName)
156+
157+
scanAndValidate(t, scm, "./testdata/good", true, validateRead)
158+
scanAndValidate(t, scm, "./testdata/bad", false, validateRead)
159+
old := schema.Get()
160+
schema.Set(scm)
161+
scanAndValidate(t, nil, "./testdata/good", true, validateRead)
162+
scanAndValidate(t, nil, "./testdata/bad", false, validateRead)
163+
schema.Set(old)
164+
})
165+
}
166+
}
167+
168+
func TestValidateReadAndValidate(t *testing.T) {
169+
type testCase struct {
170+
testName string
171+
schemaName string
172+
}
173+
for _, tc := range []*testCase{
174+
{
175+
testName: "builtin schema",
176+
schemaName: "builtin",
177+
},
178+
{
179+
testName: "externally loaded schema.json",
180+
schemaName: "file://./schema.json",
181+
},
182+
{
183+
testName: "disabled/none schema",
184+
schemaName: "none",
185+
},
186+
} {
187+
188+
t.Run(tc.testName, func(t *testing.T) {
189+
scm := loadSchema(t, tc.schemaName)
190+
191+
scanAndValidate(t, scm, "./testdata/good", true, readAndValidate)
192+
scanAndValidate(t, scm, "./testdata/bad", false, readAndValidate)
193+
old := schema.Get()
194+
schema.Set(scm)
195+
scanAndValidate(t, nil, "./testdata/good", true, readAndValidate)
196+
scanAndValidate(t, nil, "./testdata/bad", false, readAndValidate)
197+
schema.Set(old)
198+
})
199+
}
200+
}
201+
202+
func TestValidateSpec(t *testing.T) {
203+
type testCase struct {
204+
testName string
205+
schemaName string
206+
}
207+
for _, tc := range []*testCase{
208+
{
209+
testName: "builtin schema",
210+
schemaName: "builtin",
211+
},
212+
{
213+
testName: "externally loaded schema.json",
214+
schemaName: "file://./schema.json",
215+
},
216+
{
217+
testName: "disabled/none schema",
218+
schemaName: "none",
219+
},
220+
} {
221+
t.Run(tc.testName, func(t *testing.T) {
222+
scm := loadSchema(t, tc.schemaName)
223+
224+
scanAndValidate(t, scm, "./testdata/good", true, validateSpec)
225+
scanAndValidate(t, scm, "./testdata/bad", false, validateSpec)
226+
old := schema.Get()
227+
schema.Set(scm)
228+
scanAndValidate(t, nil, "./testdata/good", true, validateSpec)
229+
scanAndValidate(t, nil, "./testdata/bad", false, validateSpec)
230+
schema.Set(old)
231+
})
232+
}
233+
}
234+
235+
func scanAndValidate(t *testing.T, scm *schema.Schema, dir string, isValid bool,
236+
validateFn func(t *testing.T, scm *schema.Schema, path string, shouldLoad, isValid bool)) {
237+
err := filepath.Walk(dir, func(path string, info fs.FileInfo, err error) error {
238+
if err != nil {
239+
return err
240+
}
241+
if info.IsDir() {
242+
if path == dir {
243+
return nil
244+
}
245+
scanAndValidate(t, scm, path, isValid, validateFn)
246+
} else {
247+
if name := info.Name(); filepath.Ext(name) != ".json" || name == "empty.json" {
248+
return nil
249+
}
250+
//fmt.Printf("*** processing %s...\n", path)
251+
validateFn(t, scm, path, !unloadable[filepath.Base(path)], isValid)
252+
}
253+
254+
return nil
255+
})
256+
require.NoError(t, err)
257+
}
258+
259+
func validateFile(t *testing.T, scm *schema.Schema, path string, shouldLoad, isValid bool) {
260+
var err error
261+
262+
if scm != nil {
263+
err = scm.ValidateFile(path)
264+
} else {
265+
err = schema.ValidateFile(path)
266+
}
267+
268+
verifyResult(t, scm, err, shouldLoad, isValid)
269+
}
270+
271+
func validateData(t *testing.T, scm *schema.Schema, path string, shouldLoad, isValid bool) {
272+
data, err := ioutil.ReadFile(path)
273+
require.NoError(t, err)
274+
275+
if scm != nil {
276+
err = scm.ValidateData(data)
277+
} else {
278+
err = schema.ValidateData(data)
279+
}
280+
281+
verifyResult(t, scm, err, shouldLoad, isValid)
282+
}
283+
284+
func readAndValidate(t *testing.T, scm *schema.Schema, path string, shouldLoad, isValid bool) {
285+
var (
286+
data []byte
287+
)
288+
289+
f, err := os.Open(path)
290+
defer f.Close()
291+
require.NoError(t, err)
292+
293+
if scm != nil {
294+
data, err = scm.ReadAndValidate(f)
295+
} else {
296+
data, err = schema.ReadAndValidate(f)
297+
}
298+
299+
verifyResult(t, scm, err, shouldLoad, isValid)
300+
301+
if scm != nil {
302+
err = scm.Validate(bytes.NewReader(data))
303+
} else {
304+
err = schema.Validate(bytes.NewReader(data))
305+
}
306+
307+
verifyResult(t, scm, err, shouldLoad, isValid)
308+
}
309+
310+
func validateRead(t *testing.T, scm *schema.Schema, path string, shouldLoad, isValid bool) {
311+
f, err := os.Open(path)
312+
defer f.Close()
313+
require.NoError(t, err)
314+
315+
buf := &bytes.Buffer{}
316+
r := io.TeeReader(f, buf)
317+
318+
if scm != nil {
319+
err = scm.Validate(r)
320+
} else {
321+
err = schema.Validate(r)
322+
}
323+
324+
verifyResult(t, scm, err, shouldLoad, isValid)
325+
326+
if scm != nil {
327+
err = scm.Validate(bytes.NewReader(buf.Bytes()))
328+
} else {
329+
err = schema.Validate(bytes.NewReader(buf.Bytes()))
330+
}
331+
332+
verifyResult(t, scm, err, shouldLoad, isValid)
333+
}
334+
335+
func validateSpec(t *testing.T, scm *schema.Schema, path string, shouldLoad, isValid bool) {
336+
var old *schema.Schema
337+
338+
if scm != nil {
339+
old = schema.Get()
340+
schema.Set(scm)
341+
}
342+
spec, err := cdi.ReadSpec(path, 0)
343+
if scm != nil {
344+
schema.Set(old)
345+
}
346+
347+
if !shouldLoad || !isValid {
348+
require.Error(t, err)
349+
} else {
350+
require.NoError(t, err)
351+
require.NotNil(t, spec)
352+
}
353+
}
354+
355+
func loadSchema(t *testing.T, name string) *schema.Schema {
356+
if name == schema.NoneSchemaName {
357+
return none
358+
}
359+
360+
scm, err := schema.Load(name)
361+
require.NoError(t, err)
362+
require.NotNil(t, scm)
363+
return scm
364+
}
365+
366+
func verifyResult(t *testing.T, s *schema.Schema, err error, shouldLoad, isValid bool) {
367+
if s == none || (s == nil && schema.Get() == none) {
368+
require.NoError(t, err)
369+
return
370+
}
371+
372+
if !isValid || !shouldLoad {
373+
require.Error(t, err)
374+
} else {
375+
require.NoError(t, err)
376+
}
377+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{}

0 commit comments

Comments
 (0)