k8s.io/kube-openapi@v0.0.0-20240228011516-70dd3763d340/pkg/spec3/benchmark_serialization_test.go (about) 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 // cmp.Diff panics when reflecting unexported fields under jsonreference.Ref 19 // a custom comparator is required 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 // Make sure we have enough depth such that maps do not yield nil elements 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 }