k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/pkg/scheduler/framework/plugins/noderesources/resource_allocation_test.go (about) 1 /* 2 Copyright 2023 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 noderesources 18 19 import ( 20 "testing" 21 22 v1 "k8s.io/api/core/v1" 23 "k8s.io/apimachinery/pkg/api/resource" 24 25 "k8s.io/kubernetes/pkg/scheduler/util" 26 ) 27 28 func TestResourceAllocationScorerCalculateRequests(t *testing.T) { 29 const oneMi = 1048576 30 tests := []struct { 31 name string 32 pod v1.Pod 33 expected map[v1.ResourceName]int64 34 }{ 35 { 36 name: "overhead only", 37 pod: v1.Pod{ 38 Spec: v1.PodSpec{ 39 Overhead: v1.ResourceList{ 40 v1.ResourceCPU: resource.MustParse("1"), 41 v1.ResourceMemory: resource.MustParse("1Mi"), 42 }, 43 }, 44 }, 45 expected: map[v1.ResourceName]int64{ 46 v1.ResourceCPU: 1000, 47 v1.ResourceMemory: oneMi, 48 }, 49 }, 50 { 51 name: "1x requestless container", 52 pod: v1.Pod{ 53 Spec: v1.PodSpec{ 54 Containers: []v1.Container{ 55 {}, 56 }, 57 }, 58 }, 59 expected: map[v1.ResourceName]int64{ 60 v1.ResourceCPU: util.DefaultMilliCPURequest, 61 v1.ResourceMemory: util.DefaultMemoryRequest, 62 }, 63 }, 64 { 65 name: "2x requestless container", 66 pod: v1.Pod{ 67 Spec: v1.PodSpec{ 68 Containers: []v1.Container{ 69 {}, {}, 70 }, 71 }, 72 }, 73 // should accumulate once per container without a request 74 expected: map[v1.ResourceName]int64{ 75 v1.ResourceCPU: 2 * util.DefaultMilliCPURequest, 76 v1.ResourceMemory: 2 * util.DefaultMemoryRequest, 77 }, 78 }, 79 { 80 name: "request container + requestless container", 81 pod: v1.Pod{ 82 Spec: v1.PodSpec{ 83 Containers: []v1.Container{ 84 { 85 Resources: v1.ResourceRequirements{ 86 Requests: v1.ResourceList{ 87 v1.ResourceCPU: resource.MustParse("1"), 88 v1.ResourceMemory: resource.MustParse("1Mi"), 89 }, 90 }, 91 }, 92 {}, 93 }, 94 }, 95 }, 96 expected: map[v1.ResourceName]int64{ 97 v1.ResourceCPU: 1000 + util.DefaultMilliCPURequest, 98 v1.ResourceMemory: oneMi + util.DefaultMemoryRequest, 99 }, 100 }, 101 { 102 name: "container + requestless container + overhead", 103 pod: v1.Pod{ 104 Spec: v1.PodSpec{ 105 Overhead: v1.ResourceList{ 106 v1.ResourceCPU: resource.MustParse("1"), 107 v1.ResourceMemory: resource.MustParse("1Mi"), 108 }, 109 Containers: []v1.Container{ 110 { 111 Resources: v1.ResourceRequirements{ 112 Requests: v1.ResourceList{ 113 v1.ResourceCPU: resource.MustParse("1"), 114 v1.ResourceMemory: resource.MustParse("1Mi"), 115 }, 116 }, 117 }, 118 {}, 119 }, 120 }, 121 }, 122 expected: map[v1.ResourceName]int64{ 123 v1.ResourceCPU: 2000 + util.DefaultMilliCPURequest, 124 v1.ResourceMemory: 2*oneMi + util.DefaultMemoryRequest, 125 }, 126 }, 127 { 128 name: "init container + container + requestless container + overhead", 129 pod: v1.Pod{ 130 Spec: v1.PodSpec{ 131 Overhead: v1.ResourceList{ 132 v1.ResourceCPU: resource.MustParse("1"), 133 v1.ResourceMemory: resource.MustParse("1Mi"), 134 }, 135 InitContainers: []v1.Container{ 136 { 137 Resources: v1.ResourceRequirements{ 138 Requests: v1.ResourceList{ 139 v1.ResourceCPU: resource.MustParse("3"), 140 }, 141 }, 142 }, 143 }, 144 Containers: []v1.Container{ 145 { 146 Resources: v1.ResourceRequirements{ 147 Requests: v1.ResourceList{ 148 v1.ResourceCPU: resource.MustParse("1"), 149 v1.ResourceMemory: resource.MustParse("1Mi"), 150 }, 151 }, 152 }, 153 {}, 154 }, 155 }, 156 }, 157 expected: map[v1.ResourceName]int64{ 158 v1.ResourceCPU: 4000, 159 v1.ResourceMemory: 2*oneMi + util.DefaultMemoryRequest, 160 }, 161 }, 162 { 163 name: "requestless init container + small init container + small container ", 164 pod: v1.Pod{ 165 Spec: v1.PodSpec{ 166 InitContainers: []v1.Container{ 167 {}, 168 { 169 Resources: v1.ResourceRequirements{ 170 Requests: v1.ResourceList{ 171 v1.ResourceCPU: resource.MustParse("1m"), 172 v1.ResourceMemory: resource.MustParse("1"), 173 }, 174 }, 175 }, 176 }, 177 Containers: []v1.Container{ 178 { 179 Resources: v1.ResourceRequirements{ 180 Requests: v1.ResourceList{ 181 v1.ResourceCPU: resource.MustParse("3m"), 182 v1.ResourceMemory: resource.MustParse("3"), 183 }, 184 }, 185 }, 186 }, 187 }, 188 }, 189 expected: map[v1.ResourceName]int64{ 190 v1.ResourceCPU: util.DefaultMilliCPURequest, 191 v1.ResourceMemory: util.DefaultMemoryRequest, 192 }, 193 }, 194 { 195 name: "requestless init container + small init container + small container + requestless container ", 196 pod: v1.Pod{ 197 Spec: v1.PodSpec{ 198 InitContainers: []v1.Container{ 199 {}, 200 { 201 Resources: v1.ResourceRequirements{ 202 Requests: v1.ResourceList{ 203 v1.ResourceCPU: resource.MustParse("1m"), 204 v1.ResourceMemory: resource.MustParse("1"), 205 }, 206 }, 207 }, 208 }, 209 Containers: []v1.Container{ 210 { 211 Resources: v1.ResourceRequirements{ 212 Requests: v1.ResourceList{ 213 v1.ResourceCPU: resource.MustParse("3m"), 214 v1.ResourceMemory: resource.MustParse("3"), 215 }, 216 }, 217 }, 218 {}, 219 }, 220 }, 221 }, 222 expected: map[v1.ResourceName]int64{ 223 v1.ResourceCPU: 3 + util.DefaultMilliCPURequest, 224 v1.ResourceMemory: 3 + util.DefaultMemoryRequest, 225 }, 226 }, 227 } 228 229 for _, tc := range tests { 230 t.Run(tc.name, func(t *testing.T) { 231 var scorer resourceAllocationScorer 232 for n, exp := range tc.expected { 233 got := scorer.calculatePodResourceRequest(&tc.pod, n) 234 if got != exp { 235 t.Errorf("expected %s = %d, got %d", n, exp, got) 236 } 237 } 238 }) 239 } 240 }