k8s.io/kubernetes@v1.29.3/pkg/scheduler/framework/types_test.go (about)

     1  /*
     2  Copyright 2018 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 framework
    18  
    19  import (
    20  	"fmt"
    21  	"reflect"
    22  	"testing"
    23  
    24  	"github.com/google/go-cmp/cmp"
    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/types"
    29  	"k8s.io/apimachinery/pkg/util/sets"
    30  	utilfeature "k8s.io/apiserver/pkg/util/feature"
    31  	featuregatetesting "k8s.io/component-base/featuregate/testing"
    32  	"k8s.io/kubernetes/pkg/features"
    33  	st "k8s.io/kubernetes/pkg/scheduler/testing"
    34  	"k8s.io/kubernetes/test/utils/ktesting"
    35  )
    36  
    37  func TestNewResource(t *testing.T) {
    38  	tests := []struct {
    39  		name         string
    40  		resourceList v1.ResourceList
    41  		expected     *Resource
    42  	}{
    43  		{
    44  			name:         "empty resource",
    45  			resourceList: map[v1.ResourceName]resource.Quantity{},
    46  			expected:     &Resource{},
    47  		},
    48  		{
    49  			name: "complex resource",
    50  			resourceList: map[v1.ResourceName]resource.Quantity{
    51  				v1.ResourceCPU:                      *resource.NewScaledQuantity(4, -3),
    52  				v1.ResourceMemory:                   *resource.NewQuantity(2000, resource.BinarySI),
    53  				v1.ResourcePods:                     *resource.NewQuantity(80, resource.BinarySI),
    54  				v1.ResourceEphemeralStorage:         *resource.NewQuantity(5000, resource.BinarySI),
    55  				"scalar.test/" + "scalar1":          *resource.NewQuantity(1, resource.DecimalSI),
    56  				v1.ResourceHugePagesPrefix + "test": *resource.NewQuantity(2, resource.BinarySI),
    57  			},
    58  			expected: &Resource{
    59  				MilliCPU:         4,
    60  				Memory:           2000,
    61  				EphemeralStorage: 5000,
    62  				AllowedPodNumber: 80,
    63  				ScalarResources:  map[v1.ResourceName]int64{"scalar.test/scalar1": 1, "hugepages-test": 2},
    64  			},
    65  		},
    66  	}
    67  
    68  	for _, test := range tests {
    69  		t.Run(test.name, func(t *testing.T) {
    70  			r := NewResource(test.resourceList)
    71  			if !reflect.DeepEqual(test.expected, r) {
    72  				t.Errorf("expected: %#v, got: %#v", test.expected, r)
    73  			}
    74  		})
    75  	}
    76  }
    77  
    78  func TestResourceClone(t *testing.T) {
    79  	tests := []struct {
    80  		resource *Resource
    81  		expected *Resource
    82  	}{
    83  		{
    84  			resource: &Resource{},
    85  			expected: &Resource{},
    86  		},
    87  		{
    88  			resource: &Resource{
    89  				MilliCPU:         4,
    90  				Memory:           2000,
    91  				EphemeralStorage: 5000,
    92  				AllowedPodNumber: 80,
    93  				ScalarResources:  map[v1.ResourceName]int64{"scalar.test/scalar1": 1, "hugepages-test": 2},
    94  			},
    95  			expected: &Resource{
    96  				MilliCPU:         4,
    97  				Memory:           2000,
    98  				EphemeralStorage: 5000,
    99  				AllowedPodNumber: 80,
   100  				ScalarResources:  map[v1.ResourceName]int64{"scalar.test/scalar1": 1, "hugepages-test": 2},
   101  			},
   102  		},
   103  	}
   104  
   105  	for i, test := range tests {
   106  		t.Run(fmt.Sprintf("case_%d", i), func(t *testing.T) {
   107  			r := test.resource.Clone()
   108  			// Modify the field to check if the result is a clone of the origin one.
   109  			test.resource.MilliCPU += 1000
   110  			if !reflect.DeepEqual(test.expected, r) {
   111  				t.Errorf("expected: %#v, got: %#v", test.expected, r)
   112  			}
   113  		})
   114  	}
   115  }
   116  
   117  func TestResourceAddScalar(t *testing.T) {
   118  	tests := []struct {
   119  		resource       *Resource
   120  		scalarName     v1.ResourceName
   121  		scalarQuantity int64
   122  		expected       *Resource
   123  	}{
   124  		{
   125  			resource:       &Resource{},
   126  			scalarName:     "scalar1",
   127  			scalarQuantity: 100,
   128  			expected: &Resource{
   129  				ScalarResources: map[v1.ResourceName]int64{"scalar1": 100},
   130  			},
   131  		},
   132  		{
   133  			resource: &Resource{
   134  				MilliCPU:         4,
   135  				Memory:           2000,
   136  				EphemeralStorage: 5000,
   137  				AllowedPodNumber: 80,
   138  				ScalarResources:  map[v1.ResourceName]int64{"hugepages-test": 2},
   139  			},
   140  			scalarName:     "scalar2",
   141  			scalarQuantity: 200,
   142  			expected: &Resource{
   143  				MilliCPU:         4,
   144  				Memory:           2000,
   145  				EphemeralStorage: 5000,
   146  				AllowedPodNumber: 80,
   147  				ScalarResources:  map[v1.ResourceName]int64{"hugepages-test": 2, "scalar2": 200},
   148  			},
   149  		},
   150  	}
   151  
   152  	for _, test := range tests {
   153  		t.Run(string(test.scalarName), func(t *testing.T) {
   154  			test.resource.AddScalar(test.scalarName, test.scalarQuantity)
   155  			if !reflect.DeepEqual(test.expected, test.resource) {
   156  				t.Errorf("expected: %#v, got: %#v", test.expected, test.resource)
   157  			}
   158  		})
   159  	}
   160  }
   161  
   162  func TestSetMaxResource(t *testing.T) {
   163  	tests := []struct {
   164  		resource     *Resource
   165  		resourceList v1.ResourceList
   166  		expected     *Resource
   167  	}{
   168  		{
   169  			resource: &Resource{},
   170  			resourceList: map[v1.ResourceName]resource.Quantity{
   171  				v1.ResourceCPU:              *resource.NewScaledQuantity(4, -3),
   172  				v1.ResourceMemory:           *resource.NewQuantity(2000, resource.BinarySI),
   173  				v1.ResourceEphemeralStorage: *resource.NewQuantity(5000, resource.BinarySI),
   174  			},
   175  			expected: &Resource{
   176  				MilliCPU:         4,
   177  				Memory:           2000,
   178  				EphemeralStorage: 5000,
   179  			},
   180  		},
   181  		{
   182  			resource: &Resource{
   183  				MilliCPU:         4,
   184  				Memory:           4000,
   185  				EphemeralStorage: 5000,
   186  				ScalarResources:  map[v1.ResourceName]int64{"scalar.test/scalar1": 1, "hugepages-test": 2},
   187  			},
   188  			resourceList: map[v1.ResourceName]resource.Quantity{
   189  				v1.ResourceCPU:                      *resource.NewScaledQuantity(4, -3),
   190  				v1.ResourceMemory:                   *resource.NewQuantity(2000, resource.BinarySI),
   191  				v1.ResourceEphemeralStorage:         *resource.NewQuantity(7000, resource.BinarySI),
   192  				"scalar.test/scalar1":               *resource.NewQuantity(4, resource.DecimalSI),
   193  				v1.ResourceHugePagesPrefix + "test": *resource.NewQuantity(5, resource.BinarySI),
   194  			},
   195  			expected: &Resource{
   196  				MilliCPU:         4,
   197  				Memory:           4000,
   198  				EphemeralStorage: 7000,
   199  				ScalarResources:  map[v1.ResourceName]int64{"scalar.test/scalar1": 4, "hugepages-test": 5},
   200  			},
   201  		},
   202  	}
   203  
   204  	for i, test := range tests {
   205  		t.Run(fmt.Sprintf("case_%d", i), func(t *testing.T) {
   206  			test.resource.SetMaxResource(test.resourceList)
   207  			if !reflect.DeepEqual(test.expected, test.resource) {
   208  				t.Errorf("expected: %#v, got: %#v", test.expected, test.resource)
   209  			}
   210  		})
   211  	}
   212  }
   213  
   214  func TestNewNodeInfo(t *testing.T) {
   215  	nodeName := "test-node"
   216  	pods := []*v1.Pod{
   217  		st.MakePod().UID("test-1").Namespace("node_info_cache_test").Name("test-1").Node(nodeName).
   218  			Containers([]v1.Container{st.MakeContainer().ResourceRequests(map[v1.ResourceName]string{
   219  				v1.ResourceCPU:    "100m",
   220  				v1.ResourceMemory: "500",
   221  			}).ContainerPort([]v1.ContainerPort{{
   222  				HostIP:   "127.0.0.1",
   223  				HostPort: 80,
   224  				Protocol: "TCP",
   225  			}}).Obj()}).
   226  			Obj(),
   227  
   228  		st.MakePod().UID("test-2").Namespace("node_info_cache_test").Name("test-2").Node(nodeName).
   229  			Containers([]v1.Container{st.MakeContainer().ResourceRequests(map[v1.ResourceName]string{
   230  				v1.ResourceCPU:    "200m",
   231  				v1.ResourceMemory: "1Ki",
   232  			}).ContainerPort([]v1.ContainerPort{{
   233  				HostIP:   "127.0.0.1",
   234  				HostPort: 8080,
   235  				Protocol: "TCP",
   236  			}}).Obj()}).
   237  			Obj(),
   238  	}
   239  
   240  	expected := &NodeInfo{
   241  		Requested: &Resource{
   242  			MilliCPU:         300,
   243  			Memory:           1524,
   244  			EphemeralStorage: 0,
   245  			AllowedPodNumber: 0,
   246  			ScalarResources:  map[v1.ResourceName]int64(nil),
   247  		},
   248  		NonZeroRequested: &Resource{
   249  			MilliCPU:         300,
   250  			Memory:           1524,
   251  			EphemeralStorage: 0,
   252  			AllowedPodNumber: 0,
   253  			ScalarResources:  map[v1.ResourceName]int64(nil),
   254  		},
   255  		Allocatable: &Resource{},
   256  		Generation:  2,
   257  		UsedPorts: HostPortInfo{
   258  			"127.0.0.1": map[ProtocolPort]struct{}{
   259  				{Protocol: "TCP", Port: 80}:   {},
   260  				{Protocol: "TCP", Port: 8080}: {},
   261  			},
   262  		},
   263  		ImageStates:  map[string]*ImageStateSummary{},
   264  		PVCRefCounts: map[string]int{},
   265  		Pods: []*PodInfo{
   266  			{
   267  				Pod: &v1.Pod{
   268  					ObjectMeta: metav1.ObjectMeta{
   269  						Namespace: "node_info_cache_test",
   270  						Name:      "test-1",
   271  						UID:       types.UID("test-1"),
   272  					},
   273  					Spec: v1.PodSpec{
   274  						Containers: []v1.Container{
   275  							{
   276  								Resources: v1.ResourceRequirements{
   277  									Requests: v1.ResourceList{
   278  										v1.ResourceCPU:    resource.MustParse("100m"),
   279  										v1.ResourceMemory: resource.MustParse("500"),
   280  									},
   281  								},
   282  								Ports: []v1.ContainerPort{
   283  									{
   284  										HostIP:   "127.0.0.1",
   285  										HostPort: 80,
   286  										Protocol: "TCP",
   287  									},
   288  								},
   289  							},
   290  						},
   291  						NodeName: nodeName,
   292  					},
   293  				},
   294  			},
   295  			{
   296  				Pod: &v1.Pod{
   297  					ObjectMeta: metav1.ObjectMeta{
   298  						Namespace: "node_info_cache_test",
   299  						Name:      "test-2",
   300  						UID:       types.UID("test-2"),
   301  					},
   302  					Spec: v1.PodSpec{
   303  						Containers: []v1.Container{
   304  							{
   305  								Resources: v1.ResourceRequirements{
   306  									Requests: v1.ResourceList{
   307  										v1.ResourceCPU:    resource.MustParse("200m"),
   308  										v1.ResourceMemory: resource.MustParse("1Ki"),
   309  									},
   310  								},
   311  								Ports: []v1.ContainerPort{
   312  									{
   313  										HostIP:   "127.0.0.1",
   314  										HostPort: 8080,
   315  										Protocol: "TCP",
   316  									},
   317  								},
   318  							},
   319  						},
   320  						NodeName: nodeName,
   321  					},
   322  				},
   323  			},
   324  		},
   325  	}
   326  
   327  	gen := generation
   328  	ni := NewNodeInfo(pods...)
   329  	if ni.Generation <= gen {
   330  		t.Errorf("Generation is not incremented. previous: %v, current: %v", gen, ni.Generation)
   331  	}
   332  	expected.Generation = ni.Generation
   333  	if !reflect.DeepEqual(expected, ni) {
   334  		t.Errorf("expected: %#v, got: %#v", expected, ni)
   335  	}
   336  }
   337  
   338  func TestNodeInfoClone(t *testing.T) {
   339  	nodeName := "test-node"
   340  	tests := []struct {
   341  		nodeInfo *NodeInfo
   342  		expected *NodeInfo
   343  	}{
   344  		{
   345  			nodeInfo: &NodeInfo{
   346  				Requested:        &Resource{},
   347  				NonZeroRequested: &Resource{},
   348  				Allocatable:      &Resource{},
   349  				Generation:       2,
   350  				UsedPorts: HostPortInfo{
   351  					"127.0.0.1": map[ProtocolPort]struct{}{
   352  						{Protocol: "TCP", Port: 80}:   {},
   353  						{Protocol: "TCP", Port: 8080}: {},
   354  					},
   355  				},
   356  				ImageStates:  map[string]*ImageStateSummary{},
   357  				PVCRefCounts: map[string]int{},
   358  				Pods: []*PodInfo{
   359  					{
   360  						Pod: &v1.Pod{
   361  							ObjectMeta: metav1.ObjectMeta{
   362  								Namespace: "node_info_cache_test",
   363  								Name:      "test-1",
   364  								UID:       types.UID("test-1"),
   365  							},
   366  							Spec: v1.PodSpec{
   367  								Containers: []v1.Container{
   368  									{
   369  										Resources: v1.ResourceRequirements{
   370  											Requests: v1.ResourceList{
   371  												v1.ResourceCPU:    resource.MustParse("100m"),
   372  												v1.ResourceMemory: resource.MustParse("500"),
   373  											},
   374  										},
   375  										Ports: []v1.ContainerPort{
   376  											{
   377  												HostIP:   "127.0.0.1",
   378  												HostPort: 80,
   379  												Protocol: "TCP",
   380  											},
   381  										},
   382  									},
   383  								},
   384  								NodeName: nodeName,
   385  							},
   386  						},
   387  					},
   388  					{
   389  						Pod: &v1.Pod{
   390  							ObjectMeta: metav1.ObjectMeta{
   391  								Namespace: "node_info_cache_test",
   392  								Name:      "test-2",
   393  								UID:       types.UID("test-2"),
   394  							},
   395  							Spec: v1.PodSpec{
   396  								Containers: []v1.Container{
   397  									{
   398  										Resources: v1.ResourceRequirements{
   399  											Requests: v1.ResourceList{
   400  												v1.ResourceCPU:    resource.MustParse("200m"),
   401  												v1.ResourceMemory: resource.MustParse("1Ki"),
   402  											},
   403  										},
   404  										Ports: []v1.ContainerPort{
   405  											{
   406  												HostIP:   "127.0.0.1",
   407  												HostPort: 8080,
   408  												Protocol: "TCP",
   409  											},
   410  										},
   411  									},
   412  								},
   413  								NodeName: nodeName,
   414  							},
   415  						},
   416  					},
   417  				},
   418  			},
   419  			expected: &NodeInfo{
   420  				Requested:        &Resource{},
   421  				NonZeroRequested: &Resource{},
   422  				Allocatable:      &Resource{},
   423  				Generation:       2,
   424  				UsedPorts: HostPortInfo{
   425  					"127.0.0.1": map[ProtocolPort]struct{}{
   426  						{Protocol: "TCP", Port: 80}:   {},
   427  						{Protocol: "TCP", Port: 8080}: {},
   428  					},
   429  				},
   430  				ImageStates:  map[string]*ImageStateSummary{},
   431  				PVCRefCounts: map[string]int{},
   432  				Pods: []*PodInfo{
   433  					{
   434  						Pod: &v1.Pod{
   435  							ObjectMeta: metav1.ObjectMeta{
   436  								Namespace: "node_info_cache_test",
   437  								Name:      "test-1",
   438  								UID:       types.UID("test-1"),
   439  							},
   440  							Spec: v1.PodSpec{
   441  								Containers: []v1.Container{
   442  									{
   443  										Resources: v1.ResourceRequirements{
   444  											Requests: v1.ResourceList{
   445  												v1.ResourceCPU:    resource.MustParse("100m"),
   446  												v1.ResourceMemory: resource.MustParse("500"),
   447  											},
   448  										},
   449  										Ports: []v1.ContainerPort{
   450  											{
   451  												HostIP:   "127.0.0.1",
   452  												HostPort: 80,
   453  												Protocol: "TCP",
   454  											},
   455  										},
   456  									},
   457  								},
   458  								NodeName: nodeName,
   459  							},
   460  						},
   461  					},
   462  					{
   463  						Pod: &v1.Pod{
   464  							ObjectMeta: metav1.ObjectMeta{
   465  								Namespace: "node_info_cache_test",
   466  								Name:      "test-2",
   467  								UID:       types.UID("test-2"),
   468  							},
   469  							Spec: v1.PodSpec{
   470  								Containers: []v1.Container{
   471  									{
   472  										Resources: v1.ResourceRequirements{
   473  											Requests: v1.ResourceList{
   474  												v1.ResourceCPU:    resource.MustParse("200m"),
   475  												v1.ResourceMemory: resource.MustParse("1Ki"),
   476  											},
   477  										},
   478  										Ports: []v1.ContainerPort{
   479  											{
   480  												HostIP:   "127.0.0.1",
   481  												HostPort: 8080,
   482  												Protocol: "TCP",
   483  											},
   484  										},
   485  									},
   486  								},
   487  								NodeName: nodeName,
   488  							},
   489  						},
   490  					},
   491  				},
   492  			},
   493  		},
   494  	}
   495  
   496  	for i, test := range tests {
   497  		t.Run(fmt.Sprintf("case_%d", i), func(t *testing.T) {
   498  			ni := test.nodeInfo.Snapshot()
   499  			// Modify the field to check if the result is a clone of the origin one.
   500  			test.nodeInfo.Generation += 10
   501  			test.nodeInfo.UsedPorts.Remove("127.0.0.1", "TCP", 80)
   502  			if !reflect.DeepEqual(test.expected, ni) {
   503  				t.Errorf("expected: %#v, got: %#v", test.expected, ni)
   504  			}
   505  		})
   506  	}
   507  }
   508  
   509  func TestNodeInfoAddPod(t *testing.T) {
   510  	nodeName := "test-node"
   511  	pods := []*v1.Pod{
   512  		{
   513  			ObjectMeta: metav1.ObjectMeta{
   514  				Namespace: "node_info_cache_test",
   515  				Name:      "test-1",
   516  				UID:       types.UID("test-1"),
   517  			},
   518  			Spec: v1.PodSpec{
   519  				Containers: []v1.Container{
   520  					{
   521  						Resources: v1.ResourceRequirements{
   522  							Requests: v1.ResourceList{
   523  								v1.ResourceCPU:    resource.MustParse("100m"),
   524  								v1.ResourceMemory: resource.MustParse("500"),
   525  							},
   526  						},
   527  						Ports: []v1.ContainerPort{
   528  							{
   529  								HostIP:   "127.0.0.1",
   530  								HostPort: 80,
   531  								Protocol: "TCP",
   532  							},
   533  						},
   534  					},
   535  				},
   536  				NodeName: nodeName,
   537  				Overhead: v1.ResourceList{
   538  					v1.ResourceCPU: resource.MustParse("500m"),
   539  				},
   540  				Volumes: []v1.Volume{
   541  					{
   542  						VolumeSource: v1.VolumeSource{
   543  							PersistentVolumeClaim: &v1.PersistentVolumeClaimVolumeSource{
   544  								ClaimName: "pvc-1",
   545  							},
   546  						},
   547  					},
   548  				},
   549  			},
   550  		},
   551  		{
   552  			ObjectMeta: metav1.ObjectMeta{
   553  				Namespace: "node_info_cache_test",
   554  				Name:      "test-2",
   555  				UID:       types.UID("test-2"),
   556  			},
   557  			Spec: v1.PodSpec{
   558  				Containers: []v1.Container{
   559  					{
   560  						Resources: v1.ResourceRequirements{
   561  							Requests: v1.ResourceList{
   562  								v1.ResourceCPU: resource.MustParse("200m"),
   563  							},
   564  						},
   565  						Ports: []v1.ContainerPort{
   566  							{
   567  								HostIP:   "127.0.0.1",
   568  								HostPort: 8080,
   569  								Protocol: "TCP",
   570  							},
   571  						},
   572  					},
   573  				},
   574  				NodeName: nodeName,
   575  				Overhead: v1.ResourceList{
   576  					v1.ResourceCPU:    resource.MustParse("500m"),
   577  					v1.ResourceMemory: resource.MustParse("500"),
   578  				},
   579  				Volumes: []v1.Volume{
   580  					{
   581  						VolumeSource: v1.VolumeSource{
   582  							PersistentVolumeClaim: &v1.PersistentVolumeClaimVolumeSource{
   583  								ClaimName: "pvc-1",
   584  							},
   585  						},
   586  					},
   587  				},
   588  			},
   589  		},
   590  		{
   591  			ObjectMeta: metav1.ObjectMeta{
   592  				Namespace: "node_info_cache_test",
   593  				Name:      "test-3",
   594  				UID:       types.UID("test-3"),
   595  			},
   596  			Spec: v1.PodSpec{
   597  				Containers: []v1.Container{
   598  					{
   599  						Resources: v1.ResourceRequirements{
   600  							Requests: v1.ResourceList{
   601  								v1.ResourceCPU: resource.MustParse("200m"),
   602  							},
   603  						},
   604  						Ports: []v1.ContainerPort{
   605  							{
   606  								HostIP:   "127.0.0.1",
   607  								HostPort: 8080,
   608  								Protocol: "TCP",
   609  							},
   610  						},
   611  					},
   612  				},
   613  				InitContainers: []v1.Container{
   614  					{
   615  						Resources: v1.ResourceRequirements{
   616  							Requests: v1.ResourceList{
   617  								v1.ResourceCPU:    resource.MustParse("500m"),
   618  								v1.ResourceMemory: resource.MustParse("200Mi"),
   619  							},
   620  						},
   621  					},
   622  				},
   623  				NodeName: nodeName,
   624  				Overhead: v1.ResourceList{
   625  					v1.ResourceCPU:    resource.MustParse("500m"),
   626  					v1.ResourceMemory: resource.MustParse("500"),
   627  				},
   628  				Volumes: []v1.Volume{
   629  					{
   630  						VolumeSource: v1.VolumeSource{
   631  							PersistentVolumeClaim: &v1.PersistentVolumeClaimVolumeSource{
   632  								ClaimName: "pvc-2",
   633  							},
   634  						},
   635  					},
   636  				},
   637  			},
   638  		},
   639  	}
   640  	expected := &NodeInfo{
   641  		node: &v1.Node{
   642  			ObjectMeta: metav1.ObjectMeta{
   643  				Name: "test-node",
   644  			},
   645  		},
   646  		Requested: &Resource{
   647  			MilliCPU:         2300,
   648  			Memory:           209716700, //1500 + 200MB in initContainers
   649  			EphemeralStorage: 0,
   650  			AllowedPodNumber: 0,
   651  			ScalarResources:  map[v1.ResourceName]int64(nil),
   652  		},
   653  		NonZeroRequested: &Resource{
   654  			MilliCPU:         2300,
   655  			Memory:           419431900, //200MB(initContainers) + 200MB(default memory value) + 1500 specified in requests/overhead
   656  			EphemeralStorage: 0,
   657  			AllowedPodNumber: 0,
   658  			ScalarResources:  map[v1.ResourceName]int64(nil),
   659  		},
   660  		Allocatable: &Resource{},
   661  		Generation:  2,
   662  		UsedPorts: HostPortInfo{
   663  			"127.0.0.1": map[ProtocolPort]struct{}{
   664  				{Protocol: "TCP", Port: 80}:   {},
   665  				{Protocol: "TCP", Port: 8080}: {},
   666  			},
   667  		},
   668  		ImageStates:  map[string]*ImageStateSummary{},
   669  		PVCRefCounts: map[string]int{"node_info_cache_test/pvc-1": 2, "node_info_cache_test/pvc-2": 1},
   670  		Pods: []*PodInfo{
   671  			{
   672  				Pod: &v1.Pod{
   673  					ObjectMeta: metav1.ObjectMeta{
   674  						Namespace: "node_info_cache_test",
   675  						Name:      "test-1",
   676  						UID:       types.UID("test-1"),
   677  					},
   678  					Spec: v1.PodSpec{
   679  						Containers: []v1.Container{
   680  							{
   681  								Resources: v1.ResourceRequirements{
   682  									Requests: v1.ResourceList{
   683  										v1.ResourceCPU:    resource.MustParse("100m"),
   684  										v1.ResourceMemory: resource.MustParse("500"),
   685  									},
   686  								},
   687  								Ports: []v1.ContainerPort{
   688  									{
   689  										HostIP:   "127.0.0.1",
   690  										HostPort: 80,
   691  										Protocol: "TCP",
   692  									},
   693  								},
   694  							},
   695  						},
   696  						NodeName: nodeName,
   697  						Overhead: v1.ResourceList{
   698  							v1.ResourceCPU: resource.MustParse("500m"),
   699  						},
   700  						Volumes: []v1.Volume{
   701  							{
   702  								VolumeSource: v1.VolumeSource{
   703  									PersistentVolumeClaim: &v1.PersistentVolumeClaimVolumeSource{
   704  										ClaimName: "pvc-1",
   705  									},
   706  								},
   707  							},
   708  						},
   709  					},
   710  				},
   711  			},
   712  			{
   713  				Pod: &v1.Pod{
   714  					ObjectMeta: metav1.ObjectMeta{
   715  						Namespace: "node_info_cache_test",
   716  						Name:      "test-2",
   717  						UID:       types.UID("test-2"),
   718  					},
   719  					Spec: v1.PodSpec{
   720  						Containers: []v1.Container{
   721  							{
   722  								Resources: v1.ResourceRequirements{
   723  									Requests: v1.ResourceList{
   724  										v1.ResourceCPU: resource.MustParse("200m"),
   725  									},
   726  								},
   727  								Ports: []v1.ContainerPort{
   728  									{
   729  										HostIP:   "127.0.0.1",
   730  										HostPort: 8080,
   731  										Protocol: "TCP",
   732  									},
   733  								},
   734  							},
   735  						},
   736  						NodeName: nodeName,
   737  						Overhead: v1.ResourceList{
   738  							v1.ResourceCPU:    resource.MustParse("500m"),
   739  							v1.ResourceMemory: resource.MustParse("500"),
   740  						},
   741  						Volumes: []v1.Volume{
   742  							{
   743  								VolumeSource: v1.VolumeSource{
   744  									PersistentVolumeClaim: &v1.PersistentVolumeClaimVolumeSource{
   745  										ClaimName: "pvc-1",
   746  									},
   747  								},
   748  							},
   749  						},
   750  					},
   751  				},
   752  			},
   753  			{
   754  				Pod: &v1.Pod{
   755  					ObjectMeta: metav1.ObjectMeta{
   756  						Namespace: "node_info_cache_test",
   757  						Name:      "test-3",
   758  						UID:       types.UID("test-3"),
   759  					},
   760  					Spec: v1.PodSpec{
   761  						Containers: []v1.Container{
   762  							{
   763  								Resources: v1.ResourceRequirements{
   764  									Requests: v1.ResourceList{
   765  										v1.ResourceCPU: resource.MustParse("200m"),
   766  									},
   767  								},
   768  								Ports: []v1.ContainerPort{
   769  									{
   770  										HostIP:   "127.0.0.1",
   771  										HostPort: 8080,
   772  										Protocol: "TCP",
   773  									},
   774  								},
   775  							},
   776  						},
   777  						InitContainers: []v1.Container{
   778  							{
   779  								Resources: v1.ResourceRequirements{
   780  									Requests: v1.ResourceList{
   781  										v1.ResourceCPU:    resource.MustParse("500m"),
   782  										v1.ResourceMemory: resource.MustParse("200Mi"),
   783  									},
   784  								},
   785  							},
   786  						},
   787  						NodeName: nodeName,
   788  						Overhead: v1.ResourceList{
   789  							v1.ResourceCPU:    resource.MustParse("500m"),
   790  							v1.ResourceMemory: resource.MustParse("500"),
   791  						},
   792  						Volumes: []v1.Volume{
   793  							{
   794  								VolumeSource: v1.VolumeSource{
   795  									PersistentVolumeClaim: &v1.PersistentVolumeClaimVolumeSource{
   796  										ClaimName: "pvc-2",
   797  									},
   798  								},
   799  							},
   800  						},
   801  					},
   802  				},
   803  			},
   804  		},
   805  	}
   806  
   807  	ni := fakeNodeInfo()
   808  	gen := ni.Generation
   809  	for _, pod := range pods {
   810  		ni.AddPod(pod)
   811  		if ni.Generation <= gen {
   812  			t.Errorf("Generation is not incremented. Prev: %v, current: %v", gen, ni.Generation)
   813  		}
   814  		gen = ni.Generation
   815  	}
   816  
   817  	expected.Generation = ni.Generation
   818  	if !reflect.DeepEqual(expected, ni) {
   819  		t.Errorf("expected: %#v, got: %#v", expected, ni)
   820  	}
   821  }
   822  
   823  func TestNodeInfoRemovePod(t *testing.T) {
   824  	nodeName := "test-node"
   825  	pods := []*v1.Pod{
   826  		st.MakePod().UID("test-1").Namespace("node_info_cache_test").Name("test-1").Node(nodeName).
   827  			Containers([]v1.Container{st.MakeContainer().ResourceRequests(map[v1.ResourceName]string{
   828  				v1.ResourceCPU:    "100m",
   829  				v1.ResourceMemory: "500",
   830  			}).ContainerPort([]v1.ContainerPort{{
   831  				HostIP:   "127.0.0.1",
   832  				HostPort: 80,
   833  				Protocol: "TCP",
   834  			}}).Obj()}).
   835  			Volumes([]v1.Volume{{VolumeSource: v1.VolumeSource{PersistentVolumeClaim: &v1.PersistentVolumeClaimVolumeSource{ClaimName: "pvc-1"}}}}).
   836  			Obj(),
   837  
   838  		st.MakePod().UID("test-2").Namespace("node_info_cache_test").Name("test-2").Node(nodeName).
   839  			Containers([]v1.Container{st.MakeContainer().ResourceRequests(map[v1.ResourceName]string{
   840  				v1.ResourceCPU:    "200m",
   841  				v1.ResourceMemory: "1Ki",
   842  			}).ContainerPort([]v1.ContainerPort{{
   843  				HostIP:   "127.0.0.1",
   844  				HostPort: 8080,
   845  				Protocol: "TCP",
   846  			}}).Obj()}).
   847  			Obj(),
   848  	}
   849  
   850  	// add pod Overhead
   851  	for _, pod := range pods {
   852  		pod.Spec.Overhead = v1.ResourceList{
   853  			v1.ResourceCPU:    resource.MustParse("500m"),
   854  			v1.ResourceMemory: resource.MustParse("500"),
   855  		}
   856  	}
   857  
   858  	tests := []struct {
   859  		pod              *v1.Pod
   860  		errExpected      bool
   861  		expectedNodeInfo *NodeInfo
   862  	}{
   863  		{
   864  			pod:         st.MakePod().UID("non-exist").Namespace("node_info_cache_test").Node(nodeName).Obj(),
   865  			errExpected: true,
   866  			expectedNodeInfo: &NodeInfo{
   867  				node: &v1.Node{
   868  					ObjectMeta: metav1.ObjectMeta{
   869  						Name: "test-node",
   870  					},
   871  				},
   872  				Requested: &Resource{
   873  					MilliCPU:         1300,
   874  					Memory:           2524,
   875  					EphemeralStorage: 0,
   876  					AllowedPodNumber: 0,
   877  					ScalarResources:  map[v1.ResourceName]int64(nil),
   878  				},
   879  				NonZeroRequested: &Resource{
   880  					MilliCPU:         1300,
   881  					Memory:           2524,
   882  					EphemeralStorage: 0,
   883  					AllowedPodNumber: 0,
   884  					ScalarResources:  map[v1.ResourceName]int64(nil),
   885  				},
   886  				Allocatable: &Resource{},
   887  				Generation:  2,
   888  				UsedPorts: HostPortInfo{
   889  					"127.0.0.1": map[ProtocolPort]struct{}{
   890  						{Protocol: "TCP", Port: 80}:   {},
   891  						{Protocol: "TCP", Port: 8080}: {},
   892  					},
   893  				},
   894  				ImageStates:  map[string]*ImageStateSummary{},
   895  				PVCRefCounts: map[string]int{"node_info_cache_test/pvc-1": 1},
   896  				Pods: []*PodInfo{
   897  					{
   898  						Pod: &v1.Pod{
   899  							ObjectMeta: metav1.ObjectMeta{
   900  								Namespace: "node_info_cache_test",
   901  								Name:      "test-1",
   902  								UID:       types.UID("test-1"),
   903  							},
   904  							Spec: v1.PodSpec{
   905  								Containers: []v1.Container{
   906  									{
   907  										Resources: v1.ResourceRequirements{
   908  											Requests: v1.ResourceList{
   909  												v1.ResourceCPU:    resource.MustParse("100m"),
   910  												v1.ResourceMemory: resource.MustParse("500"),
   911  											},
   912  										},
   913  										Ports: []v1.ContainerPort{
   914  											{
   915  												HostIP:   "127.0.0.1",
   916  												HostPort: 80,
   917  												Protocol: "TCP",
   918  											},
   919  										},
   920  									},
   921  								},
   922  								NodeName: nodeName,
   923  								Overhead: v1.ResourceList{
   924  									v1.ResourceCPU:    resource.MustParse("500m"),
   925  									v1.ResourceMemory: resource.MustParse("500"),
   926  								},
   927  								Volumes: []v1.Volume{
   928  									{
   929  										VolumeSource: v1.VolumeSource{
   930  											PersistentVolumeClaim: &v1.PersistentVolumeClaimVolumeSource{
   931  												ClaimName: "pvc-1",
   932  											},
   933  										},
   934  									},
   935  								},
   936  							},
   937  						},
   938  					},
   939  					{
   940  						Pod: &v1.Pod{
   941  							ObjectMeta: metav1.ObjectMeta{
   942  								Namespace: "node_info_cache_test",
   943  								Name:      "test-2",
   944  								UID:       types.UID("test-2"),
   945  							},
   946  							Spec: v1.PodSpec{
   947  								Containers: []v1.Container{
   948  									{
   949  										Resources: v1.ResourceRequirements{
   950  											Requests: v1.ResourceList{
   951  												v1.ResourceCPU:    resource.MustParse("200m"),
   952  												v1.ResourceMemory: resource.MustParse("1Ki"),
   953  											},
   954  										},
   955  										Ports: []v1.ContainerPort{
   956  											{
   957  												HostIP:   "127.0.0.1",
   958  												HostPort: 8080,
   959  												Protocol: "TCP",
   960  											},
   961  										},
   962  									},
   963  								},
   964  								NodeName: nodeName,
   965  								Overhead: v1.ResourceList{
   966  									v1.ResourceCPU:    resource.MustParse("500m"),
   967  									v1.ResourceMemory: resource.MustParse("500"),
   968  								},
   969  							},
   970  						},
   971  					},
   972  				},
   973  			},
   974  		},
   975  		{
   976  			pod: &v1.Pod{
   977  				ObjectMeta: metav1.ObjectMeta{
   978  					Namespace: "node_info_cache_test",
   979  					Name:      "test-1",
   980  					UID:       types.UID("test-1"),
   981  				},
   982  				Spec: v1.PodSpec{
   983  					Containers: []v1.Container{
   984  						{
   985  							Resources: v1.ResourceRequirements{
   986  								Requests: v1.ResourceList{
   987  									v1.ResourceCPU:    resource.MustParse("100m"),
   988  									v1.ResourceMemory: resource.MustParse("500"),
   989  								},
   990  							},
   991  							Ports: []v1.ContainerPort{
   992  								{
   993  									HostIP:   "127.0.0.1",
   994  									HostPort: 80,
   995  									Protocol: "TCP",
   996  								},
   997  							},
   998  						},
   999  					},
  1000  					NodeName: nodeName,
  1001  					Overhead: v1.ResourceList{
  1002  						v1.ResourceCPU:    resource.MustParse("500m"),
  1003  						v1.ResourceMemory: resource.MustParse("500"),
  1004  					},
  1005  					Volumes: []v1.Volume{
  1006  						{
  1007  							VolumeSource: v1.VolumeSource{
  1008  								PersistentVolumeClaim: &v1.PersistentVolumeClaimVolumeSource{
  1009  									ClaimName: "pvc-1",
  1010  								},
  1011  							},
  1012  						},
  1013  					},
  1014  				},
  1015  			},
  1016  			errExpected: false,
  1017  			expectedNodeInfo: &NodeInfo{
  1018  				node: &v1.Node{
  1019  					ObjectMeta: metav1.ObjectMeta{
  1020  						Name: "test-node",
  1021  					},
  1022  				},
  1023  				Requested: &Resource{
  1024  					MilliCPU:         700,
  1025  					Memory:           1524,
  1026  					EphemeralStorage: 0,
  1027  					AllowedPodNumber: 0,
  1028  					ScalarResources:  map[v1.ResourceName]int64(nil),
  1029  				},
  1030  				NonZeroRequested: &Resource{
  1031  					MilliCPU:         700,
  1032  					Memory:           1524,
  1033  					EphemeralStorage: 0,
  1034  					AllowedPodNumber: 0,
  1035  					ScalarResources:  map[v1.ResourceName]int64(nil),
  1036  				},
  1037  				Allocatable: &Resource{},
  1038  				Generation:  3,
  1039  				UsedPorts: HostPortInfo{
  1040  					"127.0.0.1": map[ProtocolPort]struct{}{
  1041  						{Protocol: "TCP", Port: 8080}: {},
  1042  					},
  1043  				},
  1044  				ImageStates:  map[string]*ImageStateSummary{},
  1045  				PVCRefCounts: map[string]int{},
  1046  				Pods: []*PodInfo{
  1047  					{
  1048  						Pod: &v1.Pod{
  1049  							ObjectMeta: metav1.ObjectMeta{
  1050  								Namespace: "node_info_cache_test",
  1051  								Name:      "test-2",
  1052  								UID:       types.UID("test-2"),
  1053  							},
  1054  							Spec: v1.PodSpec{
  1055  								Containers: []v1.Container{
  1056  									{
  1057  										Resources: v1.ResourceRequirements{
  1058  											Requests: v1.ResourceList{
  1059  												v1.ResourceCPU:    resource.MustParse("200m"),
  1060  												v1.ResourceMemory: resource.MustParse("1Ki"),
  1061  											},
  1062  										},
  1063  										Ports: []v1.ContainerPort{
  1064  											{
  1065  												HostIP:   "127.0.0.1",
  1066  												HostPort: 8080,
  1067  												Protocol: "TCP",
  1068  											},
  1069  										},
  1070  									},
  1071  								},
  1072  								NodeName: nodeName,
  1073  								Overhead: v1.ResourceList{
  1074  									v1.ResourceCPU:    resource.MustParse("500m"),
  1075  									v1.ResourceMemory: resource.MustParse("500"),
  1076  								},
  1077  							},
  1078  						},
  1079  					},
  1080  				},
  1081  			},
  1082  		},
  1083  	}
  1084  
  1085  	for i, test := range tests {
  1086  		t.Run(fmt.Sprintf("case_%d", i), func(t *testing.T) {
  1087  			logger, _ := ktesting.NewTestContext(t)
  1088  			ni := fakeNodeInfo(pods...)
  1089  
  1090  			gen := ni.Generation
  1091  			err := ni.RemovePod(logger, test.pod)
  1092  			if err != nil {
  1093  				if test.errExpected {
  1094  					expectedErrorMsg := fmt.Errorf("no corresponding pod %s in pods of node %s", test.pod.Name, ni.Node().Name)
  1095  					if expectedErrorMsg == err {
  1096  						t.Errorf("expected error: %v, got: %v", expectedErrorMsg, err)
  1097  					}
  1098  				} else {
  1099  					t.Errorf("expected no error, got: %v", err)
  1100  				}
  1101  			} else {
  1102  				if ni.Generation <= gen {
  1103  					t.Errorf("Generation is not incremented. Prev: %v, current: %v", gen, ni.Generation)
  1104  				}
  1105  			}
  1106  
  1107  			test.expectedNodeInfo.Generation = ni.Generation
  1108  			if !reflect.DeepEqual(test.expectedNodeInfo, ni) {
  1109  				t.Errorf("expected: %#v, got: %#v", test.expectedNodeInfo, ni)
  1110  			}
  1111  		})
  1112  	}
  1113  }
  1114  
  1115  func fakeNodeInfo(pods ...*v1.Pod) *NodeInfo {
  1116  	ni := NewNodeInfo(pods...)
  1117  	ni.SetNode(&v1.Node{
  1118  		ObjectMeta: metav1.ObjectMeta{
  1119  			Name: "test-node",
  1120  		},
  1121  	})
  1122  	return ni
  1123  }
  1124  
  1125  type hostPortInfoParam struct {
  1126  	protocol, ip string
  1127  	port         int32
  1128  }
  1129  
  1130  func TestHostPortInfo_AddRemove(t *testing.T) {
  1131  	tests := []struct {
  1132  		desc    string
  1133  		added   []hostPortInfoParam
  1134  		removed []hostPortInfoParam
  1135  		length  int
  1136  	}{
  1137  		{
  1138  			desc: "normal add case",
  1139  			added: []hostPortInfoParam{
  1140  				{"TCP", "127.0.0.1", 79},
  1141  				{"UDP", "127.0.0.1", 80},
  1142  				{"TCP", "127.0.0.1", 81},
  1143  				{"TCP", "127.0.0.1", 82},
  1144  				// this might not make sense in real case, but the struct doesn't forbid it.
  1145  				{"TCP", "0.0.0.0", 79},
  1146  				{"UDP", "0.0.0.0", 80},
  1147  				{"TCP", "0.0.0.0", 81},
  1148  				{"TCP", "0.0.0.0", 82},
  1149  				{"TCP", "0.0.0.0", 0},
  1150  				{"TCP", "0.0.0.0", -1},
  1151  			},
  1152  			length: 8,
  1153  		},
  1154  		{
  1155  			desc: "empty ip and protocol add should work",
  1156  			added: []hostPortInfoParam{
  1157  				{"", "127.0.0.1", 79},
  1158  				{"UDP", "127.0.0.1", 80},
  1159  				{"", "127.0.0.1", 81},
  1160  				{"", "127.0.0.1", 82},
  1161  				{"", "", 79},
  1162  				{"UDP", "", 80},
  1163  				{"", "", 81},
  1164  				{"", "", 82},
  1165  				{"", "", 0},
  1166  				{"", "", -1},
  1167  			},
  1168  			length: 8,
  1169  		},
  1170  		{
  1171  			desc: "normal remove case",
  1172  			added: []hostPortInfoParam{
  1173  				{"TCP", "127.0.0.1", 79},
  1174  				{"UDP", "127.0.0.1", 80},
  1175  				{"TCP", "127.0.0.1", 81},
  1176  				{"TCP", "127.0.0.1", 82},
  1177  				{"TCP", "0.0.0.0", 79},
  1178  				{"UDP", "0.0.0.0", 80},
  1179  				{"TCP", "0.0.0.0", 81},
  1180  				{"TCP", "0.0.0.0", 82},
  1181  			},
  1182  			removed: []hostPortInfoParam{
  1183  				{"TCP", "127.0.0.1", 79},
  1184  				{"UDP", "127.0.0.1", 80},
  1185  				{"TCP", "127.0.0.1", 81},
  1186  				{"TCP", "127.0.0.1", 82},
  1187  				{"TCP", "0.0.0.0", 79},
  1188  				{"UDP", "0.0.0.0", 80},
  1189  				{"TCP", "0.0.0.0", 81},
  1190  				{"TCP", "0.0.0.0", 82},
  1191  			},
  1192  			length: 0,
  1193  		},
  1194  		{
  1195  			desc: "empty ip and protocol remove should work",
  1196  			added: []hostPortInfoParam{
  1197  				{"TCP", "127.0.0.1", 79},
  1198  				{"UDP", "127.0.0.1", 80},
  1199  				{"TCP", "127.0.0.1", 81},
  1200  				{"TCP", "127.0.0.1", 82},
  1201  				{"TCP", "0.0.0.0", 79},
  1202  				{"UDP", "0.0.0.0", 80},
  1203  				{"TCP", "0.0.0.0", 81},
  1204  				{"TCP", "0.0.0.0", 82},
  1205  			},
  1206  			removed: []hostPortInfoParam{
  1207  				{"", "127.0.0.1", 79},
  1208  				{"", "127.0.0.1", 81},
  1209  				{"", "127.0.0.1", 82},
  1210  				{"UDP", "127.0.0.1", 80},
  1211  				{"", "", 79},
  1212  				{"", "", 81},
  1213  				{"", "", 82},
  1214  				{"UDP", "", 80},
  1215  			},
  1216  			length: 0,
  1217  		},
  1218  	}
  1219  
  1220  	for _, test := range tests {
  1221  		t.Run(test.desc, func(t *testing.T) {
  1222  			hp := make(HostPortInfo)
  1223  			for _, param := range test.added {
  1224  				hp.Add(param.ip, param.protocol, param.port)
  1225  			}
  1226  			for _, param := range test.removed {
  1227  				hp.Remove(param.ip, param.protocol, param.port)
  1228  			}
  1229  			if hp.Len() != test.length {
  1230  				t.Errorf("%v failed: expect length %d; got %d", test.desc, test.length, hp.Len())
  1231  				t.Error(hp)
  1232  			}
  1233  		})
  1234  	}
  1235  }
  1236  
  1237  func TestHostPortInfo_Check(t *testing.T) {
  1238  	tests := []struct {
  1239  		desc   string
  1240  		added  []hostPortInfoParam
  1241  		check  hostPortInfoParam
  1242  		expect bool
  1243  	}{
  1244  		{
  1245  			desc: "empty check should check 0.0.0.0 and TCP",
  1246  			added: []hostPortInfoParam{
  1247  				{"TCP", "127.0.0.1", 80},
  1248  			},
  1249  			check:  hostPortInfoParam{"", "", 81},
  1250  			expect: false,
  1251  		},
  1252  		{
  1253  			desc: "empty check should check 0.0.0.0 and TCP (conflicted)",
  1254  			added: []hostPortInfoParam{
  1255  				{"TCP", "127.0.0.1", 80},
  1256  			},
  1257  			check:  hostPortInfoParam{"", "", 80},
  1258  			expect: true,
  1259  		},
  1260  		{
  1261  			desc: "empty port check should pass",
  1262  			added: []hostPortInfoParam{
  1263  				{"TCP", "127.0.0.1", 80},
  1264  			},
  1265  			check:  hostPortInfoParam{"", "", 0},
  1266  			expect: false,
  1267  		},
  1268  		{
  1269  			desc: "0.0.0.0 should check all registered IPs",
  1270  			added: []hostPortInfoParam{
  1271  				{"TCP", "127.0.0.1", 80},
  1272  			},
  1273  			check:  hostPortInfoParam{"TCP", "0.0.0.0", 80},
  1274  			expect: true,
  1275  		},
  1276  		{
  1277  			desc: "0.0.0.0 with different protocol should be allowed",
  1278  			added: []hostPortInfoParam{
  1279  				{"UDP", "127.0.0.1", 80},
  1280  			},
  1281  			check:  hostPortInfoParam{"TCP", "0.0.0.0", 80},
  1282  			expect: false,
  1283  		},
  1284  		{
  1285  			desc: "0.0.0.0 with different port should be allowed",
  1286  			added: []hostPortInfoParam{
  1287  				{"TCP", "127.0.0.1", 79},
  1288  				{"TCP", "127.0.0.1", 81},
  1289  				{"TCP", "127.0.0.1", 82},
  1290  			},
  1291  			check:  hostPortInfoParam{"TCP", "0.0.0.0", 80},
  1292  			expect: false,
  1293  		},
  1294  		{
  1295  			desc: "normal ip should check all registered 0.0.0.0",
  1296  			added: []hostPortInfoParam{
  1297  				{"TCP", "0.0.0.0", 80},
  1298  			},
  1299  			check:  hostPortInfoParam{"TCP", "127.0.0.1", 80},
  1300  			expect: true,
  1301  		},
  1302  		{
  1303  			desc: "normal ip with different port/protocol should be allowed (0.0.0.0)",
  1304  			added: []hostPortInfoParam{
  1305  				{"TCP", "0.0.0.0", 79},
  1306  				{"UDP", "0.0.0.0", 80},
  1307  				{"TCP", "0.0.0.0", 81},
  1308  				{"TCP", "0.0.0.0", 82},
  1309  			},
  1310  			check:  hostPortInfoParam{"TCP", "127.0.0.1", 80},
  1311  			expect: false,
  1312  		},
  1313  		{
  1314  			desc: "normal ip with different port/protocol should be allowed",
  1315  			added: []hostPortInfoParam{
  1316  				{"TCP", "127.0.0.1", 79},
  1317  				{"UDP", "127.0.0.1", 80},
  1318  				{"TCP", "127.0.0.1", 81},
  1319  				{"TCP", "127.0.0.1", 82},
  1320  			},
  1321  			check:  hostPortInfoParam{"TCP", "127.0.0.1", 80},
  1322  			expect: false,
  1323  		},
  1324  	}
  1325  
  1326  	for _, test := range tests {
  1327  		t.Run(test.desc, func(t *testing.T) {
  1328  			hp := make(HostPortInfo)
  1329  			for _, param := range test.added {
  1330  				hp.Add(param.ip, param.protocol, param.port)
  1331  			}
  1332  			if hp.CheckConflict(test.check.ip, test.check.protocol, test.check.port) != test.expect {
  1333  				t.Errorf("expected %t; got %t", test.expect, !test.expect)
  1334  			}
  1335  		})
  1336  	}
  1337  }
  1338  
  1339  func TestGetNamespacesFromPodAffinityTerm(t *testing.T) {
  1340  	tests := []struct {
  1341  		name string
  1342  		term *v1.PodAffinityTerm
  1343  		want sets.Set[string]
  1344  	}{
  1345  		{
  1346  			name: "podAffinityTerm_namespace_empty",
  1347  			term: &v1.PodAffinityTerm{},
  1348  			want: sets.Set[string]{metav1.NamespaceDefault: sets.Empty{}},
  1349  		},
  1350  		{
  1351  			name: "podAffinityTerm_namespace_not_empty",
  1352  			term: &v1.PodAffinityTerm{
  1353  				Namespaces: []string{metav1.NamespacePublic, metav1.NamespaceSystem},
  1354  			},
  1355  			want: sets.New(metav1.NamespacePublic, metav1.NamespaceSystem),
  1356  		},
  1357  		{
  1358  			name: "podAffinityTerm_namespace_selector_not_nil",
  1359  			term: &v1.PodAffinityTerm{
  1360  				NamespaceSelector: &metav1.LabelSelector{},
  1361  			},
  1362  			want: sets.Set[string]{},
  1363  		},
  1364  	}
  1365  
  1366  	for _, test := range tests {
  1367  		t.Run(test.name, func(t *testing.T) {
  1368  			got := getNamespacesFromPodAffinityTerm(&v1.Pod{
  1369  				ObjectMeta: metav1.ObjectMeta{
  1370  					Name:      "topologies_pod",
  1371  					Namespace: metav1.NamespaceDefault,
  1372  				},
  1373  			}, test.term)
  1374  			if diff := cmp.Diff(test.want, got); diff != "" {
  1375  				t.Errorf("unexpected diff (-want, +got):\n%s", diff)
  1376  			}
  1377  		})
  1378  	}
  1379  }
  1380  
  1381  func TestFitError_Error(t *testing.T) {
  1382  	tests := []struct {
  1383  		name          string
  1384  		pod           *v1.Pod
  1385  		numAllNodes   int
  1386  		diagnosis     Diagnosis
  1387  		wantReasonMsg string
  1388  	}{
  1389  		{
  1390  			name:        "nodes failed Prefilter plugin",
  1391  			numAllNodes: 3,
  1392  			diagnosis: Diagnosis{
  1393  				PreFilterMsg: "Node(s) failed PreFilter plugin FalsePreFilter",
  1394  				NodeToStatusMap: NodeToStatusMap{
  1395  					// They're inserted by the framework.
  1396  					// We don't include them in the reason message because they'd be just duplicates.
  1397  					"node1": NewStatus(Unschedulable, "Node(s) failed PreFilter plugin FalsePreFilter"),
  1398  					"node2": NewStatus(Unschedulable, "Node(s) failed PreFilter plugin FalsePreFilter"),
  1399  					"node3": NewStatus(Unschedulable, "Node(s) failed PreFilter plugin FalsePreFilter"),
  1400  				},
  1401  			},
  1402  			wantReasonMsg: "0/3 nodes are available: Node(s) failed PreFilter plugin FalsePreFilter.",
  1403  		},
  1404  		{
  1405  			name:        "nodes failed Prefilter plugin and the preemption also failed",
  1406  			numAllNodes: 3,
  1407  			diagnosis: Diagnosis{
  1408  				PreFilterMsg: "Node(s) failed PreFilter plugin FalsePreFilter",
  1409  				NodeToStatusMap: NodeToStatusMap{
  1410  					// They're inserted by the framework.
  1411  					// We don't include them in the reason message because they'd be just duplicates.
  1412  					"node1": NewStatus(Unschedulable, "Node(s) failed PreFilter plugin FalsePreFilter"),
  1413  					"node2": NewStatus(Unschedulable, "Node(s) failed PreFilter plugin FalsePreFilter"),
  1414  					"node3": NewStatus(Unschedulable, "Node(s) failed PreFilter plugin FalsePreFilter"),
  1415  				},
  1416  				// PostFilterMsg will be included.
  1417  				PostFilterMsg: "Error running PostFilter plugin FailedPostFilter",
  1418  			},
  1419  			wantReasonMsg: "0/3 nodes are available: Node(s) failed PreFilter plugin FalsePreFilter. Error running PostFilter plugin FailedPostFilter",
  1420  		},
  1421  		{
  1422  			name:        "nodes failed one Filter plugin with an empty PostFilterMsg",
  1423  			numAllNodes: 3,
  1424  			diagnosis: Diagnosis{
  1425  				PreFilterMsg: "",
  1426  				NodeToStatusMap: NodeToStatusMap{
  1427  					"node1": NewStatus(Unschedulable, "Node(s) failed Filter plugin FalseFilter-1"),
  1428  					"node2": NewStatus(Unschedulable, "Node(s) failed Filter plugin FalseFilter-1"),
  1429  					"node3": NewStatus(Unschedulable, "Node(s) failed Filter plugin FalseFilter-1"),
  1430  				},
  1431  			},
  1432  			wantReasonMsg: "0/3 nodes are available: 3 Node(s) failed Filter plugin FalseFilter-1.",
  1433  		},
  1434  		{
  1435  			name:        "nodes failed one Filter plugin with a non-empty PostFilterMsg",
  1436  			numAllNodes: 3,
  1437  			diagnosis: Diagnosis{
  1438  				PreFilterMsg: "",
  1439  				NodeToStatusMap: NodeToStatusMap{
  1440  					"node1": NewStatus(Unschedulable, "Node(s) failed Filter plugin FalseFilter-1"),
  1441  					"node2": NewStatus(Unschedulable, "Node(s) failed Filter plugin FalseFilter-1"),
  1442  					"node3": NewStatus(Unschedulable, "Node(s) failed Filter plugin FalseFilter-1"),
  1443  				},
  1444  				PostFilterMsg: "Error running PostFilter plugin FailedPostFilter",
  1445  			},
  1446  			wantReasonMsg: "0/3 nodes are available: 3 Node(s) failed Filter plugin FalseFilter-1. Error running PostFilter plugin FailedPostFilter",
  1447  		},
  1448  		{
  1449  			name:        "nodes failed two Filter plugins with an empty PostFilterMsg",
  1450  			numAllNodes: 3,
  1451  			diagnosis: Diagnosis{
  1452  				PreFilterMsg: "",
  1453  				NodeToStatusMap: NodeToStatusMap{
  1454  					"node1": NewStatus(Unschedulable, "Node(s) failed Filter plugin FalseFilter-1"),
  1455  					"node2": NewStatus(Unschedulable, "Node(s) failed Filter plugin FalseFilter-1"),
  1456  					"node3": NewStatus(Unschedulable, "Node(s) failed Filter plugin FalseFilter-2"),
  1457  				},
  1458  			},
  1459  			wantReasonMsg: "0/3 nodes are available: 1 Node(s) failed Filter plugin FalseFilter-2, 2 Node(s) failed Filter plugin FalseFilter-1.",
  1460  		},
  1461  		{
  1462  			name:        "nodes failed two Filter plugins with a non-empty PostFilterMsg",
  1463  			numAllNodes: 3,
  1464  			diagnosis: Diagnosis{
  1465  				PreFilterMsg: "",
  1466  				NodeToStatusMap: NodeToStatusMap{
  1467  					"node1": NewStatus(Unschedulable, "Node(s) failed Filter plugin FalseFilter-1"),
  1468  					"node2": NewStatus(Unschedulable, "Node(s) failed Filter plugin FalseFilter-1"),
  1469  					"node3": NewStatus(Unschedulable, "Node(s) failed Filter plugin FalseFilter-2"),
  1470  				},
  1471  				PostFilterMsg: "Error running PostFilter plugin FailedPostFilter",
  1472  			},
  1473  			wantReasonMsg: "0/3 nodes are available: 1 Node(s) failed Filter plugin FalseFilter-2, 2 Node(s) failed Filter plugin FalseFilter-1. Error running PostFilter plugin FailedPostFilter",
  1474  		},
  1475  		{
  1476  			name:        "failed to Permit on node",
  1477  			numAllNodes: 1,
  1478  			diagnosis: Diagnosis{
  1479  				NodeToStatusMap: NodeToStatusMap{
  1480  					// There should be only one node here.
  1481  					"node1": NewStatus(Unschedulable, "Node failed Permit plugin Permit-1"),
  1482  				},
  1483  			},
  1484  			wantReasonMsg: "0/1 nodes are available: 1 Node failed Permit plugin Permit-1.",
  1485  		},
  1486  		{
  1487  			name:        "failed to Reserve on node",
  1488  			numAllNodes: 1,
  1489  			diagnosis: Diagnosis{
  1490  				NodeToStatusMap: NodeToStatusMap{
  1491  					// There should be only one node here.
  1492  					"node1": NewStatus(Unschedulable, "Node failed Reserve plugin Reserve-1"),
  1493  				},
  1494  			},
  1495  			wantReasonMsg: "0/1 nodes are available: 1 Node failed Reserve plugin Reserve-1.",
  1496  		},
  1497  	}
  1498  	for _, tt := range tests {
  1499  		t.Run(tt.name, func(t *testing.T) {
  1500  			f := &FitError{
  1501  				Pod:         tt.pod,
  1502  				NumAllNodes: tt.numAllNodes,
  1503  				Diagnosis:   tt.diagnosis,
  1504  			}
  1505  			if gotReasonMsg := f.Error(); gotReasonMsg != tt.wantReasonMsg {
  1506  				t.Errorf("Error() = Got: %v Want: %v", gotReasonMsg, tt.wantReasonMsg)
  1507  			}
  1508  		})
  1509  	}
  1510  }
  1511  
  1512  func TestCalculatePodResourcesWithResize(t *testing.T) {
  1513  	defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.InPlacePodVerticalScaling, true)()
  1514  	cpu500m := resource.MustParse("500m")
  1515  	mem500M := resource.MustParse("500Mi")
  1516  	cpu700m := resource.MustParse("700m")
  1517  	mem800M := resource.MustParse("800Mi")
  1518  	testpod := v1.Pod{
  1519  		ObjectMeta: metav1.ObjectMeta{
  1520  			Namespace: "pod_resize_test",
  1521  			Name:      "testpod",
  1522  			UID:       types.UID("testpod"),
  1523  		},
  1524  		Spec: v1.PodSpec{
  1525  			Containers: []v1.Container{
  1526  				{
  1527  					Name:      "c1",
  1528  					Resources: v1.ResourceRequirements{Requests: v1.ResourceList{v1.ResourceCPU: cpu500m, v1.ResourceMemory: mem500M}},
  1529  				},
  1530  			},
  1531  		},
  1532  		Status: v1.PodStatus{
  1533  			Phase:  v1.PodRunning,
  1534  			Resize: "",
  1535  			ContainerStatuses: []v1.ContainerStatus{
  1536  				{
  1537  					Name:               "c1",
  1538  					AllocatedResources: v1.ResourceList{v1.ResourceCPU: cpu500m, v1.ResourceMemory: mem500M},
  1539  				},
  1540  			},
  1541  		},
  1542  	}
  1543  
  1544  	tests := []struct {
  1545  		name               string
  1546  		requests           v1.ResourceList
  1547  		allocatedResources v1.ResourceList
  1548  		resizeStatus       v1.PodResizeStatus
  1549  		expectedResource   Resource
  1550  		expectedNon0CPU    int64
  1551  		expectedNon0Mem    int64
  1552  	}{
  1553  		{
  1554  			name:               "Pod with no pending resize",
  1555  			requests:           v1.ResourceList{v1.ResourceCPU: cpu500m, v1.ResourceMemory: mem500M},
  1556  			allocatedResources: v1.ResourceList{v1.ResourceCPU: cpu500m, v1.ResourceMemory: mem500M},
  1557  			resizeStatus:       "",
  1558  			expectedResource:   Resource{MilliCPU: cpu500m.MilliValue(), Memory: mem500M.Value()},
  1559  			expectedNon0CPU:    cpu500m.MilliValue(),
  1560  			expectedNon0Mem:    mem500M.Value(),
  1561  		},
  1562  		{
  1563  			name:               "Pod with resize in progress",
  1564  			requests:           v1.ResourceList{v1.ResourceCPU: cpu500m, v1.ResourceMemory: mem500M},
  1565  			allocatedResources: v1.ResourceList{v1.ResourceCPU: cpu500m, v1.ResourceMemory: mem500M},
  1566  			resizeStatus:       v1.PodResizeStatusInProgress,
  1567  			expectedResource:   Resource{MilliCPU: cpu500m.MilliValue(), Memory: mem500M.Value()},
  1568  			expectedNon0CPU:    cpu500m.MilliValue(),
  1569  			expectedNon0Mem:    mem500M.Value(),
  1570  		},
  1571  		{
  1572  			name:               "Pod with deferred resize",
  1573  			requests:           v1.ResourceList{v1.ResourceCPU: cpu700m, v1.ResourceMemory: mem800M},
  1574  			allocatedResources: v1.ResourceList{v1.ResourceCPU: cpu500m, v1.ResourceMemory: mem500M},
  1575  			resizeStatus:       v1.PodResizeStatusDeferred,
  1576  			expectedResource:   Resource{MilliCPU: cpu700m.MilliValue(), Memory: mem800M.Value()},
  1577  			expectedNon0CPU:    cpu700m.MilliValue(),
  1578  			expectedNon0Mem:    mem800M.Value(),
  1579  		},
  1580  		{
  1581  			name:               "Pod with infeasible resize",
  1582  			requests:           v1.ResourceList{v1.ResourceCPU: cpu700m, v1.ResourceMemory: mem800M},
  1583  			allocatedResources: v1.ResourceList{v1.ResourceCPU: cpu500m, v1.ResourceMemory: mem500M},
  1584  			resizeStatus:       v1.PodResizeStatusInfeasible,
  1585  			expectedResource:   Resource{MilliCPU: cpu500m.MilliValue(), Memory: mem500M.Value()},
  1586  			expectedNon0CPU:    cpu500m.MilliValue(),
  1587  			expectedNon0Mem:    mem500M.Value(),
  1588  		},
  1589  	}
  1590  
  1591  	for _, tt := range tests {
  1592  		t.Run(tt.name, func(t *testing.T) {
  1593  			pod := testpod.DeepCopy()
  1594  			pod.Spec.Containers[0].Resources.Requests = tt.requests
  1595  			pod.Status.ContainerStatuses[0].AllocatedResources = tt.allocatedResources
  1596  			pod.Status.Resize = tt.resizeStatus
  1597  
  1598  			res, non0CPU, non0Mem := calculateResource(pod)
  1599  			if !reflect.DeepEqual(tt.expectedResource, res) {
  1600  				t.Errorf("Test: %s expected resource: %+v, got: %+v", tt.name, tt.expectedResource, res)
  1601  			}
  1602  			if non0CPU != tt.expectedNon0CPU {
  1603  				t.Errorf("Test: %s expected non0CPU: %d, got: %d", tt.name, tt.expectedNon0CPU, non0CPU)
  1604  			}
  1605  			if non0Mem != tt.expectedNon0Mem {
  1606  				t.Errorf("Test: %s expected non0Mem: %d, got: %d", tt.name, tt.expectedNon0Mem, non0Mem)
  1607  			}
  1608  		})
  1609  	}
  1610  }