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 }