github.com/kubewharf/katalyst-core@v0.5.3/pkg/agent/orm/topology/manager_test.go (about) 1 /* 2 Copyright 2022 The Katalyst Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package topology 18 19 import ( 20 "fmt" 21 "reflect" 22 "strings" 23 "testing" 24 25 "github.com/stretchr/testify/assert" 26 v1 "k8s.io/api/core/v1" 27 v12 "k8s.io/apimachinery/pkg/apis/meta/v1" 28 "k8s.io/kubernetes/pkg/kubelet/lifecycle" 29 30 "github.com/kubewharf/katalyst-core/pkg/util/bitmask" 31 ) 32 33 func NewTestBitMask(sockets ...int) bitmask.BitMask { 34 s, _ := bitmask.NewBitMask(sockets...) 35 return s 36 } 37 38 type mockHintProvider struct { 39 th map[string][]TopologyHint 40 // TODO: Add this field and add some tests to make sure things error out 41 // appropriately on allocation errors. 42 // allocateError error 43 } 44 45 func (m *mockHintProvider) GetTopologyHints(pod *v1.Pod, container *v1.Container) map[string][]TopologyHint { 46 return m.th 47 } 48 49 func (m *mockHintProvider) GetPodTopologyHints(pod *v1.Pod) map[string][]TopologyHint { 50 return m.th 51 } 52 53 func (m *mockHintProvider) Allocate(pod *v1.Pod, container *v1.Container) error { 54 // return allocateError 55 return nil 56 } 57 58 func TestNewManager(t *testing.T) { 59 t.Parallel() 60 tcases := []struct { 61 description string 62 policyName string 63 expectedPolicy string 64 expectedError error 65 }{ 66 { 67 description: "Policy is set to none", 68 policyName: "none", 69 expectedPolicy: "none", 70 }, 71 { 72 description: "Policy is set to best-effort", 73 policyName: "best-effort", 74 expectedPolicy: "best-effort", 75 }, 76 { 77 description: "Policy is set to restricted", 78 policyName: "restricted", 79 expectedPolicy: "restricted", 80 }, 81 { 82 description: "Policy is set to single-numa-node", 83 policyName: "single-numa-node", 84 expectedPolicy: "single-numa-node", 85 }, 86 { 87 description: "Policy is set to unknown", 88 policyName: "unknown", 89 expectedError: fmt.Errorf("unknown policy: \"unknown\""), 90 }, 91 } 92 93 for _, tc := range tcases { 94 mngr, err := NewManager(nil, tc.policyName, nil) 95 96 if tc.expectedError != nil { 97 if !strings.Contains(err.Error(), tc.expectedError.Error()) { 98 t.Errorf("Unexpected error message. Have: %s wants %s", err.Error(), tc.expectedError.Error()) 99 } 100 } else { 101 rawMgr := mngr.(*manager) 102 if rawMgr.policy.Name() != tc.expectedPolicy { 103 t.Errorf("Unexpected policy name. Have: %q wants %q", rawMgr.policy.Name(), tc.expectedPolicy) 104 } 105 } 106 } 107 } 108 109 func TestAddHintProvider(t *testing.T) { 110 t.Parallel() 111 tcases := []struct { 112 name string 113 hp []HintProvider 114 }{ 115 { 116 name: "Add HintProvider", 117 hp: []HintProvider{ 118 &mockHintProvider{}, 119 &mockHintProvider{}, 120 &mockHintProvider{}, 121 }, 122 }, 123 } 124 mngr := manager{ 125 hintProviders: make([]HintProvider, 0), 126 } 127 for _, tc := range tcases { 128 for _, hp := range tc.hp { 129 mngr.AddHintProvider(hp) 130 } 131 if len(tc.hp) != len(mngr.hintProviders) { 132 t.Errorf("error") 133 } 134 } 135 } 136 137 func TestGetAffinity(t *testing.T) { 138 t.Parallel() 139 tcases := []struct { 140 name string 141 resourceName string 142 containerName string 143 podUID string 144 expected TopologyHint 145 }{ 146 { 147 name: "case1", 148 resourceName: "*", 149 containerName: "nginx", 150 podUID: "0aafa4c4-38e8-11e9-bcb1-a4bf01040474", 151 expected: TopologyHint{}, 152 }, 153 { 154 name: "case2", 155 containerName: "preferredContainer", 156 resourceName: "cpu", 157 podUID: "testpoduid", 158 expected: TopologyHint{ 159 Preferred: true, 160 NUMANodeAffinity: NewTestBitMask(0), 161 }, 162 }, 163 { 164 name: "case3", 165 resourceName: "cpu", 166 containerName: "notpreferedContainer", 167 podUID: "testpoduid", 168 expected: TopologyHint{ 169 Preferred: false, 170 NUMANodeAffinity: NewTestBitMask(0, 1), 171 }, 172 }, 173 } 174 175 mngr := manager{ 176 podTopologyHints: map[string]podTopologyHints{}, 177 } 178 mngr.setTopologyHints("testpoduid", "preferredContainer", map[string]TopologyHint{ 179 "cpu": { 180 Preferred: true, 181 NUMANodeAffinity: NewTestBitMask(0), 182 }, 183 }) 184 mngr.setTopologyHints("testpoduid", "notpreferedContainer", map[string]TopologyHint{ 185 "cpu": { 186 Preferred: false, 187 NUMANodeAffinity: NewTestBitMask(0, 1), 188 }, 189 }) 190 191 for _, tc := range tcases { 192 actual := mngr.GetAffinity(tc.podUID, tc.containerName, tc.resourceName) 193 if !reflect.DeepEqual(actual, tc.expected) { 194 t.Errorf("Expected Affinity in result to be %v, got %v", tc.expected, actual) 195 } 196 } 197 } 198 199 func TestRemovePod(t *testing.T) { 200 t.Parallel() 201 mngr := manager{ 202 podTopologyHints: map[string]podTopologyHints{}, 203 } 204 mngr.setTopologyHints("testpoduid", "testContainer", map[string]TopologyHint{ 205 "cpu": { 206 Preferred: true, 207 NUMANodeAffinity: NewTestBitMask(0), 208 }, 209 }) 210 211 mngr.RemovePod("none") 212 assert.Equal(t, 1, len(mngr.podTopologyHints)) 213 mngr.RemovePod("testpoduid") 214 assert.Equal(t, 0, len(mngr.podTopologyHints)) 215 } 216 217 func TestAdmit(t *testing.T) { 218 t.Parallel() 219 numaNodes := []int{0, 1} 220 221 tcases := []struct { 222 name string 223 result lifecycle.PodAdmitResult 224 policy Policy 225 hp []HintProvider 226 expectedErr error 227 expected TopologyHint 228 }{ 229 { 230 name: "None Policy. No Hints.", 231 policy: NewNonePolicy(), 232 hp: []HintProvider{}, 233 expectedErr: nil, 234 expected: TopologyHint{}, 235 }, 236 { 237 name: "None Policy. No Hints.", 238 policy: NewNonePolicy(), 239 hp: []HintProvider{}, 240 expectedErr: nil, 241 expected: TopologyHint{}, 242 }, 243 { 244 name: "single-numa-node Policy. No Hints.", 245 policy: NewSingleNumaNodePolicy(numaNodes), 246 hp: []HintProvider{ 247 &mockHintProvider{}, 248 }, 249 expectedErr: nil, 250 expected: TopologyHint{}, 251 }, 252 { 253 name: "Restricted Policy. No Hints.", 254 policy: NewRestrictedPolicy(numaNodes), 255 hp: []HintProvider{ 256 &mockHintProvider{}, 257 }, 258 expectedErr: nil, 259 expected: TopologyHint{}, 260 }, 261 { 262 name: "BestEffort Policy. Preferred Affinity.", 263 policy: NewBestEffortPolicy(numaNodes), 264 hp: []HintProvider{ 265 &mockHintProvider{ 266 map[string][]TopologyHint{ 267 "resource": { 268 { 269 NUMANodeAffinity: NewTestBitMask(0), 270 Preferred: true, 271 }, 272 { 273 NUMANodeAffinity: NewTestBitMask(0, 1), 274 Preferred: false, 275 }, 276 }, 277 }, 278 }, 279 }, 280 expectedErr: nil, 281 expected: TopologyHint{ 282 NUMANodeAffinity: NewTestBitMask(0), 283 Preferred: true, 284 }, 285 }, 286 { 287 name: "BestEffort Policy. More than one Preferred Affinity.", 288 policy: NewBestEffortPolicy(numaNodes), 289 hp: []HintProvider{ 290 &mockHintProvider{ 291 map[string][]TopologyHint{ 292 "resource": { 293 { 294 NUMANodeAffinity: NewTestBitMask(0), 295 Preferred: true, 296 }, 297 { 298 NUMANodeAffinity: NewTestBitMask(1), 299 Preferred: true, 300 }, 301 { 302 NUMANodeAffinity: NewTestBitMask(0, 1), 303 Preferred: false, 304 }, 305 }, 306 }, 307 }, 308 }, 309 expectedErr: nil, 310 expected: TopologyHint{ 311 NUMANodeAffinity: NewTestBitMask(0), 312 Preferred: true, 313 }, 314 }, 315 { 316 name: "BestEffort Policy. More than one Preferred Affinity.", 317 policy: NewBestEffortPolicy(numaNodes), 318 hp: []HintProvider{ 319 &mockHintProvider{ 320 map[string][]TopologyHint{ 321 "resource": { 322 { 323 NUMANodeAffinity: NewTestBitMask(0), 324 Preferred: true, 325 }, 326 { 327 NUMANodeAffinity: NewTestBitMask(1), 328 Preferred: true, 329 }, 330 { 331 NUMANodeAffinity: NewTestBitMask(0, 1), 332 Preferred: false, 333 }, 334 }, 335 }, 336 }, 337 }, 338 expectedErr: nil, 339 expected: TopologyHint{ 340 NUMANodeAffinity: NewTestBitMask(0), 341 Preferred: true, 342 }, 343 }, 344 { 345 name: "BestEffort Policy. No Preferred Affinity.", 346 policy: NewBestEffortPolicy(numaNodes), 347 hp: []HintProvider{ 348 &mockHintProvider{ 349 map[string][]TopologyHint{ 350 "resource": { 351 { 352 NUMANodeAffinity: NewTestBitMask(0, 1), 353 Preferred: false, 354 }, 355 }, 356 }, 357 }, 358 }, 359 expectedErr: nil, 360 expected: TopologyHint{ 361 NUMANodeAffinity: NewTestBitMask(0, 1), 362 Preferred: false, 363 }, 364 }, 365 { 366 name: "Restricted Policy. Preferred Affinity.", 367 policy: NewRestrictedPolicy(numaNodes), 368 hp: []HintProvider{ 369 &mockHintProvider{ 370 map[string][]TopologyHint{ 371 "resource": { 372 { 373 NUMANodeAffinity: NewTestBitMask(0), 374 Preferred: true, 375 }, 376 { 377 NUMANodeAffinity: NewTestBitMask(0, 1), 378 Preferred: false, 379 }, 380 }, 381 }, 382 }, 383 }, 384 expectedErr: nil, 385 expected: TopologyHint{ 386 NUMANodeAffinity: NewTestBitMask(0), 387 Preferred: true, 388 }, 389 }, 390 { 391 name: "Restricted Policy. Preferred Affinity.", 392 policy: NewRestrictedPolicy(numaNodes), 393 hp: []HintProvider{ 394 &mockHintProvider{ 395 map[string][]TopologyHint{ 396 "resource": { 397 { 398 NUMANodeAffinity: NewTestBitMask(0), 399 Preferred: true, 400 }, 401 { 402 NUMANodeAffinity: NewTestBitMask(0, 1), 403 Preferred: false, 404 }, 405 }, 406 }, 407 }, 408 }, 409 expectedErr: nil, 410 expected: TopologyHint{ 411 NUMANodeAffinity: NewTestBitMask(0), 412 Preferred: true, 413 }, 414 }, 415 { 416 name: "Restricted Policy. More than one Preferred affinity.", 417 policy: NewRestrictedPolicy(numaNodes), 418 hp: []HintProvider{ 419 &mockHintProvider{ 420 map[string][]TopologyHint{ 421 "resource": { 422 { 423 NUMANodeAffinity: NewTestBitMask(0), 424 Preferred: true, 425 }, 426 { 427 NUMANodeAffinity: NewTestBitMask(1), 428 Preferred: true, 429 }, 430 { 431 NUMANodeAffinity: NewTestBitMask(0, 1), 432 Preferred: false, 433 }, 434 }, 435 }, 436 }, 437 }, 438 expectedErr: nil, 439 expected: TopologyHint{ 440 NUMANodeAffinity: NewTestBitMask(0), 441 Preferred: true, 442 }, 443 }, 444 { 445 name: "Restricted Policy. More than one Preferred affinity.", 446 policy: NewRestrictedPolicy(numaNodes), 447 hp: []HintProvider{ 448 &mockHintProvider{ 449 map[string][]TopologyHint{ 450 "resource": { 451 { 452 NUMANodeAffinity: NewTestBitMask(0), 453 Preferred: true, 454 }, 455 { 456 NUMANodeAffinity: NewTestBitMask(1), 457 Preferred: true, 458 }, 459 { 460 NUMANodeAffinity: NewTestBitMask(0, 1), 461 Preferred: false, 462 }, 463 }, 464 }, 465 }, 466 }, 467 expectedErr: nil, 468 expected: TopologyHint{ 469 NUMANodeAffinity: NewTestBitMask(0), 470 Preferred: true, 471 }, 472 }, 473 { 474 name: "Restricted Policy. No Preferred affinity.", 475 policy: NewRestrictedPolicy(numaNodes), 476 hp: []HintProvider{ 477 &mockHintProvider{ 478 map[string][]TopologyHint{ 479 "resource": { 480 { 481 NUMANodeAffinity: NewTestBitMask(0, 1), 482 Preferred: false, 483 }, 484 }, 485 }, 486 }, 487 }, 488 expectedErr: fmt.Errorf("pod: %v, containerName: %v not admit", "testPod", "testContainer"), 489 expected: TopologyHint{}, 490 }, 491 { 492 name: "Restricted Policy. No Preferred affinity.", 493 policy: NewRestrictedPolicy(numaNodes), 494 hp: []HintProvider{ 495 &mockHintProvider{ 496 map[string][]TopologyHint{ 497 "resource": { 498 { 499 NUMANodeAffinity: NewTestBitMask(0, 1), 500 Preferred: false, 501 }, 502 }, 503 }, 504 }, 505 }, 506 expectedErr: fmt.Errorf("pod: %v, containerName: %v not admit", "testPod", "testContainer"), 507 expected: TopologyHint{}, 508 }, 509 } 510 for _, tc := range tcases { 511 topologyManager := manager{ 512 policy: tc.policy, 513 hintProviders: tc.hp, 514 podTopologyHints: map[string]podTopologyHints{}, 515 } 516 517 pod := &v1.Pod{ 518 ObjectMeta: v12.ObjectMeta{ 519 Name: "testPod", 520 UID: "testUID", 521 }, 522 Spec: v1.PodSpec{ 523 Containers: []v1.Container{ 524 { 525 Name: "testContainer", 526 Resources: v1.ResourceRequirements{}, 527 }, 528 }, 529 }, 530 Status: v1.PodStatus{}, 531 } 532 533 err := topologyManager.Admit(pod) 534 assert.Equal(t, tc.expectedErr, err) 535 if err != nil { 536 assert.Equal(t, tc.expected, topologyManager.GetAffinity("testUID", "testContainer", "resource")) 537 } 538 } 539 }