github.com/kubewharf/katalyst-core@v0.5.3/pkg/util/resource-recommend/resource/k8s_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 resource
    18  
    19  import (
    20  	"context"
    21  	"reflect"
    22  	"testing"
    23  
    24  	v1 "k8s.io/api/core/v1"
    25  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    26  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    27  	"k8s.io/apimachinery/pkg/types"
    28  	"sigs.k8s.io/controller-runtime/pkg/client"
    29  	"sigs.k8s.io/controller-runtime/pkg/client/fake"
    30  
    31  	"github.com/kubewharf/katalyst-api/pkg/apis/recommendation/v1alpha1"
    32  )
    33  
    34  func TestConvertAndGetResource(t *testing.T) {
    35  	type args struct {
    36  		ctx       context.Context
    37  		client    client.Client
    38  		namespace string
    39  		targetRef v1alpha1.CrossVersionObjectReference
    40  	}
    41  	type env struct {
    42  		namespace  string
    43  		kind       string
    44  		name       string
    45  		apiVersion string
    46  	}
    47  	tests := []struct {
    48  		name    string
    49  		args    args
    50  		env     env
    51  		want    *unstructured.Unstructured
    52  		wantErr bool
    53  	}{
    54  		{
    55  			name: "Get resource failed",
    56  			args: args{
    57  				ctx:       context.TODO(),
    58  				client:    fake.NewClientBuilder().Build(),
    59  				namespace: "fakeNamespace",
    60  				targetRef: v1alpha1.CrossVersionObjectReference{
    61  					Kind:       "Deployment",
    62  					Name:       "mockResourceName",
    63  					APIVersion: "apps/v1",
    64  				},
    65  			},
    66  			env: env{
    67  				namespace:  "fakeNamespace",
    68  				kind:       "Deployment",
    69  				name:       "mockResourceName1",
    70  				apiVersion: "apps/v1",
    71  			},
    72  			wantErr: true,
    73  		},
    74  		{
    75  			name: "Get resource failed",
    76  			args: args{
    77  				ctx:       context.TODO(),
    78  				client:    fake.NewClientBuilder().Build(),
    79  				namespace: "fakeNamespace",
    80  				targetRef: v1alpha1.CrossVersionObjectReference{
    81  					Kind:       "Deployment",
    82  					Name:       "mockResourceName",
    83  					APIVersion: "apps/v1",
    84  				},
    85  			},
    86  			env: env{
    87  				namespace:  "fakeNamespace",
    88  				kind:       "Deployment",
    89  				name:       "mockResourceName",
    90  				apiVersion: "apps/v1",
    91  			},
    92  			wantErr: false,
    93  		},
    94  	}
    95  	for _, tt := range tests {
    96  		t.Run(tt.name, func(t *testing.T) {
    97  			CreateMockUnstructured(nil, nil, tt.env.name, tt.env.namespace, tt.env.apiVersion, tt.env.kind, tt.args.client)
    98  			_, err := ConvertAndGetResource(tt.args.ctx, tt.args.client, tt.args.namespace, tt.args.targetRef)
    99  			if (err != nil) != tt.wantErr {
   100  				t.Errorf("ConvertAndGetResource() error = %v, wantErr %v", err, tt.wantErr)
   101  				return
   102  			}
   103  		})
   104  	}
   105  }
   106  
   107  func TestGetAllClaimedContainers(t *testing.T) {
   108  	type args struct {
   109  		controller *unstructured.Unstructured
   110  	}
   111  	type env struct {
   112  		needCreate               bool
   113  		unstructuredTemplateSpec map[string]interface{}
   114  	}
   115  	tests := []struct {
   116  		name    string
   117  		args    args
   118  		env     env
   119  		want    []string
   120  		wantErr bool
   121  	}{
   122  		{
   123  			name: "spec.template.spec not found",
   124  			args: args{
   125  				controller: &unstructured.Unstructured{},
   126  			},
   127  			env: env{
   128  				needCreate:               false,
   129  				unstructuredTemplateSpec: map[string]interface{}{},
   130  			},
   131  			want:    nil,
   132  			wantErr: true,
   133  		},
   134  		{
   135  			name: "nestedMap failed",
   136  			args: args{
   137  				controller: &unstructured.Unstructured{},
   138  			},
   139  			env: env{
   140  				needCreate: true,
   141  				unstructuredTemplateSpec: map[string]interface{}{
   142  					"container": []interface{}{
   143  						map[string]interface{}{
   144  							"name":  "container-1",
   145  							"image": "image:latest",
   146  						},
   147  						map[string]interface{}{
   148  							"name":  "container-2",
   149  							"image": "image:latest",
   150  						},
   151  					},
   152  				},
   153  			},
   154  			want:    nil,
   155  			wantErr: true,
   156  		},
   157  		{
   158  			name: "container name not found",
   159  			args: args{
   160  				controller: &unstructured.Unstructured{},
   161  			},
   162  			env: env{
   163  				needCreate: true,
   164  				unstructuredTemplateSpec: map[string]interface{}{
   165  					"containers": []interface{}{
   166  						map[string]interface{}{
   167  							"image": "image:latest",
   168  						},
   169  						map[string]interface{}{
   170  							"image": "image:latest",
   171  						},
   172  					},
   173  				},
   174  			},
   175  			want:    []string{},
   176  			wantErr: false,
   177  		},
   178  		{
   179  			name: "all right",
   180  			args: args{
   181  				controller: &unstructured.Unstructured{},
   182  			},
   183  			env: env{
   184  				needCreate: true,
   185  				unstructuredTemplateSpec: map[string]interface{}{
   186  					"containers": []interface{}{
   187  						map[string]interface{}{
   188  							"name":  "container-1",
   189  							"image": "image:latest",
   190  						},
   191  						map[string]interface{}{
   192  							"name":  "container-2",
   193  							"image": "image:latest",
   194  						},
   195  					},
   196  				},
   197  			},
   198  			want:    []string{"container-1", "container-2"},
   199  			wantErr: false,
   200  		},
   201  	}
   202  	for _, tt := range tests {
   203  		t.Run(tt.name, func(t *testing.T) {
   204  			if tt.env.needCreate {
   205  				tt.args.controller.SetName("mockName")
   206  				unstructured.SetNestedMap(tt.args.controller.Object, tt.env.unstructuredTemplateSpec, "spec", "template", "spec")
   207  			}
   208  			got, err := GetAllClaimedContainers(tt.args.controller)
   209  			if (err != nil) != tt.wantErr {
   210  				t.Errorf("GetAllClaimedContainers() error = %v, wantErr %v", err, tt.wantErr)
   211  				return
   212  			}
   213  			if !reflect.DeepEqual(got, tt.want) {
   214  				t.Errorf("GetAllClaimedContainers() got = %v, want %v", got, tt.want)
   215  			}
   216  		})
   217  	}
   218  }
   219  
   220  func TestPatchUpdateResourceRecommend(t *testing.T) {
   221  	type args struct {
   222  		client            client.Client
   223  		namespaceName     types.NamespacedName
   224  		resourceRecommend *v1alpha1.ResourceRecommend
   225  	}
   226  	tests := []struct {
   227  		name                  string
   228  		args                  args
   229  		wantErr               bool
   230  		wantResourceRecommend *v1alpha1.ResourceRecommend
   231  	}{
   232  		{
   233  			name: "all right 1",
   234  			args: args{
   235  				client: fake.NewClientBuilder().Build(),
   236  				namespaceName: types.NamespacedName{
   237  					Name:      "mockName",
   238  					Namespace: "mockNamespace",
   239  				},
   240  				resourceRecommend: &v1alpha1.ResourceRecommend{
   241  					TypeMeta: metav1.TypeMeta{
   242  						Kind:       "ResourceRecommend",
   243  						APIVersion: "autoscaling.katalyst.kubewharf.io/v1alpha1",
   244  					},
   245  					ObjectMeta: metav1.ObjectMeta{
   246  						Name:      "mockName",
   247  						Namespace: "mockNamespace",
   248  					},
   249  					Status: v1alpha1.ResourceRecommendStatus{},
   250  				},
   251  			},
   252  			wantResourceRecommend: &v1alpha1.ResourceRecommend{
   253  				Status: v1alpha1.ResourceRecommendStatus{
   254  					RecommendResources: &v1alpha1.RecommendResources{
   255  						ContainerRecommendations: []v1alpha1.ContainerResources{
   256  							{
   257  								ContainerName: "ContainerName1",
   258  								Requests:      &v1alpha1.ContainerResourceList{},
   259  							},
   260  							{
   261  								ContainerName: "ContainerName2",
   262  								Requests:      &v1alpha1.ContainerResourceList{},
   263  							},
   264  							{
   265  								ContainerName: "ContainerName3",
   266  								Requests:      &v1alpha1.ContainerResourceList{},
   267  							},
   268  							{
   269  								ContainerName: "ContainerName4",
   270  								Requests:      &v1alpha1.ContainerResourceList{},
   271  							},
   272  						},
   273  					},
   274  					Conditions: []v1alpha1.ResourceRecommendCondition{
   275  						{
   276  							Type:    v1alpha1.Validated,
   277  							Reason:  "reason1",
   278  							Status:  v1.ConditionTrue,
   279  							Message: "Message",
   280  						},
   281  						{
   282  							Type:    v1alpha1.Validated,
   283  							Reason:  "reason2",
   284  							Status:  v1.ConditionTrue,
   285  							Message: "Message",
   286  						},
   287  						{
   288  							Type:    v1alpha1.Validated,
   289  							Reason:  "reason3",
   290  							Status:  v1.ConditionTrue,
   291  							Message: "Message",
   292  						},
   293  						{
   294  							Type:    v1alpha1.Validated,
   295  							Reason:  "reason4",
   296  							Status:  v1.ConditionTrue,
   297  							Message: "Message",
   298  						},
   299  					},
   300  				},
   301  			},
   302  			wantErr: false,
   303  		},
   304  		{
   305  			name: "all right 2",
   306  			args: args{
   307  				client: fake.NewClientBuilder().Build(),
   308  				namespaceName: types.NamespacedName{
   309  					Name:      "mockName",
   310  					Namespace: "mockNamespace",
   311  				},
   312  				resourceRecommend: &v1alpha1.ResourceRecommend{
   313  					TypeMeta: metav1.TypeMeta{
   314  						Kind:       "ResourceRecommend",
   315  						APIVersion: "autoscaling.katalyst.kubewharf.io/v1alpha1",
   316  					},
   317  					ObjectMeta: metav1.ObjectMeta{
   318  						Name:      "mockName",
   319  						Namespace: "mockNamespace",
   320  					},
   321  					Status: v1alpha1.ResourceRecommendStatus{
   322  						RecommendResources: &v1alpha1.RecommendResources{
   323  							ContainerRecommendations: []v1alpha1.ContainerResources{
   324  								{
   325  									ContainerName: "ContainerName0",
   326  								},
   327  								{
   328  									ContainerName: "ContainerName1",
   329  								},
   330  								{
   331  									ContainerName: "ContainerName2",
   332  								},
   333  								{
   334  									ContainerName: "ContainerName3",
   335  								},
   336  							},
   337  						},
   338  						Conditions: []v1alpha1.ResourceRecommendCondition{
   339  							{
   340  								Type:    v1alpha1.Validated,
   341  								Reason:  "reason0",
   342  								Status:  v1.ConditionTrue,
   343  								Message: "Message",
   344  							},
   345  							{
   346  								Type:    v1alpha1.Validated,
   347  								Reason:  "reason1",
   348  								Status:  v1.ConditionTrue,
   349  								Message: "Message",
   350  							},
   351  							{
   352  								Type:    v1alpha1.Validated,
   353  								Reason:  "reason2",
   354  								Status:  v1.ConditionTrue,
   355  								Message: "Message",
   356  							},
   357  							{
   358  								Type:    v1alpha1.Validated,
   359  								Reason:  "reason3",
   360  								Status:  v1.ConditionTrue,
   361  								Message: "Message",
   362  							},
   363  						},
   364  					},
   365  				},
   366  			},
   367  			wantResourceRecommend: &v1alpha1.ResourceRecommend{
   368  				Status: v1alpha1.ResourceRecommendStatus{
   369  					RecommendResources: &v1alpha1.RecommendResources{
   370  						ContainerRecommendations: []v1alpha1.ContainerResources{
   371  							{
   372  								ContainerName: "ContainerName1",
   373  								Requests:      &v1alpha1.ContainerResourceList{},
   374  							},
   375  							{
   376  								ContainerName: "ContainerName2",
   377  								Requests:      &v1alpha1.ContainerResourceList{},
   378  							},
   379  							{
   380  								ContainerName: "ContainerName3",
   381  								Requests:      &v1alpha1.ContainerResourceList{},
   382  							},
   383  							{
   384  								ContainerName: "ContainerName4",
   385  								Requests:      &v1alpha1.ContainerResourceList{},
   386  							},
   387  						},
   388  					},
   389  					Conditions: []v1alpha1.ResourceRecommendCondition{
   390  						{
   391  							Type:    v1alpha1.Validated,
   392  							Reason:  "reason1",
   393  							Status:  v1.ConditionTrue,
   394  							Message: "Message",
   395  						},
   396  						{
   397  							Type:    v1alpha1.Validated,
   398  							Reason:  "reason2",
   399  							Status:  v1.ConditionTrue,
   400  							Message: "Message",
   401  						},
   402  						{
   403  							Type:    v1alpha1.Validated,
   404  							Reason:  "reason3",
   405  							Status:  v1.ConditionTrue,
   406  							Message: "Message",
   407  						},
   408  						{
   409  							Type:    v1alpha1.Validated,
   410  							Reason:  "reason4",
   411  							Status:  v1.ConditionTrue,
   412  							Message: "Message",
   413  						},
   414  					},
   415  				},
   416  			},
   417  			wantErr: false,
   418  		},
   419  	}
   420  	for _, tt := range tests {
   421  		t.Run(tt.name, func(t *testing.T) {
   422  			v1alpha1.AddToScheme(tt.args.client.Scheme())
   423  			tt.args.client.Create(context.TODO(), tt.args.resourceRecommend)
   424  			if err := PatchUpdateResourceRecommend(tt.args.client, tt.args.namespaceName, tt.args.resourceRecommend); (err != nil) != tt.wantErr {
   425  				t.Errorf("PatchUpdateResourceRecommend() error = %v, wantErr %v", err, tt.wantErr)
   426  			}
   427  			if err := PatchUpdateResourceRecommend(tt.args.client, tt.args.namespaceName, tt.wantResourceRecommend); (err != nil) != tt.wantErr {
   428  				t.Errorf("PatchUpdateResourceRecommend() error = %v, wantErr %v", err, tt.wantErr)
   429  			}
   430  			gotResourceRecommend := &v1alpha1.ResourceRecommend{}
   431  			tt.args.client.Get(context.TODO(), client.ObjectKey{
   432  				Name:      tt.args.namespaceName.Name,
   433  				Namespace: tt.args.namespaceName.Namespace,
   434  			}, gotResourceRecommend)
   435  			if !reflect.DeepEqual(gotResourceRecommend.Status, tt.wantResourceRecommend.Status) {
   436  				t.Errorf("PatchUpdateResourceRecommend() gotResourceRecommend.Status = %v, wantResourceRecommend.Status = %v",
   437  					gotResourceRecommend.Status, tt.wantResourceRecommend.Status)
   438  			}
   439  		})
   440  	}
   441  }