k8s.io/kubernetes@v1.29.3/pkg/api/testing/serialization_test.go (about)

     1  /*
     2  Copyright 2014 The Kubernetes 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 testing
    18  
    19  import (
    20  	"bytes"
    21  	"encoding/hex"
    22  	gojson "encoding/json"
    23  	"io"
    24  	"math/rand"
    25  	"reflect"
    26  	"testing"
    27  
    28  	"github.com/google/go-cmp/cmp"
    29  
    30  	appsv1 "k8s.io/api/apps/v1"
    31  	v1 "k8s.io/api/core/v1"
    32  	"k8s.io/apimachinery/pkg/api/apitesting/fuzzer"
    33  	"k8s.io/apimachinery/pkg/api/apitesting/roundtrip"
    34  	apiequality "k8s.io/apimachinery/pkg/api/equality"
    35  	"k8s.io/apimachinery/pkg/api/meta"
    36  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    37  	"k8s.io/apimachinery/pkg/conversion"
    38  	"k8s.io/apimachinery/pkg/runtime"
    39  	"k8s.io/apimachinery/pkg/runtime/schema"
    40  	"k8s.io/apimachinery/pkg/runtime/serializer/streaming"
    41  	"k8s.io/apimachinery/pkg/util/sets"
    42  	"k8s.io/apimachinery/pkg/watch"
    43  	"k8s.io/kubernetes/pkg/api/legacyscheme"
    44  	"k8s.io/kubernetes/pkg/apis/apps"
    45  	k8s_apps_v1 "k8s.io/kubernetes/pkg/apis/apps/v1"
    46  	api "k8s.io/kubernetes/pkg/apis/core"
    47  	k8s_api_v1 "k8s.io/kubernetes/pkg/apis/core/v1"
    48  	"sigs.k8s.io/yaml"
    49  )
    50  
    51  // fuzzInternalObject fuzzes an arbitrary runtime object using the appropriate
    52  // fuzzer registered with the apitesting package.
    53  func fuzzInternalObject(t *testing.T, forVersion schema.GroupVersion, item runtime.Object, seed int64) runtime.Object {
    54  	fuzzer.FuzzerFor(FuzzerFuncs, rand.NewSource(seed), legacyscheme.Codecs).Fuzz(item)
    55  
    56  	j, err := meta.TypeAccessor(item)
    57  	if err != nil {
    58  		t.Fatalf("Unexpected error %v for %#v", err, item)
    59  	}
    60  	j.SetKind("")
    61  	j.SetAPIVersion("")
    62  
    63  	return item
    64  }
    65  
    66  func ConvertV1ReplicaSetToAPIReplicationController(in *appsv1.ReplicaSet, out *api.ReplicationController, s conversion.Scope) error {
    67  	intermediate1 := &apps.ReplicaSet{}
    68  	if err := k8s_apps_v1.Convert_v1_ReplicaSet_To_apps_ReplicaSet(in, intermediate1, s); err != nil {
    69  		return err
    70  	}
    71  
    72  	intermediate2 := &v1.ReplicationController{}
    73  	if err := k8s_api_v1.Convert_apps_ReplicaSet_To_v1_ReplicationController(intermediate1, intermediate2, s); err != nil {
    74  		return err
    75  	}
    76  
    77  	return k8s_api_v1.Convert_v1_ReplicationController_To_core_ReplicationController(intermediate2, out, s)
    78  }
    79  
    80  func TestSetControllerConversion(t *testing.T) {
    81  	s := legacyscheme.Scheme
    82  	if err := s.AddConversionFunc((*appsv1.ReplicaSet)(nil), (*api.ReplicationController)(nil), func(a, b interface{}, scope conversion.Scope) error {
    83  		return ConvertV1ReplicaSetToAPIReplicationController(a.(*appsv1.ReplicaSet), b.(*api.ReplicationController), scope)
    84  	}); err != nil {
    85  		t.Fatal(err)
    86  	}
    87  
    88  	rs := &apps.ReplicaSet{}
    89  	rc := &api.ReplicationController{}
    90  	extGroup := schema.GroupVersion{Group: "apps", Version: "v1"}
    91  	extCodec := legacyscheme.Codecs.LegacyCodec(extGroup)
    92  
    93  	defaultGroup := schema.GroupVersion{Group: "", Version: "v1"}
    94  	defaultCodec := legacyscheme.Codecs.LegacyCodec(defaultGroup)
    95  
    96  	fuzzInternalObject(t, schema.GroupVersion{Group: "apps", Version: runtime.APIVersionInternal}, rs, rand.Int63())
    97  
    98  	// explicitly set the selector to something that is convertible to old-style selectors
    99  	// (since normally we'll fuzz the selectors with things that aren't convertible)
   100  	rs.Spec.Selector = &metav1.LabelSelector{
   101  		MatchLabels: map[string]string{
   102  			"foo": "bar",
   103  			"baz": "quux",
   104  		},
   105  	}
   106  
   107  	t.Logf("rs._internal.apps -> rs.v1.apps")
   108  	data, err := runtime.Encode(extCodec, rs)
   109  	if err != nil {
   110  		t.Fatalf("unexpected encoding error: %v", err)
   111  	}
   112  
   113  	decoder := legacyscheme.Codecs.DecoderToVersion(
   114  		legacyscheme.Codecs.UniversalDeserializer(),
   115  		runtime.NewMultiGroupVersioner(
   116  			defaultGroup,
   117  			schema.GroupKind{Group: defaultGroup.Group},
   118  			schema.GroupKind{Group: extGroup.Group},
   119  		),
   120  	)
   121  
   122  	t.Logf("rs.v1.apps -> rc._internal")
   123  	if err := runtime.DecodeInto(decoder, data, rc); err != nil {
   124  		t.Fatalf("unexpected decoding error: %v", err)
   125  	}
   126  
   127  	t.Logf("rc._internal -> rc.v1")
   128  	data, err = runtime.Encode(defaultCodec, rc)
   129  	if err != nil {
   130  		t.Fatalf("unexpected encoding error: %v", err)
   131  	}
   132  
   133  	t.Logf("rc.v1 -> rs._internal.apps")
   134  	if err := runtime.DecodeInto(decoder, data, rs); err != nil {
   135  		t.Fatalf("unexpected decoding error: %v", err)
   136  	}
   137  }
   138  
   139  // TestSpecificKind round-trips a single specific kind and is intended to help
   140  // debug issues that arise while adding a new API type.
   141  func TestSpecificKind(t *testing.T) {
   142  	// Uncomment the following line to enable logging of which conversions
   143  	// legacyscheme.Scheme.Log(t)
   144  	internalGVK := schema.GroupVersionKind{Group: "apps", Version: runtime.APIVersionInternal, Kind: "DaemonSet"}
   145  
   146  	seed := rand.Int63()
   147  	fuzzer := fuzzer.FuzzerFor(FuzzerFuncs, rand.NewSource(seed), legacyscheme.Codecs)
   148  
   149  	roundtrip.RoundTripSpecificKind(t, internalGVK, legacyscheme.Scheme, legacyscheme.Codecs, fuzzer, nil)
   150  }
   151  
   152  var nonRoundTrippableTypes = sets.NewString(
   153  	"ExportOptions",
   154  	"GetOptions",
   155  	// WatchEvent does not include kind and version and can only be deserialized
   156  	// implicitly (if the caller expects the specific object). The watch call defines
   157  	// the schema by content type, rather than via kind/version included in each
   158  	// object.
   159  	"WatchEvent",
   160  	// ListOptions is now part of the meta group
   161  	"ListOptions",
   162  	// DeleteOptions, CreateOptions and UpdateOptions are only read in metav1
   163  	"DeleteOptions",
   164  	"CreateOptions",
   165  	"UpdateOptions",
   166  	"PatchOptions",
   167  )
   168  
   169  var commonKinds = []string{"Status", "ListOptions", "DeleteOptions", "GetOptions", "CreateOptions", "UpdateOptions", "PatchOptions"}
   170  
   171  // TestCommonKindsRegistered verifies that all group/versions registered with
   172  // the legacyscheme package have the common kinds.
   173  func TestCommonKindsRegistered(t *testing.T) {
   174  	gvs := map[schema.GroupVersion]bool{}
   175  	for gvk := range legacyscheme.Scheme.AllKnownTypes() {
   176  		if gvk.Version == runtime.APIVersionInternal {
   177  			continue
   178  		}
   179  		gvs[gvk.GroupVersion()] = true
   180  	}
   181  
   182  	for _, kind := range commonKinds {
   183  		for gv := range gvs {
   184  			gvk := gv.WithKind(kind)
   185  			obj, err := legacyscheme.Scheme.New(gvk)
   186  			if err != nil {
   187  				t.Error(err)
   188  			}
   189  			defaults := gv.WithKind("")
   190  			var got *schema.GroupVersionKind
   191  			if obj, got, err = legacyscheme.Codecs.LegacyCodec().Decode([]byte(`{"kind":"`+kind+`"}`), &defaults, obj); err != nil || gvk != *got {
   192  				t.Errorf("expected %v: %v %v", gvk, got, err)
   193  			}
   194  			data, err := runtime.Encode(legacyscheme.Codecs.LegacyCodec(gv), obj)
   195  			if err != nil {
   196  				t.Errorf("expected %v: %v\n%s", gvk, err, string(data))
   197  				continue
   198  			}
   199  			if !bytes.Contains(data, []byte(`"kind":"`+kind+`","apiVersion":"`+gv.String()+`"`)) {
   200  				if kind != "Status" {
   201  					t.Errorf("expected %v: %v\n%s", gvk, err, string(data))
   202  					continue
   203  				}
   204  				// TODO: this is wrong, but legacy clients expect it
   205  				if !bytes.Contains(data, []byte(`"kind":"`+kind+`","apiVersion":"v1"`)) {
   206  					t.Errorf("expected %v: %v\n%s", gvk, err, string(data))
   207  					continue
   208  				}
   209  			}
   210  		}
   211  	}
   212  }
   213  
   214  // TestRoundTripTypes applies the round-trip test to all round-trippable Kinds
   215  // in all of the API groups registered for test in the legacyscheme package.
   216  func TestRoundTripTypes(t *testing.T) {
   217  	seed := rand.Int63()
   218  	fuzzer := fuzzer.FuzzerFor(FuzzerFuncs, rand.NewSource(seed), legacyscheme.Codecs)
   219  	nonRoundTrippableTypes := map[schema.GroupVersionKind]bool{}
   220  
   221  	roundtrip.RoundTripTypes(t, legacyscheme.Scheme, legacyscheme.Codecs, fuzzer, nonRoundTrippableTypes)
   222  }
   223  
   224  // TestEncodePtr tests that a pointer to a golang type can be encoded and
   225  // decoded without information loss or mutation.
   226  func TestEncodePtr(t *testing.T) {
   227  	grace := int64(30)
   228  	enableServiceLinks := v1.DefaultEnableServiceLinks
   229  	preemptNever := api.PreemptNever
   230  	pod := &api.Pod{
   231  		ObjectMeta: metav1.ObjectMeta{
   232  			Labels: map[string]string{"name": "foo"},
   233  		},
   234  		Spec: api.PodSpec{
   235  			RestartPolicy: api.RestartPolicyAlways,
   236  			DNSPolicy:     api.DNSClusterFirst,
   237  
   238  			TerminationGracePeriodSeconds: &grace,
   239  
   240  			SecurityContext:    &api.PodSecurityContext{},
   241  			SchedulerName:      v1.DefaultSchedulerName,
   242  			EnableServiceLinks: &enableServiceLinks,
   243  			PreemptionPolicy:   &preemptNever,
   244  		},
   245  	}
   246  	obj := runtime.Object(pod)
   247  	data, err := runtime.Encode(legacyscheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), obj)
   248  	obj2, err2 := runtime.Decode(legacyscheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), data)
   249  	if err != nil || err2 != nil {
   250  		t.Fatalf("Failure: '%v' '%v'", err, err2)
   251  	}
   252  	if _, ok := obj2.(*api.Pod); !ok {
   253  		t.Fatalf("Got wrong type")
   254  	}
   255  	if !apiequality.Semantic.DeepEqual(obj2, pod) {
   256  		t.Errorf("\nExpected:\n\n %#v,\n\nGot:\n\n %#vDiff: %v\n\n", pod, obj2, cmp.Diff(obj2, pod))
   257  	}
   258  }
   259  
   260  func TestDecodeTimeStampWithoutQuotes(t *testing.T) {
   261  	testYAML := []byte(`
   262  apiVersion: v1
   263  kind: Pod
   264  metadata:
   265    creationTimestamp: 2018-08-30T14:10:58Z
   266    name: test
   267  spec:
   268    containers: null
   269  status: {}`)
   270  	if obj, err := runtime.Decode(legacyscheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), testYAML); err != nil {
   271  		t.Fatalf("unable to decode yaml: %v", err)
   272  	} else {
   273  		if obj2, ok := obj.(*api.Pod); !ok {
   274  			t.Fatalf("Got wrong type")
   275  		} else {
   276  			if obj2.ObjectMeta.CreationTimestamp.UnixNano() != parseTimeOrDie("2018-08-30T14:10:58Z").UnixNano() {
   277  				t.Fatalf("Time stamps do not match")
   278  			}
   279  		}
   280  	}
   281  }
   282  
   283  // TestBadJSONRejection establishes that a JSON object without a kind or with
   284  // an unknown kind will not be decoded without error.
   285  func TestBadJSONRejection(t *testing.T) {
   286  	badJSONMissingKind := []byte(`{ }`)
   287  	if _, err := runtime.Decode(legacyscheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), badJSONMissingKind); err == nil {
   288  		t.Errorf("Did not reject despite lack of kind field: %s", badJSONMissingKind)
   289  	}
   290  	badJSONUnknownType := []byte(`{"kind": "bar"}`)
   291  	if _, err1 := runtime.Decode(legacyscheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), badJSONUnknownType); err1 == nil {
   292  		t.Errorf("Did not reject despite use of unknown type: %s", badJSONUnknownType)
   293  	}
   294  }
   295  
   296  // TestUnversionedTypes establishes that the default codec can encode and
   297  // decode unversioned objects.
   298  func TestUnversionedTypes(t *testing.T) {
   299  	testcases := []runtime.Object{
   300  		&metav1.Status{Status: "Failure", Message: "something went wrong"},
   301  		&metav1.APIVersions{Versions: []string{"A", "B", "C"}},
   302  		&metav1.APIGroupList{Groups: []metav1.APIGroup{{Name: "mygroup"}}},
   303  		&metav1.APIGroup{Name: "mygroup"},
   304  		&metav1.APIResourceList{GroupVersion: "mygroup/myversion"},
   305  	}
   306  
   307  	for _, obj := range testcases {
   308  		// Make sure the unversioned codec can encode
   309  		unversionedJSON, err := runtime.Encode(legacyscheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), obj)
   310  		if err != nil {
   311  			t.Errorf("%v: unexpected error: %v", obj, err)
   312  			continue
   313  		}
   314  
   315  		// Make sure the versioned codec under test can decode
   316  		versionDecodedObject, err := runtime.Decode(legacyscheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), unversionedJSON)
   317  		if err != nil {
   318  			t.Errorf("%v: unexpected error: %v", obj, err)
   319  			continue
   320  		}
   321  		// Make sure it decodes correctly
   322  		if !reflect.DeepEqual(obj, versionDecodedObject) {
   323  			t.Errorf("%v: expected %#v, got %#v", obj, obj, versionDecodedObject)
   324  			continue
   325  		}
   326  	}
   327  }
   328  
   329  // TestObjectWatchFraming establishes that a watch event can be encoded and
   330  // decoded correctly through each of the supported RFC2046 media types.
   331  func TestObjectWatchFraming(t *testing.T) {
   332  	f := fuzzer.FuzzerFor(FuzzerFuncs, rand.NewSource(benchmarkSeed), legacyscheme.Codecs)
   333  	secret := &api.Secret{}
   334  	f.Fuzz(secret)
   335  	if secret.Data == nil {
   336  		secret.Data = map[string][]byte{}
   337  	}
   338  	secret.Data["binary"] = []byte{0x00, 0x10, 0x30, 0x55, 0xff, 0x00}
   339  	secret.Data["utf8"] = []byte("a string with \u0345 characters")
   340  	secret.Data["long"] = bytes.Repeat([]byte{0x01, 0x02, 0x03, 0x00}, 1000)
   341  	converted, _ := legacyscheme.Scheme.ConvertToVersion(secret, v1.SchemeGroupVersion)
   342  	v1secret := converted.(*v1.Secret)
   343  	for _, info := range legacyscheme.Codecs.SupportedMediaTypes() {
   344  		if info.StreamSerializer == nil {
   345  			continue
   346  		}
   347  		s := info.StreamSerializer
   348  		framer := s.Framer
   349  		embedded := info.Serializer
   350  		if embedded == nil {
   351  			t.Errorf("no embedded serializer for %s", info.MediaType)
   352  			continue
   353  		}
   354  		innerDecode := legacyscheme.Codecs.DecoderToVersion(embedded, api.SchemeGroupVersion)
   355  
   356  		// write a single object through the framer and back out
   357  		obj := &bytes.Buffer{}
   358  		if err := s.Encode(v1secret, obj); err != nil {
   359  			t.Fatal(err)
   360  		}
   361  		out := &bytes.Buffer{}
   362  		w := framer.NewFrameWriter(out)
   363  		if n, err := w.Write(obj.Bytes()); err != nil || n != len(obj.Bytes()) {
   364  			t.Fatal(err)
   365  		}
   366  		sr := streaming.NewDecoder(framer.NewFrameReader(io.NopCloser(out)), s)
   367  		resultSecret := &v1.Secret{}
   368  		res, _, err := sr.Decode(nil, resultSecret)
   369  		if err != nil {
   370  			t.Fatalf("%v:\n%s", err, hex.Dump(obj.Bytes()))
   371  		}
   372  		resultSecret.Kind = "Secret"
   373  		resultSecret.APIVersion = "v1"
   374  		if !apiequality.Semantic.DeepEqual(v1secret, res) {
   375  			t.Fatalf("objects did not match: %s", cmp.Diff(v1secret, res))
   376  		}
   377  
   378  		// write a watch event through the frame writer and read it back in
   379  		// via the frame reader for this media type
   380  		obj = &bytes.Buffer{}
   381  		if err := embedded.Encode(v1secret, obj); err != nil {
   382  			t.Fatal(err)
   383  		}
   384  		event := &metav1.WatchEvent{Type: string(watch.Added)}
   385  		event.Object.Raw = obj.Bytes()
   386  		obj = &bytes.Buffer{}
   387  		if err := s.Encode(event, obj); err != nil {
   388  			t.Fatal(err)
   389  		}
   390  		out = &bytes.Buffer{}
   391  		w = framer.NewFrameWriter(out)
   392  		if n, err := w.Write(obj.Bytes()); err != nil || n != len(obj.Bytes()) {
   393  			t.Fatal(err)
   394  		}
   395  		sr = streaming.NewDecoder(framer.NewFrameReader(io.NopCloser(out)), s)
   396  		outEvent := &metav1.WatchEvent{}
   397  		_, _, err = sr.Decode(nil, outEvent)
   398  		if err != nil || outEvent.Type != string(watch.Added) {
   399  			t.Fatalf("%v: %#v", err, outEvent)
   400  		}
   401  		if outEvent.Object.Object == nil && outEvent.Object.Raw != nil {
   402  			outEvent.Object.Object, err = runtime.Decode(innerDecode, outEvent.Object.Raw)
   403  			if err != nil {
   404  				t.Fatalf("%v:\n%s", err, hex.Dump(outEvent.Object.Raw))
   405  			}
   406  		}
   407  
   408  		if !apiequality.Semantic.DeepEqual(secret, outEvent.Object.Object) {
   409  			t.Fatalf("%s: did not match after frame decoding: %s", info.MediaType, cmp.Diff(secret, outEvent.Object.Object))
   410  		}
   411  	}
   412  }
   413  
   414  const benchmarkSeed = 100
   415  
   416  func benchmarkItems(b *testing.B) []v1.Pod {
   417  	apiObjectFuzzer := fuzzer.FuzzerFor(FuzzerFuncs, rand.NewSource(benchmarkSeed), legacyscheme.Codecs)
   418  	items := make([]v1.Pod, 10)
   419  	for i := range items {
   420  		var pod api.Pod
   421  		apiObjectFuzzer.Fuzz(&pod)
   422  		pod.Spec.InitContainers, pod.Status.InitContainerStatuses = nil, nil
   423  		out, err := legacyscheme.Scheme.ConvertToVersion(&pod, v1.SchemeGroupVersion)
   424  		if err != nil {
   425  			panic(err)
   426  		}
   427  		items[i] = *out.(*v1.Pod)
   428  	}
   429  	return items
   430  }
   431  
   432  func benchmarkItemsList(b *testing.B, numItems int) v1.PodList {
   433  	apiObjectFuzzer := fuzzer.FuzzerFor(FuzzerFuncs, rand.NewSource(benchmarkSeed), legacyscheme.Codecs)
   434  	items := make([]v1.Pod, numItems)
   435  	for i := range items {
   436  		var pod api.Pod
   437  		apiObjectFuzzer.Fuzz(&pod)
   438  		pod.Spec.InitContainers, pod.Status.InitContainerStatuses = nil, nil
   439  		out, err := legacyscheme.Scheme.ConvertToVersion(&pod, v1.SchemeGroupVersion)
   440  		if err != nil {
   441  			panic(err)
   442  		}
   443  		items[i] = *out.(*v1.Pod)
   444  	}
   445  
   446  	return v1.PodList{
   447  		Items: items,
   448  	}
   449  }
   450  
   451  // BenchmarkEncodeCodec measures the cost of performing a codec encode, which includes
   452  // reflection (to clear APIVersion and Kind)
   453  func BenchmarkEncodeCodec(b *testing.B) {
   454  	items := benchmarkItems(b)
   455  	width := len(items)
   456  	b.ResetTimer()
   457  	for i := 0; i < b.N; i++ {
   458  		if _, err := runtime.Encode(legacyscheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), &items[i%width]); err != nil {
   459  			b.Fatal(err)
   460  		}
   461  	}
   462  	b.StopTimer()
   463  }
   464  
   465  // BenchmarkEncodeCodecFromInternal measures the cost of performing a codec encode,
   466  // including conversions.
   467  func BenchmarkEncodeCodecFromInternal(b *testing.B) {
   468  	items := benchmarkItems(b)
   469  	width := len(items)
   470  	encodable := make([]api.Pod, width)
   471  	for i := range items {
   472  		if err := legacyscheme.Scheme.Convert(&items[i], &encodable[i], nil); err != nil {
   473  			b.Fatal(err)
   474  		}
   475  	}
   476  	b.ResetTimer()
   477  	for i := 0; i < b.N; i++ {
   478  		if _, err := runtime.Encode(legacyscheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), &encodable[i%width]); err != nil {
   479  			b.Fatal(err)
   480  		}
   481  	}
   482  	b.StopTimer()
   483  }
   484  
   485  // BenchmarkEncodeJSONMarshal provides a baseline for regular JSON encode performance
   486  func BenchmarkEncodeJSONMarshal(b *testing.B) {
   487  	items := benchmarkItems(b)
   488  	width := len(items)
   489  	b.ResetTimer()
   490  	for i := 0; i < b.N; i++ {
   491  		if _, err := gojson.Marshal(&items[i%width]); err != nil {
   492  			b.Fatal(err)
   493  		}
   494  	}
   495  	b.StopTimer()
   496  }
   497  
   498  func BenchmarkDecodeCodec(b *testing.B) {
   499  	codec := legacyscheme.Codecs.LegacyCodec(v1.SchemeGroupVersion)
   500  	items := benchmarkItems(b)
   501  	width := len(items)
   502  	encoded := make([][]byte, width)
   503  	for i := range items {
   504  		data, err := runtime.Encode(codec, &items[i])
   505  		if err != nil {
   506  			b.Fatal(err)
   507  		}
   508  		encoded[i] = data
   509  	}
   510  
   511  	b.ResetTimer()
   512  	for i := 0; i < b.N; i++ {
   513  		if _, err := runtime.Decode(codec, encoded[i%width]); err != nil {
   514  			b.Fatal(err)
   515  		}
   516  	}
   517  	b.StopTimer()
   518  }
   519  
   520  func BenchmarkDecodeIntoExternalCodec(b *testing.B) {
   521  	codec := legacyscheme.Codecs.LegacyCodec(v1.SchemeGroupVersion)
   522  	items := benchmarkItems(b)
   523  	width := len(items)
   524  	encoded := make([][]byte, width)
   525  	for i := range items {
   526  		data, err := runtime.Encode(codec, &items[i])
   527  		if err != nil {
   528  			b.Fatal(err)
   529  		}
   530  		encoded[i] = data
   531  	}
   532  
   533  	b.ResetTimer()
   534  	for i := 0; i < b.N; i++ {
   535  		obj := v1.Pod{}
   536  		if err := runtime.DecodeInto(codec, encoded[i%width], &obj); err != nil {
   537  			b.Fatal(err)
   538  		}
   539  	}
   540  	b.StopTimer()
   541  }
   542  
   543  func BenchmarkDecodeIntoInternalCodec(b *testing.B) {
   544  	codec := legacyscheme.Codecs.LegacyCodec(v1.SchemeGroupVersion)
   545  	items := benchmarkItems(b)
   546  	width := len(items)
   547  	encoded := make([][]byte, width)
   548  	for i := range items {
   549  		data, err := runtime.Encode(codec, &items[i])
   550  		if err != nil {
   551  			b.Fatal(err)
   552  		}
   553  		encoded[i] = data
   554  	}
   555  
   556  	b.ResetTimer()
   557  	for i := 0; i < b.N; i++ {
   558  		obj := api.Pod{}
   559  		if err := runtime.DecodeInto(codec, encoded[i%width], &obj); err != nil {
   560  			b.Fatal(err)
   561  		}
   562  	}
   563  	b.StopTimer()
   564  }
   565  
   566  // BenchmarkDecodeJSON provides a baseline for regular JSON decode performance
   567  func BenchmarkDecodeIntoJSON(b *testing.B) {
   568  	codec := legacyscheme.Codecs.LegacyCodec(v1.SchemeGroupVersion)
   569  	items := benchmarkItems(b)
   570  	width := len(items)
   571  	encoded := make([][]byte, width)
   572  	for i := range items {
   573  		data, err := runtime.Encode(codec, &items[i])
   574  		if err != nil {
   575  			b.Fatal(err)
   576  		}
   577  		encoded[i] = data
   578  	}
   579  
   580  	b.ResetTimer()
   581  	for i := 0; i < b.N; i++ {
   582  		obj := v1.Pod{}
   583  		if err := gojson.Unmarshal(encoded[i%width], &obj); err != nil {
   584  			b.Fatal(err)
   585  		}
   586  	}
   587  	b.StopTimer()
   588  }
   589  
   590  // BenchmarkEncodeYAMLMarshal provides a baseline for regular YAML encode performance
   591  func BenchmarkEncodeYAMLMarshal(b *testing.B) {
   592  	items := benchmarkItems(b)
   593  	width := len(items)
   594  	b.ResetTimer()
   595  	for i := 0; i < b.N; i++ {
   596  		if _, err := yaml.Marshal(&items[i%width]); err != nil {
   597  			b.Fatal(err)
   598  		}
   599  	}
   600  	b.StopTimer()
   601  }
   602  
   603  // BenchmarkDecodeYAML provides a baseline for regular YAML decode performance
   604  func BenchmarkDecodeIntoYAML(b *testing.B) {
   605  	codec := legacyscheme.Codecs.LegacyCodec(v1.SchemeGroupVersion)
   606  	items := benchmarkItems(b)
   607  	width := len(items)
   608  	encoded := make([][]byte, width)
   609  	for i := range items {
   610  		data, err := runtime.Encode(codec, &items[i])
   611  		if err != nil {
   612  			b.Fatal(err)
   613  		}
   614  		encoded[i] = data
   615  	}
   616  
   617  	b.ResetTimer()
   618  	for i := 0; i < b.N; i++ {
   619  		obj := v1.Pod{}
   620  		if err := yaml.Unmarshal(encoded[i%width], &obj); err != nil {
   621  			b.Fatal(err)
   622  		}
   623  	}
   624  	b.StopTimer()
   625  }