sigs.k8s.io/kueue@v0.6.2/pkg/util/resource/resource_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 resource 18 19 import ( 20 "testing" 21 22 "github.com/google/go-cmp/cmp" 23 corev1 "k8s.io/api/core/v1" 24 "k8s.io/apimachinery/pkg/api/resource" 25 ) 26 27 func TestMerge(t *testing.T) { 28 rl_500mcpu_2GiMem := corev1.ResourceList{ 29 corev1.ResourceCPU: resource.MustParse("500m"), 30 corev1.ResourceMemory: resource.MustParse("2Gi"), 31 } 32 rl_1cpu := corev1.ResourceList{ 33 corev1.ResourceCPU: resource.MustParse("1"), 34 } 35 rl_1cpu_1GiMem := corev1.ResourceList{ 36 corev1.ResourceCPU: resource.MustParse("1"), 37 corev1.ResourceMemory: resource.MustParse("1Gi"), 38 } 39 40 type oper_result struct { 41 oper func(a, b corev1.ResourceList) corev1.ResourceList 42 result corev1.ResourceList 43 } 44 cases := map[string]struct { 45 a corev1.ResourceList 46 b corev1.ResourceList 47 want map[string]oper_result 48 }{ 49 "asymmetric": { 50 a: rl_1cpu, 51 b: rl_500mcpu_2GiMem, 52 want: map[string]oper_result{ 53 "merge": { 54 oper: MergeResourceListKeepFirst, 55 result: corev1.ResourceList{ 56 corev1.ResourceCPU: resource.MustParse("1"), 57 corev1.ResourceMemory: resource.MustParse("2Gi"), 58 }, 59 }, 60 "min": { 61 oper: MergeResourceListKeepMin, 62 result: corev1.ResourceList{ 63 corev1.ResourceCPU: resource.MustParse("500m"), 64 corev1.ResourceMemory: resource.MustParse("2Gi"), 65 }, 66 }, 67 "max": { 68 oper: MergeResourceListKeepMax, 69 result: corev1.ResourceList{ 70 corev1.ResourceCPU: resource.MustParse("1"), 71 corev1.ResourceMemory: resource.MustParse("2Gi"), 72 }, 73 }, 74 "sum": { 75 oper: MergeResourceListKeepSum, 76 result: corev1.ResourceList{ 77 corev1.ResourceCPU: resource.MustParse("1500m"), 78 corev1.ResourceMemory: resource.MustParse("2Gi"), 79 }, 80 }, 81 }, 82 }, 83 "symmetric": { 84 a: rl_1cpu_1GiMem, 85 b: rl_500mcpu_2GiMem, 86 want: map[string]oper_result{ 87 "merge": { 88 oper: MergeResourceListKeepFirst, 89 result: corev1.ResourceList{ 90 corev1.ResourceCPU: resource.MustParse("1"), 91 corev1.ResourceMemory: resource.MustParse("1Gi"), 92 }, 93 }, 94 "min": { 95 oper: MergeResourceListKeepMin, 96 result: corev1.ResourceList{ 97 corev1.ResourceCPU: resource.MustParse("500m"), 98 corev1.ResourceMemory: resource.MustParse("1Gi"), 99 }, 100 }, 101 "max": { 102 oper: MergeResourceListKeepMax, 103 result: corev1.ResourceList{ 104 corev1.ResourceCPU: resource.MustParse("1"), 105 corev1.ResourceMemory: resource.MustParse("2Gi"), 106 }, 107 }, 108 "sum": { 109 oper: MergeResourceListKeepSum, 110 result: corev1.ResourceList{ 111 corev1.ResourceCPU: resource.MustParse("1500m"), 112 corev1.ResourceMemory: resource.MustParse("3Gi"), 113 }, 114 }, 115 }, 116 }, 117 "nil source": { 118 a: rl_1cpu_1GiMem, 119 b: nil, 120 want: map[string]oper_result{ 121 "merge": { 122 oper: MergeResourceListKeepFirst, 123 result: rl_1cpu_1GiMem, 124 }, 125 "min": { 126 oper: MergeResourceListKeepMin, 127 result: rl_1cpu_1GiMem, 128 }, 129 "max": { 130 oper: MergeResourceListKeepMax, 131 result: rl_1cpu_1GiMem, 132 }, 133 "sum": { 134 oper: MergeResourceListKeepSum, 135 result: rl_1cpu_1GiMem, 136 }, 137 }, 138 }, 139 "nil destination": { 140 a: nil, 141 b: rl_1cpu_1GiMem, 142 want: map[string]oper_result{ 143 "merge": { 144 oper: MergeResourceListKeepFirst, 145 result: rl_1cpu_1GiMem, 146 }, 147 "min": { 148 oper: MergeResourceListKeepMin, 149 result: rl_1cpu_1GiMem, 150 }, 151 "max": { 152 oper: MergeResourceListKeepMax, 153 result: rl_1cpu_1GiMem, 154 }, 155 "sum": { 156 oper: MergeResourceListKeepSum, 157 result: rl_1cpu_1GiMem, 158 }, 159 }, 160 }, 161 "nil": { 162 a: nil, 163 b: nil, 164 want: map[string]oper_result{ 165 "merge": { 166 oper: MergeResourceListKeepFirst, 167 result: nil, 168 }, 169 "min": { 170 oper: MergeResourceListKeepMin, 171 result: nil, 172 }, 173 "max": { 174 oper: MergeResourceListKeepMax, 175 result: nil, 176 }, 177 "sum": { 178 oper: MergeResourceListKeepSum, 179 result: nil, 180 }, 181 }, 182 }, 183 } 184 185 for name, tc := range cases { 186 t.Run(name, func(t *testing.T) { 187 for opname, oper := range tc.want { 188 t.Run(opname, func(t *testing.T) { 189 result := oper.oper(tc.a, tc.b) 190 if diff := cmp.Diff(oper.result, result); diff != "" { 191 t.Errorf("Unexpected result (-want,+got):\n%s", diff) 192 } 193 }) 194 } 195 }) 196 } 197 198 } 199 200 func TestGetGraterKeys(t *testing.T) { 201 cpuOnly1 := corev1.ResourceList{ 202 corev1.ResourceCPU: resource.MustParse("1"), 203 } 204 cpuOnly500m := corev1.ResourceList{ 205 corev1.ResourceCPU: resource.MustParse("500m"), 206 } 207 cases := map[string]struct { 208 a, b corev1.ResourceList 209 want []string 210 }{ 211 "empty_a": { 212 b: cpuOnly1, 213 want: nil, 214 }, 215 "empty_b": { 216 a: cpuOnly1, 217 want: nil, 218 }, 219 "less one resource": { 220 a: cpuOnly500m, 221 b: cpuOnly1, 222 want: nil, 223 }, 224 "not less one resource": { 225 a: cpuOnly1, 226 b: cpuOnly500m, 227 want: []string{corev1.ResourceCPU.String()}, 228 }, 229 "multiple unrelated": { 230 a: corev1.ResourceList{ 231 "r1": resource.MustParse("2"), 232 "r2": resource.MustParse("2"), 233 }, 234 b: corev1.ResourceList{ 235 "r3": resource.MustParse("1"), 236 "r4": resource.MustParse("1"), 237 }, 238 want: nil, 239 }, 240 "multiple": { 241 a: corev1.ResourceList{ 242 "r1": resource.MustParse("2"), 243 "r2": resource.MustParse("1"), 244 }, 245 b: corev1.ResourceList{ 246 "r1": resource.MustParse("1"), 247 "r2": resource.MustParse("2"), 248 }, 249 want: []string{"r1"}, 250 }, 251 } 252 253 for name, tc := range cases { 254 t.Run(name, func(t *testing.T) { 255 got := GetGreaterKeys(tc.a, tc.b) 256 if diff := cmp.Diff(tc.want, got); diff != "" { 257 t.Errorf("Unexpected result (-want, +got)\n%s", diff) 258 } 259 }) 260 } 261 } 262 263 func TestQuantityToFloat(t *testing.T) { 264 cases := map[string]struct { 265 q resource.Quantity 266 wantResult float64 267 }{ 268 "decimal zero exponent": { 269 q: resource.MustParse("5"), 270 wantResult: 5, 271 }, 272 "float zero exponent": { 273 q: resource.MustParse("5.5"), 274 wantResult: 5.5, 275 }, 276 "decimal positive exponent": { 277 q: resource.MustParse("5k"), 278 wantResult: 5000, 279 }, 280 "float positive exponent": { 281 q: resource.MustParse("5.5k"), 282 wantResult: 5500, 283 }, 284 "decimal negative exponent": { 285 q: resource.MustParse("5m"), 286 wantResult: 0.005, 287 }, 288 "float negative exponent": { 289 q: resource.MustParse("5.5m"), 290 wantResult: 0.006, // 1/1000 is the maximum precision, the value will be rounded 291 }, 292 } 293 294 for name, tc := range cases { 295 t.Run(name, func(t *testing.T) { 296 got := QuantityToFloat(&tc.q) 297 if got != tc.wantResult { 298 t.Errorf("Unexpected result, expecting %f got %f", tc.wantResult, got) 299 } 300 }) 301 } 302 }