1 package spec3
2
3 import (
4 "encoding/json"
5 "fmt"
6 "io"
7 "os"
8 "reflect"
9 "testing"
10
11 "github.com/google/go-cmp/cmp"
12 fuzz "github.com/google/gofuzz"
13 "k8s.io/kube-openapi/pkg/internal"
14 jsontesting "k8s.io/kube-openapi/pkg/util/jsontesting"
15 "k8s.io/kube-openapi/pkg/validation/spec"
16 )
17
18
19
20 var swaggerDiffOptions = []cmp.Option{cmp.Comparer(func(a spec.Ref, b spec.Ref) bool {
21 return a.String() == b.String()
22 })}
23
24 func TestOpenAPIV3RoundTrip(t *testing.T) {
25 var fuzzer *fuzz.Fuzzer
26 fuzzer = fuzz.NewWithSeed(1646791953)
27
28 fuzzer.MaxDepth(22).NilChance(0.5).NumElements(1, 7)
29 fuzzer.Funcs(OpenAPIV3FuzzFuncs...)
30 expected := &OpenAPI{}
31 fuzzer.Fuzz(expected)
32
33 j, err := json.Marshal(expected)
34 if err != nil {
35 t.Fatal(err)
36 }
37 var actual *OpenAPI
38 err = json.Unmarshal(j, &actual)
39 if err != nil {
40 t.Fatal(err)
41 }
42 if !reflect.DeepEqual(expected, actual) {
43 t.Fatal(cmp.Diff(expected, actual, swaggerDiffOptions...))
44 }
45 }
46
47 func TestOpenAPIV3Deserialize(t *testing.T) {
48 swagFile, err := os.Open("./testdata/appsv1spec.json")
49 if err != nil {
50 t.Fatal(err)
51 }
52 defer swagFile.Close()
53 originalJSON, err := io.ReadAll(swagFile)
54 if err != nil {
55 t.Fatal(err)
56 }
57 internal.UseOptimizedJSONUnmarshalingV3 = false
58
59 var result1 *OpenAPI
60
61 if err := json.Unmarshal(originalJSON, &result1); err != nil {
62 t.Fatal(err)
63 }
64 internal.UseOptimizedJSONUnmarshalingV3 = true
65 var result2 *OpenAPI
66 if err := json.Unmarshal(originalJSON, &result2); err != nil {
67 t.Fatal(err)
68 }
69
70 if !reflect.DeepEqual(result1, result2) {
71 t.Fatal(cmp.Diff(result1, result2, swaggerDiffOptions...))
72 }
73 }
74
75 func TestOpenAPIV3Serialize(t *testing.T) {
76 swagFile, err := os.Open("./testdata/appsv1spec.json")
77 if err != nil {
78 t.Fatal(err)
79 }
80 defer swagFile.Close()
81 originalJSON, err := io.ReadAll(swagFile)
82 if err != nil {
83 t.Fatal(err)
84 }
85 var openapi *OpenAPI
86 if err := json.Unmarshal(originalJSON, &openapi); err != nil {
87 t.Fatal(err)
88 }
89
90 internal.UseOptimizedJSONUnmarshalingV3 = false
91 want, err := json.Marshal(openapi)
92 if err != nil {
93 t.Fatal(err)
94 }
95 internal.UseOptimizedJSONUnmarshalingV3 = true
96 got, err := openapi.MarshalJSON()
97 if err != nil {
98 t.Fatal(err)
99 }
100 if err := jsontesting.JsonCompare(want, got); err != nil {
101 t.Errorf("marshal doesn't match: %v", err)
102 }
103 }
104
105 func TestOpenAPIV3SerializeFuzzed(t *testing.T) {
106 var fuzzer *fuzz.Fuzzer
107 fuzzer = fuzz.NewWithSeed(1646791953)
108 fuzzer.MaxDepth(13).NilChance(0.075).NumElements(1, 2)
109 fuzzer.Funcs(OpenAPIV3FuzzFuncs...)
110
111 for i := 0; i < 100; i++ {
112 openapi := &OpenAPI{}
113 fuzzer.Fuzz(openapi)
114
115 internal.UseOptimizedJSONUnmarshalingV3 = false
116 want, err := json.Marshal(openapi)
117 if err != nil {
118 t.Fatal(err)
119 }
120 internal.UseOptimizedJSONUnmarshalingV3 = true
121 got, err := openapi.MarshalJSON()
122 if err != nil {
123 t.Fatal(err)
124 }
125 if err := jsontesting.JsonCompare(want, got); err != nil {
126 t.Errorf("fuzzed marshal doesn't match: %v", err)
127 }
128 }
129 }
130
131 func TestOpenAPIV3SerializeStable(t *testing.T) {
132 swagFile, err := os.Open("./testdata/appsv1spec.json")
133 if err != nil {
134 t.Fatal(err)
135 }
136 defer swagFile.Close()
137 originalJSON, err := io.ReadAll(swagFile)
138 if err != nil {
139 t.Fatal(err)
140 }
141 var openapi *OpenAPI
142 if err := json.Unmarshal(originalJSON, &openapi); err != nil {
143 t.Fatal(err)
144 }
145
146 internal.UseOptimizedJSONUnmarshalingV3 = true
147 for i := 0; i < 5; i++ {
148 t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
149 want, err := openapi.MarshalJSON()
150 if err != nil {
151 t.Fatal(err)
152 }
153 got, err := openapi.MarshalJSON()
154 if err != nil {
155 t.Fatal(err)
156 }
157 if err := jsontesting.JsonCompare(want, got); err != nil {
158 t.Errorf("marshal doesn't match: %v", err)
159 }
160 })
161 }
162 }
163
164 func BenchmarkOpenAPIV3Deserialize(b *testing.B) {
165 benchcases := []struct {
166 file string
167 }{
168 {
169 file: "appsv1spec.json",
170 },
171 {
172 file: "authorizationv1spec.json",
173 },
174 }
175 for _, bc := range benchcases {
176 swagFile, err := os.Open("./testdata/" + bc.file)
177 if err != nil {
178 b.Fatal(err)
179 }
180 defer swagFile.Close()
181 originalJSON, err := io.ReadAll(swagFile)
182 if err != nil {
183 b.Fatal(err)
184 }
185 b.ResetTimer()
186 b.Run(fmt.Sprintf("%s jsonv1", bc.file), func(b2 *testing.B) {
187 b2.ReportAllocs()
188 internal.UseOptimizedJSONUnmarshaling = false
189 internal.UseOptimizedJSONUnmarshalingV3 = false
190 for i := 0; i < b2.N; i++ {
191 var result *OpenAPI
192 if err := json.Unmarshal(originalJSON, &result); err != nil {
193 b2.Fatal(err)
194 }
195 }
196 })
197
198 b.Run(fmt.Sprintf("%s jsonv2 via jsonv1 schema only", bc.file), func(b2 *testing.B) {
199 b2.ReportAllocs()
200 internal.UseOptimizedJSONUnmarshaling = true
201 internal.UseOptimizedJSONUnmarshalingV3 = false
202 for i := 0; i < b2.N; i++ {
203 var result *OpenAPI
204 if err := json.Unmarshal(originalJSON, &result); err != nil {
205 b2.Fatal(err)
206 }
207 }
208 })
209
210 b.Run(fmt.Sprintf("%s jsonv2 via jsonv1 full spec", bc.file), func(b2 *testing.B) {
211 b2.ReportAllocs()
212 internal.UseOptimizedJSONUnmarshaling = true
213 internal.UseOptimizedJSONUnmarshalingV3 = true
214 for i := 0; i < b2.N; i++ {
215 var result *OpenAPI
216 if err := json.Unmarshal(originalJSON, &result); err != nil {
217 b2.Fatal(err)
218 }
219 }
220 })
221
222 b.Run("jsonv2", func(b2 *testing.B) {
223 b2.ReportAllocs()
224 internal.UseOptimizedJSONUnmarshaling = true
225 internal.UseOptimizedJSONUnmarshalingV3 = true
226 for i := 0; i < b2.N; i++ {
227 var result *OpenAPI
228 if err := result.UnmarshalJSON(originalJSON); err != nil {
229 b2.Fatal(err)
230 }
231 }
232 })
233 }
234 }
235
236 func BenchmarkOpenAPIV3Serialize(b *testing.B) {
237 benchcases := []struct {
238 file string
239 }{
240 {
241 file: "appsv1spec.json",
242 },
243 {
244 file: "authorizationv1spec.json",
245 },
246 }
247 for _, bc := range benchcases {
248 swagFile, err := os.Open("./testdata/" + bc.file)
249 if err != nil {
250 b.Fatal(err)
251 }
252 defer swagFile.Close()
253 originalJSON, err := io.ReadAll(swagFile)
254 if err != nil {
255 b.Fatal(err)
256 }
257 var openapi *OpenAPI
258 if err := json.Unmarshal(originalJSON, &openapi); err != nil {
259 b.Fatal(err)
260 }
261 b.ResetTimer()
262 b.Run(fmt.Sprintf("%s jsonv1", bc.file), func(b2 *testing.B) {
263 b2.ReportAllocs()
264 internal.UseOptimizedJSONMarshalingV3 = false
265 for i := 0; i < b2.N; i++ {
266 if _, err := json.Marshal(openapi); err != nil {
267 b2.Fatal(err)
268 }
269 }
270 })
271
272 b.Run(fmt.Sprintf("%s jsonv2 via jsonv1 full spec", bc.file), func(b2 *testing.B) {
273 b2.ReportAllocs()
274 internal.UseOptimizedJSONMarshalingV3 = true
275 for i := 0; i < b2.N; i++ {
276 if _, err := json.Marshal(openapi); err != nil {
277 b2.Fatal(err)
278 }
279 }
280 })
281
282 b.Run("jsonv2", func(b2 *testing.B) {
283 b2.ReportAllocs()
284 internal.UseOptimizedJSONMarshalingV3 = true
285 for i := 0; i < b2.N; i++ {
286 if _, err := openapi.MarshalJSON(); err != nil {
287 b2.Fatal(err)
288 }
289 }
290 })
291 }
292 }
293
View as plain text