k8s.io/kubernetes@v1.29.3/pkg/scheduler/metrics/resources/resources_test.go (about)

     1  /*
     2  Copyright 2020 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  // Package resources provides a metrics collector that reports the
    18  // resource consumption (requests and limits) of the pods in the cluster
    19  // as the scheduler and kubelet would interpret it.
    20  package resources
    21  
    22  import (
    23  	"net/http"
    24  	"net/http/httptest"
    25  	"strings"
    26  	"testing"
    27  
    28  	v1 "k8s.io/api/core/v1"
    29  	"k8s.io/apimachinery/pkg/api/resource"
    30  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    31  	"k8s.io/apimachinery/pkg/labels"
    32  	corelisters "k8s.io/client-go/listers/core/v1"
    33  	"k8s.io/component-base/metrics"
    34  	"k8s.io/component-base/metrics/testutil"
    35  	"k8s.io/utils/ptr"
    36  )
    37  
    38  type fakePodLister struct {
    39  	pods []*v1.Pod
    40  }
    41  
    42  func (l *fakePodLister) List(selector labels.Selector) (ret []*v1.Pod, err error) {
    43  	return l.pods, nil
    44  }
    45  
    46  func (l *fakePodLister) Pods(namespace string) corelisters.PodNamespaceLister {
    47  	panic("not implemented")
    48  }
    49  
    50  func Test_podResourceCollector_Handler(t *testing.T) {
    51  	h := Handler(&fakePodLister{pods: []*v1.Pod{
    52  		{
    53  			ObjectMeta: metav1.ObjectMeta{Namespace: "test", Name: "foo"},
    54  			Spec: v1.PodSpec{
    55  				NodeName: "node-one",
    56  				InitContainers: []v1.Container{
    57  					{Resources: v1.ResourceRequirements{
    58  						Requests: v1.ResourceList{
    59  							"cpu":    resource.MustParse("2"),
    60  							"custom": resource.MustParse("3"),
    61  						},
    62  						Limits: v1.ResourceList{
    63  							"memory": resource.MustParse("1G"),
    64  							"custom": resource.MustParse("5"),
    65  						},
    66  					}},
    67  				},
    68  				Containers: []v1.Container{
    69  					{Resources: v1.ResourceRequirements{
    70  						Requests: v1.ResourceList{
    71  							"cpu":    resource.MustParse("1"),
    72  							"custom": resource.MustParse("0"),
    73  						},
    74  						Limits: v1.ResourceList{
    75  							"memory": resource.MustParse("2.5Gi"),
    76  							"custom": resource.MustParse("6"),
    77  						},
    78  					}},
    79  				},
    80  			},
    81  			Status: v1.PodStatus{
    82  				Conditions: []v1.PodCondition{
    83  					{Type: v1.PodInitialized, Status: v1.ConditionTrue},
    84  				},
    85  			},
    86  		},
    87  	}})
    88  
    89  	r := httptest.NewRecorder()
    90  	req, err := http.NewRequest("GET", "/metrics/resources", nil)
    91  	if err != nil {
    92  		t.Fatal(err)
    93  	}
    94  	h.ServeHTTP(r, req)
    95  
    96  	expected := `# HELP kube_pod_resource_limit [STABLE] Resources limit for workloads on the cluster, broken down by pod. This shows the resource usage the scheduler and kubelet expect per pod for resources along with the unit for the resource if any.
    97  # TYPE kube_pod_resource_limit gauge
    98  kube_pod_resource_limit{namespace="test",node="node-one",pod="foo",priority="",resource="custom",scheduler="",unit=""} 6
    99  kube_pod_resource_limit{namespace="test",node="node-one",pod="foo",priority="",resource="memory",scheduler="",unit="bytes"} 2.68435456e+09
   100  # HELP kube_pod_resource_request [STABLE] Resources requested by workloads on the cluster, broken down by pod. This shows the resource usage the scheduler and kubelet expect per pod for resources along with the unit for the resource if any.
   101  # TYPE kube_pod_resource_request gauge
   102  kube_pod_resource_request{namespace="test",node="node-one",pod="foo",priority="",resource="cpu",scheduler="",unit="cores"} 2
   103  kube_pod_resource_request{namespace="test",node="node-one",pod="foo",priority="",resource="custom",scheduler="",unit=""} 3
   104  `
   105  	out := r.Body.String()
   106  	if expected != out {
   107  		t.Fatal(out)
   108  	}
   109  }
   110  
   111  func Test_podResourceCollector_CollectWithStability(t *testing.T) {
   112  	tests := []struct {
   113  		name string
   114  
   115  		pods     []*v1.Pod
   116  		expected string
   117  	}{
   118  		{},
   119  		{
   120  			name: "no containers",
   121  			pods: []*v1.Pod{
   122  				{
   123  					ObjectMeta: metav1.ObjectMeta{Namespace: "test", Name: "foo"},
   124  				},
   125  			},
   126  		},
   127  		{
   128  			name: "no resources",
   129  			pods: []*v1.Pod{
   130  				{
   131  					ObjectMeta: metav1.ObjectMeta{Namespace: "test", Name: "foo"},
   132  					Spec: v1.PodSpec{
   133  						InitContainers: []v1.Container{},
   134  						Containers:     []v1.Container{},
   135  					},
   136  				},
   137  			},
   138  		},
   139  		{
   140  			name: "request only",
   141  			pods: []*v1.Pod{
   142  				{
   143  					ObjectMeta: metav1.ObjectMeta{Namespace: "test", Name: "foo"},
   144  					Spec: v1.PodSpec{
   145  						Containers: []v1.Container{
   146  							{Resources: v1.ResourceRequirements{Requests: v1.ResourceList{"cpu": resource.MustParse("1")}}},
   147  						},
   148  					},
   149  				},
   150  			},
   151  			expected: `
   152  				# HELP kube_pod_resource_request [STABLE] Resources requested by workloads on the cluster, broken down by pod. This shows the resource usage the scheduler and kubelet expect per pod for resources along with the unit for the resource if any.
   153  				# TYPE kube_pod_resource_request gauge
   154  				kube_pod_resource_request{namespace="test",node="",pod="foo",priority="",resource="cpu",scheduler="",unit="cores"} 1
   155  				`,
   156  		},
   157  		{
   158  			name: "limits only",
   159  			pods: []*v1.Pod{
   160  				{
   161  					ObjectMeta: metav1.ObjectMeta{Namespace: "test", Name: "foo"},
   162  					Spec: v1.PodSpec{
   163  						Containers: []v1.Container{
   164  							{Resources: v1.ResourceRequirements{Limits: v1.ResourceList{"cpu": resource.MustParse("1")}}},
   165  						},
   166  					},
   167  				},
   168  			},
   169  			expected: `      
   170  				# HELP kube_pod_resource_limit [STABLE] Resources limit for workloads on the cluster, broken down by pod. This shows the resource usage the scheduler and kubelet expect per pod for resources along with the unit for the resource if any.
   171  				# TYPE kube_pod_resource_limit gauge
   172  				kube_pod_resource_limit{namespace="test",node="",pod="foo",priority="",resource="cpu",scheduler="",unit="cores"} 1
   173  				`,
   174  		},
   175  		{
   176  			name: "terminal pods are excluded",
   177  			pods: []*v1.Pod{
   178  				{
   179  					ObjectMeta: metav1.ObjectMeta{Namespace: "test", Name: "foo-unscheduled-succeeded"},
   180  					Spec: v1.PodSpec{
   181  						Containers: []v1.Container{
   182  							{Resources: v1.ResourceRequirements{Requests: v1.ResourceList{"cpu": resource.MustParse("1")}}},
   183  						},
   184  					},
   185  					// until node name is set, phase is ignored
   186  					Status: v1.PodStatus{Phase: v1.PodSucceeded},
   187  				},
   188  				{
   189  					ObjectMeta: metav1.ObjectMeta{Namespace: "test", Name: "foo-succeeded"},
   190  					Spec: v1.PodSpec{
   191  						NodeName: "node-one",
   192  						Containers: []v1.Container{
   193  							{Resources: v1.ResourceRequirements{Requests: v1.ResourceList{"cpu": resource.MustParse("1")}}},
   194  						},
   195  					},
   196  					Status: v1.PodStatus{Phase: v1.PodSucceeded},
   197  				},
   198  				{
   199  					ObjectMeta: metav1.ObjectMeta{Namespace: "test", Name: "foo-failed"},
   200  					Spec: v1.PodSpec{
   201  						NodeName: "node-one",
   202  						Containers: []v1.Container{
   203  							{Resources: v1.ResourceRequirements{Requests: v1.ResourceList{"cpu": resource.MustParse("1")}}},
   204  						},
   205  					},
   206  					Status: v1.PodStatus{Phase: v1.PodFailed},
   207  				},
   208  				{
   209  					ObjectMeta: metav1.ObjectMeta{Namespace: "test", Name: "foo-unknown"},
   210  					Spec: v1.PodSpec{
   211  						NodeName: "node-one",
   212  						Containers: []v1.Container{
   213  							{Resources: v1.ResourceRequirements{Requests: v1.ResourceList{"cpu": resource.MustParse("1")}}},
   214  						},
   215  					},
   216  					Status: v1.PodStatus{Phase: v1.PodUnknown},
   217  				},
   218  				{
   219  					ObjectMeta: metav1.ObjectMeta{Namespace: "test", Name: "foo-pending"},
   220  					Spec: v1.PodSpec{
   221  						NodeName: "node-one",
   222  						InitContainers: []v1.Container{
   223  							{Resources: v1.ResourceRequirements{Requests: v1.ResourceList{"cpu": resource.MustParse("1")}}},
   224  						},
   225  						Containers: []v1.Container{
   226  							{Resources: v1.ResourceRequirements{Requests: v1.ResourceList{"cpu": resource.MustParse("1")}}},
   227  						},
   228  					},
   229  					Status: v1.PodStatus{
   230  						Phase: v1.PodPending,
   231  						Conditions: []v1.PodCondition{
   232  							{Type: "ArbitraryCondition", Status: v1.ConditionTrue},
   233  						},
   234  					},
   235  				},
   236  			},
   237  			expected: `
   238  				# HELP kube_pod_resource_request [STABLE] Resources requested by workloads on the cluster, broken down by pod. This shows the resource usage the scheduler and kubelet expect per pod for resources along with the unit for the resource if any.
   239  				# TYPE kube_pod_resource_request gauge
   240  				kube_pod_resource_request{namespace="test",node="",pod="foo-unscheduled-succeeded",priority="",resource="cpu",scheduler="",unit="cores"} 1
   241  				kube_pod_resource_request{namespace="test",node="node-one",pod="foo-pending",priority="",resource="cpu",scheduler="",unit="cores"} 1
   242  				kube_pod_resource_request{namespace="test",node="node-one",pod="foo-unknown",priority="",resource="cpu",scheduler="",unit="cores"} 1
   243  				`,
   244  		},
   245  		{
   246  			name: "zero resource should be excluded",
   247  			pods: []*v1.Pod{
   248  				{
   249  					ObjectMeta: metav1.ObjectMeta{Namespace: "test", Name: "foo"},
   250  					Spec: v1.PodSpec{
   251  						InitContainers: []v1.Container{
   252  							{Resources: v1.ResourceRequirements{
   253  								Requests: v1.ResourceList{
   254  									"cpu":                    resource.MustParse("0"),
   255  									"custom":                 resource.MustParse("0"),
   256  									"test.com/custom-metric": resource.MustParse("0"),
   257  								},
   258  								Limits: v1.ResourceList{
   259  									"cpu":                    resource.MustParse("0"),
   260  									"custom":                 resource.MustParse("0"),
   261  									"test.com/custom-metric": resource.MustParse("0"),
   262  								},
   263  							}},
   264  						},
   265  						Containers: []v1.Container{
   266  							{Resources: v1.ResourceRequirements{
   267  								Requests: v1.ResourceList{
   268  									"cpu":                    resource.MustParse("0"),
   269  									"custom":                 resource.MustParse("0"),
   270  									"test.com/custom-metric": resource.MustParse("0"),
   271  								},
   272  								Limits: v1.ResourceList{
   273  									"cpu":                    resource.MustParse("0"),
   274  									"custom":                 resource.MustParse("0"),
   275  									"test.com/custom-metric": resource.MustParse("0"),
   276  								},
   277  							}},
   278  						},
   279  					},
   280  				},
   281  			},
   282  			expected: ``,
   283  		},
   284  		{
   285  			name: "optional field labels",
   286  			pods: []*v1.Pod{
   287  				{
   288  					ObjectMeta: metav1.ObjectMeta{Namespace: "test", Name: "foo"},
   289  					Spec: v1.PodSpec{
   290  						SchedulerName: "default-scheduler",
   291  						Priority:      ptr.To[int32](0),
   292  						NodeName:      "node-one",
   293  						Containers: []v1.Container{
   294  							{Resources: v1.ResourceRequirements{Requests: v1.ResourceList{"cpu": resource.MustParse("1")}}},
   295  						},
   296  					},
   297  				},
   298  			},
   299  			expected: `
   300  				# HELP kube_pod_resource_request [STABLE] Resources requested by workloads on the cluster, broken down by pod. This shows the resource usage the scheduler and kubelet expect per pod for resources along with the unit for the resource if any.
   301  				# TYPE kube_pod_resource_request gauge
   302  				kube_pod_resource_request{namespace="test",node="node-one",pod="foo",priority="0",resource="cpu",scheduler="default-scheduler",unit="cores"} 1
   303  				`,
   304  		},
   305  		{
   306  			name: "init containers and regular containers when initialized",
   307  			pods: []*v1.Pod{
   308  				{
   309  					ObjectMeta: metav1.ObjectMeta{Namespace: "test", Name: "foo"},
   310  					Spec: v1.PodSpec{
   311  						NodeName: "node-one",
   312  						InitContainers: []v1.Container{
   313  							{Resources: v1.ResourceRequirements{
   314  								Requests: v1.ResourceList{
   315  									"cpu":    resource.MustParse("2"),
   316  									"custom": resource.MustParse("3"),
   317  								},
   318  								Limits: v1.ResourceList{
   319  									"memory": resource.MustParse("1G"),
   320  									"custom": resource.MustParse("5"),
   321  								},
   322  							}},
   323  						},
   324  						Containers: []v1.Container{
   325  							{Resources: v1.ResourceRequirements{
   326  								Requests: v1.ResourceList{
   327  									"cpu":    resource.MustParse("1"),
   328  									"custom": resource.MustParse("0"),
   329  								},
   330  								Limits: v1.ResourceList{
   331  									"memory": resource.MustParse("2G"),
   332  									"custom": resource.MustParse("6"),
   333  								},
   334  							}},
   335  						},
   336  					},
   337  					Status: v1.PodStatus{
   338  						Conditions: []v1.PodCondition{
   339  							{Type: v1.PodInitialized, Status: v1.ConditionTrue},
   340  						},
   341  					},
   342  				},
   343  			},
   344  			expected: `
   345  				# HELP kube_pod_resource_limit [STABLE] Resources limit for workloads on the cluster, broken down by pod. This shows the resource usage the scheduler and kubelet expect per pod for resources along with the unit for the resource if any.
   346  				# TYPE kube_pod_resource_limit gauge
   347  				kube_pod_resource_limit{namespace="test",node="node-one",pod="foo",priority="",resource="custom",scheduler="",unit=""} 6
   348  				kube_pod_resource_limit{namespace="test",node="node-one",pod="foo",priority="",resource="memory",scheduler="",unit="bytes"} 2e+09
   349  				# HELP kube_pod_resource_request [STABLE] Resources requested by workloads on the cluster, broken down by pod. This shows the resource usage the scheduler and kubelet expect per pod for resources along with the unit for the resource if any.
   350  				# TYPE kube_pod_resource_request gauge
   351  				kube_pod_resource_request{namespace="test",node="node-one",pod="foo",priority="",resource="cpu",scheduler="",unit="cores"} 2
   352  				kube_pod_resource_request{namespace="test",node="node-one",pod="foo",priority="",resource="custom",scheduler="",unit=""} 3
   353  				`,
   354  		},
   355  		{
   356  			name: "init containers and regular containers when initializing",
   357  			pods: []*v1.Pod{
   358  				{
   359  					ObjectMeta: metav1.ObjectMeta{Namespace: "test", Name: "foo"},
   360  					Spec: v1.PodSpec{
   361  						NodeName: "node-one",
   362  						InitContainers: []v1.Container{
   363  							{Resources: v1.ResourceRequirements{
   364  								Requests: v1.ResourceList{
   365  									"cpu":    resource.MustParse("2"),
   366  									"custom": resource.MustParse("3"),
   367  								},
   368  								Limits: v1.ResourceList{
   369  									"memory": resource.MustParse("1G"),
   370  									"custom": resource.MustParse("5"),
   371  								},
   372  							}},
   373  						},
   374  						Containers: []v1.Container{
   375  							{Resources: v1.ResourceRequirements{
   376  								Requests: v1.ResourceList{
   377  									"cpu":    resource.MustParse("1"),
   378  									"custom": resource.MustParse("0"),
   379  								},
   380  								Limits: v1.ResourceList{
   381  									"memory": resource.MustParse("2G"),
   382  									"custom": resource.MustParse("6"),
   383  								},
   384  							}},
   385  						},
   386  					},
   387  					Status: v1.PodStatus{
   388  						Conditions: []v1.PodCondition{
   389  							{Type: "AnotherCondition", Status: v1.ConditionUnknown},
   390  							{Type: v1.PodInitialized, Status: v1.ConditionFalse},
   391  						},
   392  					},
   393  				},
   394  			},
   395  			expected: `
   396  				# HELP kube_pod_resource_limit [STABLE] Resources limit for workloads on the cluster, broken down by pod. This shows the resource usage the scheduler and kubelet expect per pod for resources along with the unit for the resource if any.
   397  				# TYPE kube_pod_resource_limit gauge
   398  				kube_pod_resource_limit{namespace="test",node="node-one",pod="foo",priority="",resource="custom",scheduler="",unit=""} 6
   399  				kube_pod_resource_limit{namespace="test",node="node-one",pod="foo",priority="",resource="memory",scheduler="",unit="bytes"} 2e+09
   400  				# HELP kube_pod_resource_request [STABLE] Resources requested by workloads on the cluster, broken down by pod. This shows the resource usage the scheduler and kubelet expect per pod for resources along with the unit for the resource if any.
   401  				# TYPE kube_pod_resource_request gauge
   402  				kube_pod_resource_request{namespace="test",node="node-one",pod="foo",priority="",resource="cpu",scheduler="",unit="cores"} 2
   403  				kube_pod_resource_request{namespace="test",node="node-one",pod="foo",priority="",resource="custom",scheduler="",unit=""} 3
   404  				`,
   405  		},
   406  		{
   407  			name: "aggregate container requests and limits",
   408  			pods: []*v1.Pod{
   409  				{
   410  					ObjectMeta: metav1.ObjectMeta{Namespace: "test", Name: "foo"},
   411  					Spec: v1.PodSpec{
   412  						Containers: []v1.Container{
   413  							{Resources: v1.ResourceRequirements{
   414  								Requests: v1.ResourceList{"cpu": resource.MustParse("1")},
   415  								Limits:   v1.ResourceList{"cpu": resource.MustParse("2")},
   416  							}},
   417  							{Resources: v1.ResourceRequirements{
   418  								Requests: v1.ResourceList{"memory": resource.MustParse("1G")},
   419  								Limits:   v1.ResourceList{"memory": resource.MustParse("2G")},
   420  							}},
   421  							{Resources: v1.ResourceRequirements{
   422  								Requests: v1.ResourceList{"cpu": resource.MustParse("0.5")},
   423  								Limits:   v1.ResourceList{"cpu": resource.MustParse("1.25")},
   424  							}},
   425  							{Resources: v1.ResourceRequirements{
   426  								Limits: v1.ResourceList{"memory": resource.MustParse("2G")},
   427  							}},
   428  						},
   429  					},
   430  				},
   431  			},
   432  			expected: `            
   433  				# HELP kube_pod_resource_limit [STABLE] Resources limit for workloads on the cluster, broken down by pod. This shows the resource usage the scheduler and kubelet expect per pod for resources along with the unit for the resource if any.
   434  				# TYPE kube_pod_resource_limit gauge
   435  				kube_pod_resource_limit{namespace="test",node="",pod="foo",priority="",resource="cpu",scheduler="",unit="cores"} 3.25
   436  				kube_pod_resource_limit{namespace="test",node="",pod="foo",priority="",resource="memory",scheduler="",unit="bytes"} 4e+09
   437  				# HELP kube_pod_resource_request [STABLE] Resources requested by workloads on the cluster, broken down by pod. This shows the resource usage the scheduler and kubelet expect per pod for resources along with the unit for the resource if any.
   438  				# TYPE kube_pod_resource_request gauge
   439  				kube_pod_resource_request{namespace="test",node="",pod="foo",priority="",resource="cpu",scheduler="",unit="cores"} 1.5
   440  				kube_pod_resource_request{namespace="test",node="",pod="foo",priority="",resource="memory",scheduler="",unit="bytes"} 1e+09
   441  				`,
   442  		},
   443  		{
   444  			name: "overhead added to requests and limits",
   445  			pods: []*v1.Pod{
   446  				{
   447  					ObjectMeta: metav1.ObjectMeta{Namespace: "test", Name: "foo"},
   448  					Spec: v1.PodSpec{
   449  						Overhead: v1.ResourceList{
   450  							"cpu":    resource.MustParse("0.25"),
   451  							"memory": resource.MustParse("0.75G"),
   452  							"custom": resource.MustParse("0.5"),
   453  						},
   454  						InitContainers: []v1.Container{
   455  							{Resources: v1.ResourceRequirements{
   456  								Requests: v1.ResourceList{
   457  									"cpu":    resource.MustParse("2"),
   458  									"custom": resource.MustParse("3"),
   459  								},
   460  								Limits: v1.ResourceList{
   461  									"memory": resource.MustParse("1G"),
   462  									"custom": resource.MustParse("5"),
   463  								},
   464  							}},
   465  						},
   466  						Containers: []v1.Container{
   467  							{Resources: v1.ResourceRequirements{
   468  								Requests: v1.ResourceList{
   469  									"cpu":    resource.MustParse("1"),
   470  									"custom": resource.MustParse("0"),
   471  								},
   472  								Limits: v1.ResourceList{
   473  									"memory": resource.MustParse("2G"),
   474  									"custom": resource.MustParse("6"),
   475  								},
   476  							}},
   477  						},
   478  					},
   479  				},
   480  			},
   481  			expected: `
   482  				# HELP kube_pod_resource_limit [STABLE] Resources limit for workloads on the cluster, broken down by pod. This shows the resource usage the scheduler and kubelet expect per pod for resources along with the unit for the resource if any.
   483  				# TYPE kube_pod_resource_limit gauge
   484  				kube_pod_resource_limit{namespace="test",node="",pod="foo",priority="",resource="custom",scheduler="",unit=""} 6.5
   485  				kube_pod_resource_limit{namespace="test",node="",pod="foo",priority="",resource="memory",scheduler="",unit="bytes"} 2.75e+09
   486  				# HELP kube_pod_resource_request [STABLE] Resources requested by workloads on the cluster, broken down by pod. This shows the resource usage the scheduler and kubelet expect per pod for resources along with the unit for the resource if any.
   487  				# TYPE kube_pod_resource_request gauge
   488  				kube_pod_resource_request{namespace="test",node="",pod="foo",priority="",resource="cpu",scheduler="",unit="cores"} 2.25
   489  				kube_pod_resource_request{namespace="test",node="",pod="foo",priority="",resource="custom",scheduler="",unit=""} 3.5
   490  				kube_pod_resource_request{namespace="test",node="",pod="foo",priority="",resource="memory",scheduler="",unit="bytes"} 7.5e+08
   491  				`,
   492  		},
   493  		{
   494  			name: "units for standard resources",
   495  			pods: []*v1.Pod{
   496  				{
   497  					ObjectMeta: metav1.ObjectMeta{Namespace: "test", Name: "foo"},
   498  					Spec: v1.PodSpec{
   499  						Containers: []v1.Container{
   500  							{Resources: v1.ResourceRequirements{
   501  								Requests: v1.ResourceList{
   502  									"storage":           resource.MustParse("5"),
   503  									"ephemeral-storage": resource.MustParse("6"),
   504  								},
   505  								Limits: v1.ResourceList{
   506  									"hugepages-x":            resource.MustParse("1"),
   507  									"hugepages-":             resource.MustParse("2"),
   508  									"attachable-volumes-aws": resource.MustParse("3"),
   509  									"attachable-volumes-":    resource.MustParse("4"),
   510  								},
   511  							}},
   512  						},
   513  					},
   514  				},
   515  			},
   516  			expected: `
   517  				# HELP kube_pod_resource_limit [STABLE] Resources limit for workloads on the cluster, broken down by pod. This shows the resource usage the scheduler and kubelet expect per pod for resources along with the unit for the resource if any.
   518  				# TYPE kube_pod_resource_limit gauge
   519  				kube_pod_resource_limit{namespace="test",node="",pod="foo",priority="",resource="attachable-volumes-",scheduler="",unit="integer"} 4
   520  				kube_pod_resource_limit{namespace="test",node="",pod="foo",priority="",resource="attachable-volumes-aws",scheduler="",unit="integer"} 3
   521  				kube_pod_resource_limit{namespace="test",node="",pod="foo",priority="",resource="hugepages-",scheduler="",unit="bytes"} 2
   522  				kube_pod_resource_limit{namespace="test",node="",pod="foo",priority="",resource="hugepages-x",scheduler="",unit="bytes"} 1
   523  				# HELP kube_pod_resource_request [STABLE] Resources requested by workloads on the cluster, broken down by pod. This shows the resource usage the scheduler and kubelet expect per pod for resources along with the unit for the resource if any.
   524  				# TYPE kube_pod_resource_request gauge
   525  				kube_pod_resource_request{namespace="test",node="",pod="foo",priority="",resource="ephemeral-storage",scheduler="",unit="bytes"} 6
   526  				kube_pod_resource_request{namespace="test",node="",pod="foo",priority="",resource="storage",scheduler="",unit="bytes"} 5
   527  				`,
   528  		},
   529  	}
   530  	for _, tt := range tests {
   531  		t.Run(tt.name, func(t *testing.T) {
   532  			c := NewPodResourcesMetricsCollector(&fakePodLister{pods: tt.pods})
   533  			registry := metrics.NewKubeRegistry()
   534  			registry.CustomMustRegister(c)
   535  			err := testutil.GatherAndCompare(registry, strings.NewReader(tt.expected))
   536  			if err != nil {
   537  				t.Fatal(err)
   538  			}
   539  		})
   540  	}
   541  }