volcano.sh/volcano@v1.9.0/pkg/controllers/job/job_controller_util_test.go (about) 1 /* 2 Copyright 2019 The Volcano 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 job 18 19 import ( 20 "testing" 21 22 v1 "k8s.io/api/core/v1" 23 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 24 25 "volcano.sh/apis/pkg/apis/batch/v1alpha1" 26 busv1alpha1 "volcano.sh/apis/pkg/apis/bus/v1alpha1" 27 "volcano.sh/volcano/pkg/controllers/apis" 28 ) 29 30 func TestMakePodName(t *testing.T) { 31 testcases := []struct { 32 Name string 33 TaskName string 34 JobName string 35 Index int 36 ReturnVal string 37 }{ 38 { 39 Name: "Test MakePodName function", 40 TaskName: "task1", 41 JobName: "job1", 42 Index: 1, 43 ReturnVal: "job1-task1-1", 44 }, 45 } 46 47 for i, testcase := range testcases { 48 49 t.Run(testcase.Name, func(t *testing.T) { 50 podName := MakePodName(testcase.JobName, testcase.TaskName, testcase.Index) 51 52 if podName != testcase.ReturnVal { 53 t.Errorf("Expected Return value to be: %s, but got: %s in case %d", testcase.ReturnVal, podName, i) 54 } 55 }) 56 57 } 58 } 59 60 func TestCreateJobPod(t *testing.T) { 61 namespace := "test" 62 63 testcases := []struct { 64 Name string 65 Job *v1alpha1.Job 66 PodTemplate *v1.PodTemplateSpec 67 Index int 68 ReturnVal *v1.Pod 69 }{ 70 { 71 Name: "Test Create Job Pod", 72 Job: &v1alpha1.Job{ 73 ObjectMeta: metav1.ObjectMeta{ 74 Name: "job1", 75 Namespace: namespace, 76 }, 77 Spec: v1alpha1.JobSpec{ 78 Tasks: []v1alpha1.TaskSpec{ 79 { 80 Name: "task1", 81 Replicas: 6, 82 Template: v1.PodTemplateSpec{ 83 ObjectMeta: metav1.ObjectMeta{ 84 Name: "pods", 85 Namespace: namespace, 86 }, 87 Spec: v1.PodSpec{ 88 Containers: []v1.Container{ 89 { 90 Name: "Containers", 91 }, 92 }, 93 }, 94 }, 95 }, 96 }, 97 }, 98 }, 99 PodTemplate: &v1.PodTemplateSpec{ 100 ObjectMeta: metav1.ObjectMeta{ 101 Namespace: namespace, 102 }, 103 Spec: v1.PodSpec{ 104 Containers: []v1.Container{ 105 { 106 Name: "Containers", 107 }, 108 }, 109 }, 110 }, 111 Index: 0, 112 ReturnVal: &v1.Pod{ 113 ObjectMeta: metav1.ObjectMeta{ 114 Name: "job1-task1-0", 115 Namespace: namespace, 116 }, 117 }, 118 }, 119 { 120 Name: "Test Create Job Pod with volumes", 121 Job: &v1alpha1.Job{ 122 ObjectMeta: metav1.ObjectMeta{ 123 Name: "job1", 124 Namespace: namespace, 125 }, 126 Spec: v1alpha1.JobSpec{ 127 Volumes: []v1alpha1.VolumeSpec{ 128 { 129 VolumeClaimName: "vc1", 130 }, 131 { 132 VolumeClaimName: "vc2", 133 }, 134 }, 135 Tasks: []v1alpha1.TaskSpec{ 136 { 137 Name: "task1", 138 Replicas: 6, 139 Template: v1.PodTemplateSpec{ 140 ObjectMeta: metav1.ObjectMeta{ 141 Name: "pods", 142 Namespace: namespace, 143 }, 144 Spec: v1.PodSpec{ 145 Containers: []v1.Container{ 146 { 147 Name: "Containers", 148 }, 149 }, 150 }, 151 }, 152 }, 153 }, 154 }, 155 }, 156 PodTemplate: &v1.PodTemplateSpec{ 157 ObjectMeta: metav1.ObjectMeta{ 158 Namespace: namespace, 159 }, 160 Spec: v1.PodSpec{ 161 Containers: []v1.Container{ 162 { 163 Name: "Containers", 164 }, 165 }, 166 }, 167 }, 168 Index: 0, 169 ReturnVal: &v1.Pod{ 170 ObjectMeta: metav1.ObjectMeta{ 171 Name: "job1-task1-0", 172 Namespace: namespace, 173 }, 174 }, 175 }, 176 { 177 Name: "Test Create Job Pod with volumes added to controlled resources", 178 Job: &v1alpha1.Job{ 179 ObjectMeta: metav1.ObjectMeta{ 180 Name: "job1", 181 Namespace: namespace, 182 }, 183 Spec: v1alpha1.JobSpec{ 184 SchedulerName: "volcano", 185 Volumes: []v1alpha1.VolumeSpec{ 186 { 187 VolumeClaimName: "vc1", 188 VolumeClaim: &v1.PersistentVolumeClaimSpec{ 189 VolumeName: "v1", 190 }, 191 }, 192 { 193 VolumeClaimName: "vc2", 194 }, 195 }, 196 Tasks: []v1alpha1.TaskSpec{ 197 { 198 Name: "task1", 199 Replicas: 6, 200 Template: v1.PodTemplateSpec{ 201 ObjectMeta: metav1.ObjectMeta{ 202 Name: "pods", 203 Namespace: namespace, 204 }, 205 Spec: v1.PodSpec{ 206 Containers: []v1.Container{ 207 { 208 Name: "Containers", 209 }, 210 }, 211 }, 212 }, 213 }, 214 }, 215 }, 216 }, 217 PodTemplate: &v1.PodTemplateSpec{ 218 ObjectMeta: metav1.ObjectMeta{ 219 Namespace: namespace, 220 }, 221 Spec: v1.PodSpec{ 222 Containers: []v1.Container{ 223 { 224 Name: "Containers", 225 }, 226 }, 227 }, 228 }, 229 Index: 0, 230 ReturnVal: &v1.Pod{ 231 ObjectMeta: metav1.ObjectMeta{ 232 Name: "job1-task1-0", 233 Namespace: namespace, 234 }, 235 }, 236 }, 237 } 238 239 for i, testcase := range testcases { 240 241 t.Run(testcase.Name, func(t *testing.T) { 242 pod := createJobPod(testcase.Job, testcase.PodTemplate, "", testcase.Index, false) 243 244 if testcase.ReturnVal != nil && pod != nil && pod.Name != testcase.ReturnVal.Name && pod.Namespace != testcase.ReturnVal.Namespace { 245 t.Errorf("Expected Return Value to be %v but got %v in case %d", testcase.ReturnVal, pod, i) 246 } 247 }) 248 } 249 } 250 251 func TestApplyPolicies(t *testing.T) { 252 namespace := "test" 253 errorCode0 := int32(0) 254 255 testcases := []struct { 256 Name string 257 Job *v1alpha1.Job 258 Request *apis.Request 259 ReturnVal busv1alpha1.Action 260 }{ 261 { 262 Name: "Test Apply policies where Action is not empty", 263 Job: &v1alpha1.Job{ 264 ObjectMeta: metav1.ObjectMeta{ 265 Name: "job1", 266 Namespace: namespace, 267 }, 268 Spec: v1alpha1.JobSpec{ 269 SchedulerName: "volcano", 270 Tasks: []v1alpha1.TaskSpec{ 271 { 272 Name: "task1", 273 Replicas: 6, 274 Template: v1.PodTemplateSpec{ 275 ObjectMeta: metav1.ObjectMeta{ 276 Name: "pods", 277 Namespace: namespace, 278 }, 279 Spec: v1.PodSpec{ 280 Containers: []v1.Container{ 281 { 282 Name: "Containers", 283 }, 284 }, 285 }, 286 }, 287 }, 288 }, 289 }, 290 }, 291 Request: &apis.Request{ 292 Action: busv1alpha1.EnqueueAction, 293 }, 294 ReturnVal: busv1alpha1.EnqueueAction, 295 }, 296 { 297 Name: "Test Apply policies where event is OutOfSync", 298 Job: &v1alpha1.Job{ 299 ObjectMeta: metav1.ObjectMeta{ 300 Name: "job1", 301 Namespace: namespace, 302 }, 303 Spec: v1alpha1.JobSpec{ 304 SchedulerName: "volcano", 305 Tasks: []v1alpha1.TaskSpec{ 306 { 307 Name: "task1", 308 Replicas: 6, 309 Template: v1.PodTemplateSpec{ 310 ObjectMeta: metav1.ObjectMeta{ 311 Name: "pods", 312 Namespace: namespace, 313 }, 314 Spec: v1.PodSpec{ 315 Containers: []v1.Container{ 316 { 317 Name: "Containers", 318 }, 319 }, 320 }, 321 }, 322 }, 323 }, 324 }, 325 }, 326 Request: &apis.Request{ 327 Event: busv1alpha1.OutOfSyncEvent, 328 }, 329 ReturnVal: busv1alpha1.SyncJobAction, 330 }, 331 { 332 Name: "Test Apply policies where version is outdated", 333 Job: &v1alpha1.Job{ 334 ObjectMeta: metav1.ObjectMeta{ 335 Name: "job1", 336 Namespace: namespace, 337 }, 338 Spec: v1alpha1.JobSpec{ 339 SchedulerName: "volcano", 340 Tasks: []v1alpha1.TaskSpec{ 341 { 342 Name: "task1", 343 Replicas: 6, 344 Template: v1.PodTemplateSpec{ 345 ObjectMeta: metav1.ObjectMeta{ 346 Name: "pods", 347 Namespace: namespace, 348 }, 349 Spec: v1.PodSpec{ 350 Containers: []v1.Container{ 351 { 352 Name: "Containers", 353 }, 354 }, 355 }, 356 }, 357 }, 358 }, 359 }, 360 }, 361 Request: &apis.Request{ 362 JobVersion: 1, 363 }, 364 ReturnVal: busv1alpha1.SyncJobAction, 365 }, 366 { 367 Name: "Test Apply policies where overriding job level policies and with exitcode", 368 Job: &v1alpha1.Job{ 369 ObjectMeta: metav1.ObjectMeta{ 370 Name: "job1", 371 Namespace: namespace, 372 }, 373 Spec: v1alpha1.JobSpec{ 374 SchedulerName: "volcano", 375 Tasks: []v1alpha1.TaskSpec{ 376 { 377 Name: "task1", 378 Replicas: 6, 379 Template: v1.PodTemplateSpec{ 380 ObjectMeta: metav1.ObjectMeta{ 381 Name: "pods", 382 Namespace: namespace, 383 }, 384 Spec: v1.PodSpec{ 385 Containers: []v1.Container{ 386 { 387 Name: "Containers", 388 }, 389 }, 390 }, 391 }, 392 Policies: []v1alpha1.LifecyclePolicy{ 393 { 394 Action: busv1alpha1.SyncJobAction, 395 Event: busv1alpha1.CommandIssuedEvent, 396 ExitCode: &errorCode0, 397 }, 398 }, 399 }, 400 }, 401 }, 402 }, 403 Request: &apis.Request{ 404 TaskName: "task1", 405 }, 406 ReturnVal: busv1alpha1.SyncJobAction, 407 }, 408 { 409 Name: "Test Apply policies where overriding job level policies and without exitcode", 410 Job: &v1alpha1.Job{ 411 ObjectMeta: metav1.ObjectMeta{ 412 Name: "job1", 413 Namespace: namespace, 414 }, 415 Spec: v1alpha1.JobSpec{ 416 SchedulerName: "volcano", 417 Tasks: []v1alpha1.TaskSpec{ 418 { 419 Name: "task1", 420 Replicas: 6, 421 Template: v1.PodTemplateSpec{ 422 ObjectMeta: metav1.ObjectMeta{ 423 Name: "pods", 424 Namespace: namespace, 425 }, 426 Spec: v1.PodSpec{ 427 Containers: []v1.Container{ 428 { 429 Name: "Containers", 430 }, 431 }, 432 }, 433 }, 434 Policies: []v1alpha1.LifecyclePolicy{ 435 { 436 Action: busv1alpha1.SyncJobAction, 437 Event: busv1alpha1.CommandIssuedEvent, 438 }, 439 }, 440 }, 441 }, 442 }, 443 }, 444 Request: &apis.Request{ 445 TaskName: "task1", 446 Event: busv1alpha1.CommandIssuedEvent, 447 }, 448 ReturnVal: busv1alpha1.SyncJobAction, 449 }, 450 { 451 Name: "Test Apply policies with job level policies", 452 Job: &v1alpha1.Job{ 453 ObjectMeta: metav1.ObjectMeta{ 454 Name: "job1", 455 Namespace: namespace, 456 }, 457 Spec: v1alpha1.JobSpec{ 458 SchedulerName: "volcano", 459 Tasks: []v1alpha1.TaskSpec{ 460 { 461 Name: "task1", 462 Replicas: 6, 463 Template: v1.PodTemplateSpec{ 464 ObjectMeta: metav1.ObjectMeta{ 465 Name: "pods", 466 Namespace: namespace, 467 }, 468 Spec: v1.PodSpec{ 469 Containers: []v1.Container{ 470 { 471 Name: "Containers", 472 }, 473 }, 474 }, 475 }, 476 }, 477 }, 478 }, 479 }, 480 Request: &apis.Request{ 481 TaskName: "task1", 482 Event: busv1alpha1.CommandIssuedEvent, 483 }, 484 ReturnVal: busv1alpha1.SyncJobAction, 485 }, 486 { 487 Name: "Test Apply policies with job level policies", 488 Job: &v1alpha1.Job{ 489 ObjectMeta: metav1.ObjectMeta{ 490 Name: "job1", 491 Namespace: namespace, 492 }, 493 Spec: v1alpha1.JobSpec{ 494 SchedulerName: "volcano", 495 Tasks: []v1alpha1.TaskSpec{ 496 { 497 Name: "task1", 498 Replicas: 6, 499 Template: v1.PodTemplateSpec{ 500 ObjectMeta: metav1.ObjectMeta{ 501 Name: "pods", 502 Namespace: namespace, 503 }, 504 Spec: v1.PodSpec{ 505 Containers: []v1.Container{ 506 { 507 Name: "Containers", 508 }, 509 }, 510 }, 511 }, 512 }, 513 }, 514 Policies: []v1alpha1.LifecyclePolicy{ 515 { 516 Action: busv1alpha1.SyncJobAction, 517 Event: busv1alpha1.CommandIssuedEvent, 518 }, 519 }, 520 }, 521 }, 522 Request: &apis.Request{ 523 Event: busv1alpha1.CommandIssuedEvent, 524 }, 525 ReturnVal: busv1alpha1.SyncJobAction, 526 }, 527 { 528 Name: "Test Apply policies with job level policies with exitcode", 529 Job: &v1alpha1.Job{ 530 ObjectMeta: metav1.ObjectMeta{ 531 Name: "job1", 532 Namespace: namespace, 533 }, 534 Spec: v1alpha1.JobSpec{ 535 SchedulerName: "volcano", 536 Tasks: []v1alpha1.TaskSpec{ 537 { 538 Name: "task1", 539 Replicas: 6, 540 Template: v1.PodTemplateSpec{ 541 ObjectMeta: metav1.ObjectMeta{ 542 Name: "pods", 543 Namespace: namespace, 544 }, 545 Spec: v1.PodSpec{ 546 Containers: []v1.Container{ 547 { 548 Name: "Containers", 549 }, 550 }, 551 }, 552 }, 553 }, 554 }, 555 Policies: []v1alpha1.LifecyclePolicy{ 556 { 557 Action: busv1alpha1.SyncJobAction, 558 Event: busv1alpha1.CommandIssuedEvent, 559 ExitCode: &errorCode0, 560 }, 561 }, 562 }, 563 }, 564 Request: &apis.Request{}, 565 ReturnVal: busv1alpha1.SyncJobAction, 566 }, 567 } 568 569 for i, testcase := range testcases { 570 571 t.Run(testcase.Name, func(t *testing.T) { 572 action := applyPolicies(testcase.Job, testcase.Request) 573 574 if testcase.ReturnVal != "" && action != "" && testcase.ReturnVal != action { 575 t.Errorf("Expected return value to be %s but got %s in case %d", testcase.ReturnVal, action, i) 576 } 577 }) 578 } 579 } 580 581 func TestTasksPriority_Less(t *testing.T) { 582 testcases := []struct { 583 Name string 584 TasksPriority TasksPriority 585 Task1Index int 586 Task2Index int 587 ReturnVal bool 588 }{ 589 { 590 Name: "False Case", 591 TasksPriority: []TaskPriority{ 592 { 593 priority: 1, 594 }, 595 { 596 priority: 2, 597 }, 598 { 599 priority: 3, 600 }, 601 }, 602 Task1Index: 1, 603 Task2Index: 2, 604 ReturnVal: false, 605 }, 606 { 607 Name: "True Case", 608 TasksPriority: []TaskPriority{ 609 { 610 priority: 1, 611 }, 612 { 613 priority: 2, 614 }, 615 { 616 priority: 3, 617 }, 618 }, 619 Task1Index: 2, 620 Task2Index: 1, 621 ReturnVal: true, 622 }, 623 } 624 625 for i, testcase := range testcases { 626 627 t.Run(testcase.Name, func(t *testing.T) { 628 less := testcase.TasksPriority.Less(testcase.Task1Index, testcase.Task2Index) 629 630 if less != testcase.ReturnVal { 631 t.Errorf("Expected Return Value to be %t, but got %t in case %d", testcase.ReturnVal, less, i) 632 } 633 }) 634 } 635 } 636 637 func TestTasksPriority_Swap(t *testing.T) { 638 testcases := []struct { 639 Name string 640 TasksPriority TasksPriority 641 Task1Index int 642 Task2Index int 643 ReturnVal bool 644 }{ 645 { 646 Name: "False Case", 647 TasksPriority: []TaskPriority{ 648 { 649 priority: 1, 650 }, 651 { 652 priority: 2, 653 }, 654 { 655 priority: 3, 656 }, 657 }, 658 Task1Index: 1, 659 Task2Index: 2, 660 }, 661 { 662 Name: "True Case", 663 TasksPriority: []TaskPriority{ 664 { 665 priority: 1, 666 }, 667 { 668 priority: 2, 669 }, 670 { 671 priority: 3, 672 }, 673 }, 674 Task1Index: 2, 675 Task2Index: 1, 676 }, 677 } 678 679 for _, testcase := range testcases { 680 t.Run(testcase.Name, func(_ *testing.T) { 681 testcase.TasksPriority.Swap(testcase.Task1Index, testcase.Task2Index) 682 }) 683 } 684 }