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  }