github.com/kubewharf/katalyst-core@v0.5.3/pkg/controller/vpa/util/resource_test.go (about)

     1  /*
     2  Copyright 2022 The Katalyst 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 util
    18  
    19  import (
    20  	"fmt"
    21  	"testing"
    22  
    23  	"github.com/stretchr/testify/assert"
    24  	appsv1 "k8s.io/api/apps/v1"
    25  	v1 "k8s.io/api/core/v1"
    26  	"k8s.io/apimachinery/pkg/api/resource"
    27  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    28  	"k8s.io/apimachinery/pkg/runtime"
    29  	"k8s.io/apimachinery/pkg/runtime/schema"
    30  	"k8s.io/apimachinery/pkg/types"
    31  	"k8s.io/client-go/dynamic/dynamicinformer"
    32  	dynamicfake "k8s.io/client-go/dynamic/fake"
    33  	"k8s.io/client-go/informers"
    34  	"k8s.io/client-go/kubernetes/fake"
    35  	"k8s.io/client-go/tools/cache"
    36  	"k8s.io/klog/v2"
    37  	"k8s.io/utils/pointer"
    38  
    39  	apis "github.com/kubewharf/katalyst-api/pkg/apis/autoscaling/v1alpha1"
    40  	katalystutil "github.com/kubewharf/katalyst-core/pkg/util"
    41  	"github.com/kubewharf/katalyst-core/pkg/util/native"
    42  )
    43  
    44  var (
    45  	stsGVK = schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Statefulset"}
    46  	stsGVR = schema.GroupVersionResource{Group: "apps", Version: "v1", Resource: "statefulsets"}
    47  )
    48  
    49  func TestGetVPAResourceStatusWithCurrent(t *testing.T) {
    50  	t.Parallel()
    51  
    52  	// test with no indexers
    53  	klog.Infof("================== test with no indexers ==================")
    54  	testGetVPAResourceStatusWithCurrentAndIndexer(t, nil, []string{})
    55  
    56  	// test with existed indexers
    57  	indexerKeys := []string{"workload"}
    58  	podIndexers := cache.Indexers{}
    59  	for _, key := range indexerKeys {
    60  		indexer := native.PodLabelIndexer(key)
    61  		podIndexers[key] = indexer.IndexFunc
    62  	}
    63  	klog.Infof("================== test with existed indexers ==================")
    64  	testGetVPAResourceStatusWithCurrentAndIndexer(t, podIndexers, indexerKeys)
    65  
    66  	// test with none-existed indexers
    67  	indexerKeys = []string{"none-exist"}
    68  	podIndexers = cache.Indexers{}
    69  	for _, key := range indexerKeys {
    70  		indexer := native.PodLabelIndexer(key)
    71  		podIndexers[key] = indexer.IndexFunc
    72  	}
    73  	klog.Infof("================== test with none-existed indexers ==================")
    74  	testGetVPAResourceStatusWithCurrentAndIndexer(t, podIndexers, indexerKeys)
    75  }
    76  
    77  func testGetVPAResourceStatusWithCurrentAndIndexer(t *testing.T, podIndexers cache.Indexers, podIndexerKeys []string) {
    78  	container1 := &v1.Container{
    79  		Name: "c1",
    80  		Resources: v1.ResourceRequirements{
    81  			Limits: map[v1.ResourceName]resource.Quantity{
    82  				v1.ResourceMemory: resource.MustParse("4Gi"),
    83  				v1.ResourceCPU:    resource.MustParse("4"),
    84  			},
    85  			Requests: map[v1.ResourceName]resource.Quantity{
    86  				v1.ResourceMemory: resource.MustParse("2Gi"),
    87  				v1.ResourceCPU:    resource.MustParse("2"),
    88  			},
    89  		},
    90  	}
    91  	container2 := &v1.Container{
    92  		Name: "c1",
    93  		Resources: v1.ResourceRequirements{
    94  			Limits: map[v1.ResourceName]resource.Quantity{
    95  				v1.ResourceMemory: resource.MustParse("3Gi"),
    96  				v1.ResourceCPU:    resource.MustParse("3"),
    97  			},
    98  			Requests: map[v1.ResourceName]resource.Quantity{
    99  				v1.ResourceMemory: resource.MustParse("2Gi"),
   100  				v1.ResourceCPU:    resource.MustParse("2"),
   101  			},
   102  		},
   103  	}
   104  	pod1 := &v1.Pod{
   105  		ObjectMeta: metav1.ObjectMeta{
   106  			Namespace: "default",
   107  			Name:      "pod1",
   108  			Labels: map[string]string{
   109  				"workload": "sts",
   110  			},
   111  			OwnerReferences: []metav1.OwnerReference{
   112  				{
   113  					APIVersion: stsGVK.GroupVersion().String(),
   114  					Kind:       stsGVK.Kind,
   115  					Name:       "sts1",
   116  				},
   117  			},
   118  			UID: types.UID("pod1-uid"),
   119  		},
   120  		Spec: v1.PodSpec{
   121  			Containers: []v1.Container{*container1},
   122  		},
   123  	}
   124  	pod2 := &v1.Pod{
   125  		ObjectMeta: metav1.ObjectMeta{
   126  			Namespace: "default",
   127  			Name:      "pod2",
   128  			Labels: map[string]string{
   129  				"workload": "sts",
   130  			},
   131  			OwnerReferences: []metav1.OwnerReference{
   132  				{
   133  					APIVersion: stsGVK.GroupVersion().String(),
   134  					Kind:       stsGVK.Kind,
   135  					Name:       "sts1",
   136  				},
   137  			},
   138  			UID: types.UID("pod2-uid"),
   139  		},
   140  		Spec: v1.PodSpec{
   141  			Containers: []v1.Container{*container2},
   142  		},
   143  	}
   144  	vpa1 := &apis.KatalystVerticalPodAutoscaler{
   145  		ObjectMeta: metav1.ObjectMeta{
   146  			Namespace: "default",
   147  			Name:      "vpa1",
   148  		},
   149  		Spec: apis.KatalystVerticalPodAutoscalerSpec{
   150  			TargetRef: apis.CrossVersionObjectReference{
   151  				Kind:       stsGVK.Kind,
   152  				Name:       "sts1",
   153  				APIVersion: stsGVK.GroupVersion().String(),
   154  			},
   155  		},
   156  		Status: apis.KatalystVerticalPodAutoscalerStatus{
   157  			ContainerResources: []apis.ContainerResources{
   158  				{
   159  					ContainerName: pointer.String("c1"),
   160  					Requests: &apis.ContainerResourceList{
   161  						Target: map[v1.ResourceName]resource.Quantity{
   162  							v1.ResourceMemory: resource.MustParse("1Gi"),
   163  							v1.ResourceCPU:    resource.MustParse("1"),
   164  						},
   165  						UncappedTarget: map[v1.ResourceName]resource.Quantity{
   166  							v1.ResourceMemory: resource.MustParse("1Gi"),
   167  							v1.ResourceCPU:    resource.MustParse("1"),
   168  						},
   169  					},
   170  				},
   171  			},
   172  		},
   173  	}
   174  	vpa2 := &apis.KatalystVerticalPodAutoscaler{
   175  		ObjectMeta: metav1.ObjectMeta{
   176  			Namespace: "default",
   177  			Name:      "vpa1",
   178  		},
   179  		Spec: apis.KatalystVerticalPodAutoscalerSpec{
   180  			TargetRef: apis.CrossVersionObjectReference{
   181  				Kind:       stsGVK.Kind,
   182  				Name:       "sts1",
   183  				APIVersion: stsGVK.GroupVersion().String(),
   184  			},
   185  		},
   186  		Status: apis.KatalystVerticalPodAutoscalerStatus{
   187  			ContainerResources: []apis.ContainerResources{
   188  				{
   189  					ContainerName: pointer.String("c1"),
   190  					Requests: &apis.ContainerResourceList{
   191  						Target: map[v1.ResourceName]resource.Quantity{
   192  							v1.ResourceMemory: resource.MustParse("3Gi"),
   193  							v1.ResourceCPU:    resource.MustParse("3"),
   194  						},
   195  						UncappedTarget: map[v1.ResourceName]resource.Quantity{
   196  							v1.ResourceMemory: resource.MustParse("3Gi"),
   197  							v1.ResourceCPU:    resource.MustParse("3"),
   198  						},
   199  					},
   200  				},
   201  			},
   202  		},
   203  	}
   204  	vpa3 := &apis.KatalystVerticalPodAutoscaler{
   205  		ObjectMeta: metav1.ObjectMeta{
   206  			Namespace: "default",
   207  			Name:      "vpa1",
   208  		},
   209  		Spec: apis.KatalystVerticalPodAutoscalerSpec{
   210  			TargetRef: apis.CrossVersionObjectReference{
   211  				Kind:       stsGVK.Kind,
   212  				Name:       "sts1",
   213  				APIVersion: stsGVK.GroupVersion().String(),
   214  			},
   215  		},
   216  		Status: apis.KatalystVerticalPodAutoscalerStatus{
   217  			PodResources: []apis.PodResources{
   218  				{
   219  					PodName: pointer.String("pod1"),
   220  					ContainerResources: []apis.ContainerResources{
   221  						{
   222  							ContainerName: pointer.String("c1"),
   223  							Requests: &apis.ContainerResourceList{
   224  								Target: map[v1.ResourceName]resource.Quantity{
   225  									v1.ResourceMemory: resource.MustParse("3Gi"),
   226  									v1.ResourceCPU:    resource.MustParse("3"),
   227  								},
   228  								UncappedTarget: map[v1.ResourceName]resource.Quantity{
   229  									v1.ResourceMemory: resource.MustParse("3Gi"),
   230  									v1.ResourceCPU:    resource.MustParse("3"),
   231  								},
   232  							},
   233  							Limits: &apis.ContainerResourceList{
   234  								Target: map[v1.ResourceName]resource.Quantity{
   235  									v1.ResourceMemory: resource.MustParse("3Gi"),
   236  									v1.ResourceCPU:    resource.MustParse("3"),
   237  								},
   238  								UncappedTarget: map[v1.ResourceName]resource.Quantity{
   239  									v1.ResourceMemory: resource.MustParse("3Gi"),
   240  									v1.ResourceCPU:    resource.MustParse("3"),
   241  								},
   242  							},
   243  						},
   244  					},
   245  				},
   246  			},
   247  		},
   248  	}
   249  
   250  	vpa4 := &apis.KatalystVerticalPodAutoscaler{
   251  		ObjectMeta: metav1.ObjectMeta{
   252  			Namespace: "default",
   253  			Name:      "vpa1",
   254  		},
   255  		Spec: apis.KatalystVerticalPodAutoscalerSpec{
   256  			TargetRef: apis.CrossVersionObjectReference{
   257  				Kind:       stsGVK.Kind,
   258  				Name:       "sts1",
   259  				APIVersion: stsGVK.GroupVersion().String(),
   260  			},
   261  		},
   262  		Status: apis.KatalystVerticalPodAutoscalerStatus{
   263  			ContainerResources: []apis.ContainerResources{
   264  				{
   265  					ContainerName: pointer.String("c1"),
   266  					Limits: &apis.ContainerResourceList{
   267  						Target:         v1.ResourceList{},
   268  						UncappedTarget: v1.ResourceList{},
   269  						LowerBound: v1.ResourceList{
   270  							v1.ResourceMemory: resource.MustParse("400Mi"),
   271  						},
   272  						UpperBound: v1.ResourceList{
   273  							v1.ResourceMemory: resource.MustParse("6000Mi"),
   274  						},
   275  					},
   276  				},
   277  			},
   278  		},
   279  	}
   280  
   281  	sts1 := &appsv1.StatefulSet{
   282  		TypeMeta: metav1.TypeMeta{
   283  			Kind:       "StatefulSet",
   284  			APIVersion: "apps/v1",
   285  		},
   286  		ObjectMeta: metav1.ObjectMeta{
   287  			Namespace: "default",
   288  			Name:      "sts1",
   289  		},
   290  		Spec: appsv1.StatefulSetSpec{
   291  			Replicas: pointer.Int32(1),
   292  			Template: v1.PodTemplateSpec{
   293  				Spec: v1.PodSpec{
   294  					Containers: []v1.Container{*container1},
   295  				},
   296  			},
   297  			Selector: &metav1.LabelSelector{
   298  				MatchLabels: map[string]string{
   299  					"workload": "sts",
   300  				},
   301  			},
   302  		},
   303  		Status: appsv1.StatefulSetStatus{},
   304  	}
   305  	for _, tc := range []struct {
   306  		name                  string
   307  		vpa                   *apis.KatalystVerticalPodAutoscaler
   308  		pods                  []*v1.Pod
   309  		object                runtime.Object
   310  		gvk                   schema.GroupVersionKind
   311  		vpaPodResources       []apis.PodResources
   312  		vpaContainerResources []apis.ContainerResources
   313  	}{
   314  		{
   315  			name:            "shrink resource: vpa container",
   316  			vpa:             vpa1,
   317  			pods:            []*v1.Pod{pod1},
   318  			object:          sts1,
   319  			gvk:             stsGVK,
   320  			vpaPodResources: []apis.PodResources{},
   321  			vpaContainerResources: []apis.ContainerResources{
   322  				{
   323  					ContainerName: pointer.String("c1"),
   324  					Requests: &apis.ContainerResourceList{
   325  						Current: v1.ResourceList{
   326  							v1.ResourceMemory: resource.MustParse("2Gi"),
   327  							v1.ResourceCPU:    resource.MustParse("2"),
   328  						},
   329  						Target: v1.ResourceList{
   330  							v1.ResourceMemory: resource.MustParse("1Gi"),
   331  							v1.ResourceCPU:    resource.MustParse("1"),
   332  						},
   333  						UncappedTarget: v1.ResourceList{
   334  							v1.ResourceMemory: resource.MustParse("1Gi"),
   335  							v1.ResourceCPU:    resource.MustParse("1"),
   336  						},
   337  					},
   338  				},
   339  			},
   340  		},
   341  		{
   342  			name:            "expand resource: vpa container",
   343  			vpa:             vpa2,
   344  			pods:            []*v1.Pod{pod1},
   345  			object:          sts1,
   346  			gvk:             stsGVK,
   347  			vpaPodResources: []apis.PodResources{},
   348  			vpaContainerResources: []apis.ContainerResources{
   349  				{
   350  					ContainerName: pointer.String("c1"),
   351  					Requests: &apis.ContainerResourceList{
   352  						Current: v1.ResourceList{
   353  							v1.ResourceMemory: resource.MustParse("2Gi"),
   354  							v1.ResourceCPU:    resource.MustParse("2"),
   355  						},
   356  						Target: v1.ResourceList{
   357  							v1.ResourceMemory: resource.MustParse("3Gi"),
   358  							v1.ResourceCPU:    resource.MustParse("3"),
   359  						},
   360  						UncappedTarget: v1.ResourceList{
   361  							v1.ResourceMemory: resource.MustParse("3Gi"),
   362  							v1.ResourceCPU:    resource.MustParse("3"),
   363  						},
   364  					},
   365  				},
   366  			},
   367  		},
   368  		{
   369  			name:   "expand resource: two pod",
   370  			vpa:    vpa3,
   371  			pods:   []*v1.Pod{pod1, pod2},
   372  			object: sts1,
   373  			gvk:    stsGVK,
   374  			vpaPodResources: []apis.PodResources{
   375  				{
   376  					PodName: pointer.String("pod1"),
   377  					ContainerResources: []apis.ContainerResources{
   378  						{
   379  							ContainerName: pointer.String("c1"),
   380  							Requests: &apis.ContainerResourceList{
   381  								Current: v1.ResourceList{
   382  									v1.ResourceMemory: resource.MustParse("2Gi"),
   383  									v1.ResourceCPU:    resource.MustParse("2"),
   384  								},
   385  								Target: v1.ResourceList{
   386  									v1.ResourceMemory: resource.MustParse("3Gi"),
   387  									v1.ResourceCPU:    resource.MustParse("3"),
   388  								},
   389  								UncappedTarget: v1.ResourceList{
   390  									v1.ResourceMemory: resource.MustParse("3Gi"),
   391  									v1.ResourceCPU:    resource.MustParse("3"),
   392  								},
   393  							},
   394  							Limits: &apis.ContainerResourceList{
   395  								Current: v1.ResourceList{
   396  									v1.ResourceMemory: resource.MustParse("4Gi"),
   397  									v1.ResourceCPU:    resource.MustParse("4"),
   398  								},
   399  								Target: v1.ResourceList{
   400  									v1.ResourceMemory: resource.MustParse("3Gi"),
   401  									v1.ResourceCPU:    resource.MustParse("3"),
   402  								},
   403  								UncappedTarget: v1.ResourceList{
   404  									v1.ResourceMemory: resource.MustParse("3Gi"),
   405  									v1.ResourceCPU:    resource.MustParse("3"),
   406  								},
   407  							},
   408  						},
   409  					},
   410  				},
   411  			},
   412  			vpaContainerResources: []apis.ContainerResources{},
   413  		},
   414  		{
   415  			name:            "expand resource: without limit",
   416  			vpa:             vpa4,
   417  			pods:            []*v1.Pod{pod1},
   418  			object:          sts1,
   419  			gvk:             stsGVK,
   420  			vpaPodResources: []apis.PodResources{},
   421  			vpaContainerResources: []apis.ContainerResources{
   422  				{
   423  					ContainerName: pointer.String("c1"),
   424  					Limits: &apis.ContainerResourceList{
   425  						Current:        v1.ResourceList{},
   426  						Target:         v1.ResourceList{},
   427  						UncappedTarget: v1.ResourceList{},
   428  						LowerBound: v1.ResourceList{
   429  							v1.ResourceMemory: resource.MustParse("400Mi"),
   430  						},
   431  						UpperBound: v1.ResourceList{
   432  							v1.ResourceMemory: resource.MustParse("6000Mi"),
   433  						},
   434  					},
   435  				},
   436  			},
   437  		},
   438  	} {
   439  		t.Run(tc.name, func(t *testing.T) {
   440  			fakeDynamicClient := dynamicfake.NewSimpleDynamicClient(runtime.NewScheme())
   441  			dynamicFactory := dynamicinformer.NewDynamicSharedInformerFactory(fakeDynamicClient, 0)
   442  			stsInformer := dynamicFactory.ForResource(stsGVR)
   443  			workloadInformers := map[schema.GroupVersionKind]informers.GenericInformer{
   444  				stsGVK: stsInformer,
   445  			}
   446  
   447  			KubeClient := fake.NewSimpleClientset()
   448  			KubeInformerFactory := informers.NewSharedInformerFactory(KubeClient, 0)
   449  
   450  			u, err := native.ToUnstructured(tc.object)
   451  			assert.NoError(t, err)
   452  			err = workloadInformers[tc.gvk].Informer().GetStore().Add(u)
   453  			assert.NoError(t, err)
   454  
   455  			podInformer := KubeInformerFactory.Core().V1().Pods()
   456  			err = podInformer.Informer().AddIndexers(podIndexers)
   457  			assert.NoError(t, err)
   458  
   459  			for _, pod := range tc.pods {
   460  				err = podInformer.Informer().GetStore().Add(pod)
   461  				assert.NoError(t, err)
   462  			}
   463  
   464  			pods, err := katalystutil.GetPodListForVPA(tc.vpa, podInformer.Informer().GetIndexer(), podIndexerKeys, workloadInformers[tc.gvk].Lister(), podInformer.Lister())
   465  			assert.NoError(t, err)
   466  
   467  			vpaPodResources, vpaContainerResources, err := GetVPAResourceStatusWithCurrent(tc.vpa, pods)
   468  			assert.NoError(t, err)
   469  			assert.Equal(t, tc.vpaPodResources, vpaPodResources)
   470  			assert.Equal(t, tc.vpaContainerResources, vpaContainerResources)
   471  		})
   472  	}
   473  }
   474  
   475  func TestGetVPAResourceStatusWithRecommendation(t *testing.T) {
   476  	t.Parallel()
   477  
   478  	type args struct {
   479  		vpa                   *apis.KatalystVerticalPodAutoscaler
   480  		recPodResources       []apis.RecommendedPodResources
   481  		recContainerResources []apis.RecommendedContainerResources
   482  	}
   483  	tests := []struct {
   484  		name    string
   485  		args    args
   486  		want    []apis.PodResources
   487  		want1   []apis.ContainerResources
   488  		wantErr assert.ErrorAssertionFunc
   489  	}{
   490  		{
   491  			name: "without recommend limit but with memory bound",
   492  			args: args{
   493  				vpa: &apis.KatalystVerticalPodAutoscaler{
   494  					ObjectMeta: metav1.ObjectMeta{
   495  						Namespace: "default",
   496  						Name:      "vpa1",
   497  					},
   498  					Spec: apis.KatalystVerticalPodAutoscalerSpec{
   499  						TargetRef: apis.CrossVersionObjectReference{
   500  							Kind:       stsGVK.Kind,
   501  							Name:       "sts1",
   502  							APIVersion: stsGVK.GroupVersion().String(),
   503  						},
   504  						ResourcePolicy: apis.PodResourcePolicy{
   505  							ContainerPolicies: []apis.ContainerResourcePolicy{
   506  								{
   507  									ContainerName: pointer.String("nginx"),
   508  									ControlledResources: []v1.ResourceName{
   509  										v1.ResourceCPU,
   510  										v1.ResourceMemory,
   511  									},
   512  									ControlledValues: apis.ContainerControlledValuesRequestsAndLimits,
   513  									MaxAllowed: v1.ResourceList{
   514  										v1.ResourceMemory: resource.MustParse("6000Mi"),
   515  									},
   516  									MinAllowed: v1.ResourceList{
   517  										v1.ResourceMemory: resource.MustParse("400Mi"),
   518  									},
   519  									ResourceResizePolicy: apis.ResourceResizePolicyNone,
   520  								},
   521  							},
   522  						},
   523  						UpdatePolicy: apis.PodUpdatePolicy{
   524  							PodApplyStrategy:    apis.PodApplyStrategyStrategyGroup,
   525  							PodMatchingStrategy: apis.PodMatchingStrategyAll,
   526  							PodUpdatingStrategy: apis.PodUpdatingStrategyInplace,
   527  						},
   528  					},
   529  					Status: apis.KatalystVerticalPodAutoscalerStatus{
   530  						ContainerResources: []apis.ContainerResources{
   531  							{
   532  								ContainerName: pointer.String("nginx"),
   533  								Limits: &apis.ContainerResourceList{
   534  									Current: v1.ResourceList{
   535  										v1.ResourceCPU:    resource.MustParse("4"),
   536  										v1.ResourceMemory: resource.MustParse("6000Mi"),
   537  									},
   538  								},
   539  							},
   540  						},
   541  					},
   542  				},
   543  				recContainerResources: []apis.RecommendedContainerResources{
   544  					{
   545  						ContainerName: pointer.String("nginx"),
   546  						Limits: &apis.RecommendedRequestResources{
   547  							Resources: v1.ResourceList{},
   548  						},
   549  					},
   550  				},
   551  			},
   552  			want: []apis.PodResources{},
   553  			want1: []apis.ContainerResources{
   554  				{
   555  					ContainerName: pointer.String("nginx"),
   556  					Limits: &apis.ContainerResourceList{
   557  						Current: v1.ResourceList{
   558  							v1.ResourceCPU:    resource.MustParse("4"),
   559  							v1.ResourceMemory: resource.MustParse("6000Mi"),
   560  						},
   561  						Target:         v1.ResourceList{},
   562  						UncappedTarget: v1.ResourceList{},
   563  						LowerBound: v1.ResourceList{
   564  							v1.ResourceMemory: resource.MustParse("400Mi"),
   565  						},
   566  						UpperBound: v1.ResourceList{
   567  							v1.ResourceMemory: resource.MustParse("6000Mi"),
   568  						},
   569  					},
   570  				},
   571  			},
   572  			wantErr: func(t assert.TestingT, err error, i ...interface{}) bool {
   573  				return true
   574  			},
   575  		},
   576  		{
   577  			name: "without either recommend limit or bound",
   578  			args: args{
   579  				vpa: &apis.KatalystVerticalPodAutoscaler{
   580  					ObjectMeta: metav1.ObjectMeta{
   581  						Namespace: "default",
   582  						Name:      "vpa1",
   583  					},
   584  					Spec: apis.KatalystVerticalPodAutoscalerSpec{
   585  						TargetRef: apis.CrossVersionObjectReference{
   586  							Kind:       stsGVK.Kind,
   587  							Name:       "sts1",
   588  							APIVersion: stsGVK.GroupVersion().String(),
   589  						},
   590  						ResourcePolicy: apis.PodResourcePolicy{
   591  							ContainerPolicies: []apis.ContainerResourcePolicy{
   592  								{
   593  									ContainerName: pointer.String("nginx"),
   594  									ControlledResources: []v1.ResourceName{
   595  										v1.ResourceCPU,
   596  										v1.ResourceMemory,
   597  									},
   598  									ControlledValues:     apis.ContainerControlledValuesRequestsAndLimits,
   599  									ResourceResizePolicy: apis.ResourceResizePolicyNone,
   600  								},
   601  							},
   602  						},
   603  						UpdatePolicy: apis.PodUpdatePolicy{
   604  							PodApplyStrategy:    apis.PodApplyStrategyStrategyGroup,
   605  							PodMatchingStrategy: apis.PodMatchingStrategyAll,
   606  							PodUpdatingStrategy: apis.PodUpdatingStrategyInplace,
   607  						},
   608  					},
   609  				},
   610  				recContainerResources: []apis.RecommendedContainerResources{
   611  					{
   612  						ContainerName: pointer.String("nginx"),
   613  						Limits: &apis.RecommendedRequestResources{
   614  							Resources: v1.ResourceList{},
   615  						},
   616  					},
   617  				},
   618  			},
   619  			want: []apis.PodResources{},
   620  			want1: []apis.ContainerResources{
   621  				{
   622  					ContainerName: pointer.String("nginx"),
   623  					Limits: &apis.ContainerResourceList{
   624  						Target:         v1.ResourceList{},
   625  						UncappedTarget: v1.ResourceList{},
   626  						LowerBound:     nil,
   627  						UpperBound:     nil,
   628  					},
   629  				},
   630  			},
   631  			wantErr: func(t assert.TestingT, err error, i ...interface{}) bool {
   632  				return true
   633  			},
   634  		},
   635  	}
   636  	for _, tt := range tests {
   637  		tt := tt
   638  		t.Run(tt.name, func(t *testing.T) {
   639  			t.Parallel()
   640  			got, got1, err := GetVPAResourceStatusWithRecommendation(tt.args.vpa, tt.args.recPodResources, tt.args.recContainerResources)
   641  			if !tt.wantErr(t, err, fmt.Sprintf("GetVPAResourceStatusWithRecommendation(%v, %v, %v)", tt.args.vpa, tt.args.recPodResources, tt.args.recContainerResources)) {
   642  				return
   643  			}
   644  			assert.Equalf(t, tt.want, got, "GetVPAResourceStatusWithRecommendation(%v, %v, %v)", tt.args.vpa, tt.args.recPodResources, tt.args.recContainerResources)
   645  			assert.Equalf(t, tt.want1, got1, "GetVPAResourceStatusWithRecommendation(%v, %v, %v)", tt.args.vpa, tt.args.recPodResources, tt.args.recContainerResources)
   646  		})
   647  	}
   648  }