k8s.io/kubernetes@v1.29.3/test/integration/apiserver/timestamp_transformer_test.go (about)

     1  /*
     2  Copyright 2020 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 apiserver
    18  
    19  import (
    20  	"context"
    21  	"encoding/json"
    22  	"math/rand"
    23  	"testing"
    24  
    25  	"github.com/stretchr/testify/require"
    26  	v1 "k8s.io/api/core/v1"
    27  	k8sfuzz "k8s.io/apimachinery/pkg/api/apitesting/fuzzer"
    28  	"k8s.io/apimachinery/pkg/api/meta"
    29  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    30  	"k8s.io/apimachinery/pkg/runtime"
    31  	"k8s.io/apimachinery/pkg/runtime/serializer"
    32  	"k8s.io/apimachinery/pkg/util/managedfields"
    33  	"k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager"
    34  	k8stest "k8s.io/kubernetes/pkg/api/testing"
    35  )
    36  
    37  func convertToUnstructured(b *testing.B, obj runtime.Object) runtime.Object {
    38  	converter := managedfields.NewDeducedTypeConverter()
    39  	typed, err := converter.ObjectToTyped(obj)
    40  	require.NoError(b, err)
    41  	res, err := converter.TypedToObject(typed)
    42  	require.NoError(b, err)
    43  	return res
    44  }
    45  
    46  func doBench(b *testing.B, useUnstructured bool, shortCircuit bool) {
    47  	var (
    48  		expectedLarge runtime.Object
    49  		actualLarge   runtime.Object
    50  		expectedSmall runtime.Object
    51  		actualSmall   runtime.Object
    52  	)
    53  
    54  	scheme := runtime.NewScheme()
    55  	codecs := serializer.NewCodecFactory(scheme)
    56  	seed := rand.Int63()
    57  	fuzzer := k8sfuzz.FuzzerFor(k8stest.FuzzerFuncs, rand.NewSource(seed), codecs)
    58  	fuzzer.NilChance(0)
    59  
    60  	fuzzer.MaxDepth(1000).NilChance(0.2).NumElements(2, 15)
    61  	pod := &v1.Pod{}
    62  	fuzzer.Fuzz(pod)
    63  
    64  	fuzzer.NilChance(0.2).NumElements(10, 100).MaxDepth(10)
    65  	deployment := &v1.Endpoints{}
    66  	fuzzer.Fuzz(deployment)
    67  
    68  	bts, err := json.Marshal(deployment)
    69  	require.NoError(b, err)
    70  	b.Logf("Small (Deployment): %v bytes", len(bts))
    71  	bts, err = json.Marshal(pod)
    72  	require.NoError(b, err)
    73  	b.Logf("Large (Pod): %v bytes", len(bts))
    74  
    75  	expectedLarge = deployment
    76  	expectedSmall = pod
    77  
    78  	if useUnstructured {
    79  		expectedSmall = convertToUnstructured(b, expectedSmall)
    80  		expectedLarge = convertToUnstructured(b, expectedLarge)
    81  	}
    82  
    83  	actualLarge = expectedLarge.DeepCopyObject()
    84  	actualSmall = expectedSmall.DeepCopyObject()
    85  
    86  	if shortCircuit {
    87  		// Modify managed fields of the compared objects to induce a short circuit
    88  		now := metav1.Now()
    89  		extraEntry := &metav1.ManagedFieldsEntry{
    90  			Manager:    "sidecar_controller",
    91  			Operation:  metav1.ManagedFieldsOperationApply,
    92  			APIVersion: "apps/v1",
    93  			Time:       &now,
    94  			FieldsType: "FieldsV1",
    95  			FieldsV1: &metav1.FieldsV1{
    96  				Raw: []byte(`{"f:metadata":{"f:labels":{"f:sidecar_version":{}}},"f:spec":{"f:template":{"f:spec":{"f:containers":{"k:{\"name\":\"sidecar\"}":{".":{},"f:image":{},"f:name":{}}}}}}}`),
    97  			},
    98  		}
    99  
   100  		largeMeta, err := meta.Accessor(actualLarge)
   101  		require.NoError(b, err)
   102  		largeMeta.SetManagedFields(append(largeMeta.GetManagedFields(), *extraEntry))
   103  
   104  		smallMeta, err := meta.Accessor(actualSmall)
   105  		require.NoError(b, err)
   106  		smallMeta.SetManagedFields(append(smallMeta.GetManagedFields(), *extraEntry))
   107  	}
   108  
   109  	b.ResetTimer()
   110  
   111  	b.Run("Large", func(b2 *testing.B) {
   112  		for i := 0; i < b2.N; i++ {
   113  			if _, err := fieldmanager.IgnoreManagedFieldsTimestampsTransformer(
   114  				context.TODO(),
   115  				actualLarge,
   116  				expectedLarge,
   117  			); err != nil {
   118  				b2.Fatal(err)
   119  			}
   120  		}
   121  	})
   122  
   123  	b.Run("Small", func(b2 *testing.B) {
   124  		for i := 0; i < b2.N; i++ {
   125  			if _, err := fieldmanager.IgnoreManagedFieldsTimestampsTransformer(
   126  				context.TODO(),
   127  				actualSmall,
   128  				expectedSmall,
   129  			); err != nil {
   130  				b2.Fatal(err)
   131  			}
   132  		}
   133  	})
   134  }
   135  
   136  func BenchmarkIgnoreManagedFieldsTimestampTransformerStructuredShortCircuit(b *testing.B) {
   137  	doBench(b, false, true)
   138  }
   139  
   140  func BenchmarkIgnoreManagedFieldsTimestampTransformerStructuredWorstCase(b *testing.B) {
   141  	doBench(b, false, false)
   142  }
   143  
   144  func BenchmarkIgnoreManagedFieldsTimestampTransformerUnstructuredShortCircuit(b *testing.B) {
   145  	doBench(b, true, true)
   146  }
   147  
   148  func BenchmarkIgnoreManagedFieldsTimestampTransformerUnstructuredWorstCase(b *testing.B) {
   149  	doBench(b, true, false)
   150  }