Skip to content

Commit 505ae69

Browse files
committed
add integration-test for NonPreemption
1 parent 570cdb8 commit 505ae69

File tree

2 files changed

+107
-0
lines changed

2 files changed

+107
-0
lines changed

test/integration/scheduler/preemption_test.go

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,16 @@ import (
3333
"k8s.io/apimachinery/pkg/types"
3434
"k8s.io/apimachinery/pkg/util/intstr"
3535
"k8s.io/apimachinery/pkg/util/wait"
36+
utilfeature "k8s.io/apiserver/pkg/util/feature"
3637
"k8s.io/client-go/informers"
3738
"k8s.io/client-go/kubernetes"
3839
clientset "k8s.io/client-go/kubernetes"
3940
restclient "k8s.io/client-go/rest"
41+
featuregatetesting "k8s.io/component-base/featuregate/testing"
4042
"k8s.io/klog/v2"
4143
podutil "k8s.io/kubernetes/pkg/api/v1/pod"
4244
"k8s.io/kubernetes/pkg/apis/scheduling"
45+
"k8s.io/kubernetes/pkg/features"
4346
"k8s.io/kubernetes/pkg/scheduler"
4447
schedulerconfig "k8s.io/kubernetes/pkg/scheduler/apis/config"
4548
framework "k8s.io/kubernetes/pkg/scheduler/framework/v1alpha1"
@@ -434,6 +437,87 @@ func TestPreemption(t *testing.T) {
434437
}
435438
}
436439

440+
// TestNonPreemption tests NonPreempt option of PriorityClass of scheduler works as expected.
441+
func TestNonPreemption(t *testing.T) {
442+
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.NonPreemptingPriority, true)()
443+
444+
var preemptNever = v1.PreemptNever
445+
// Initialize scheduler.
446+
testCtx := initTest(t, "non-preemption")
447+
defer testutils.CleanupTest(t, testCtx)
448+
cs := testCtx.ClientSet
449+
tests := []struct {
450+
name string
451+
PreemptionPolicy *v1.PreemptionPolicy
452+
}{
453+
{
454+
name: "pod preemption will happen",
455+
PreemptionPolicy: nil,
456+
},
457+
{
458+
name: "pod preemption will not happen",
459+
PreemptionPolicy: &preemptNever,
460+
},
461+
}
462+
victim := initPausePod(&pausePodConfig{
463+
Name: "victim-pod",
464+
Namespace: testCtx.NS.Name,
465+
Priority: &lowPriority,
466+
Resources: &v1.ResourceRequirements{Requests: v1.ResourceList{
467+
v1.ResourceCPU: *resource.NewMilliQuantity(400, resource.DecimalSI),
468+
v1.ResourceMemory: *resource.NewQuantity(200, resource.DecimalSI)},
469+
},
470+
})
471+
472+
preemptor := initPausePod(&pausePodConfig{
473+
Name: "preemptor-pod",
474+
Namespace: testCtx.NS.Name,
475+
Priority: &highPriority,
476+
Resources: &v1.ResourceRequirements{Requests: v1.ResourceList{
477+
v1.ResourceCPU: *resource.NewMilliQuantity(300, resource.DecimalSI),
478+
v1.ResourceMemory: *resource.NewQuantity(200, resource.DecimalSI)},
479+
},
480+
})
481+
482+
// Create a node with some resources and a label.
483+
nodeRes := &v1.ResourceList{
484+
v1.ResourcePods: *resource.NewQuantity(32, resource.DecimalSI),
485+
v1.ResourceCPU: *resource.NewMilliQuantity(500, resource.DecimalSI),
486+
v1.ResourceMemory: *resource.NewQuantity(500, resource.DecimalSI),
487+
}
488+
_, err := createNode(testCtx.ClientSet, "node1", nodeRes)
489+
if err != nil {
490+
t.Fatalf("Error creating nodes: %v", err)
491+
}
492+
for _, test := range tests {
493+
t.Run(test.name, func(t *testing.T) {
494+
defer testutils.CleanupPods(cs, t, []*v1.Pod{preemptor, victim})
495+
preemptor.Spec.PreemptionPolicy = test.PreemptionPolicy
496+
victimPod, err := createPausePod(cs, victim)
497+
if err != nil {
498+
t.Fatalf("Error while creating victim: %v", err)
499+
}
500+
if err := waitForPodToScheduleWithTimeout(cs, victimPod, 5*time.Second); err != nil {
501+
t.Fatalf("victim %v should be become scheduled", victimPod.Name)
502+
}
503+
504+
preemptorPod, err := createPausePod(cs, preemptor)
505+
if err != nil {
506+
t.Fatalf("Error while creating preemptor: %v", err)
507+
}
508+
509+
err = waitForNominatedNodeNameWithTimeout(cs, preemptorPod, 5*time.Second)
510+
// test.PreemptionPolicy == nil means we expect the preemptor to be nominated.
511+
expect := test.PreemptionPolicy == nil
512+
// err == nil indicates the preemptor is indeed nominated.
513+
got := err == nil
514+
if got != expect {
515+
t.Errorf("Expect preemptor to be nominated=%v, but got=%v", expect, got)
516+
}
517+
})
518+
}
519+
}
520+
437521
// TestDisablePreemption tests disable pod preemption of scheduler works as expected.
438522
func TestDisablePreemption(t *testing.T) {
439523
// Initialize scheduler, and disable preemption.

test/integration/scheduler/util.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,7 @@ type pausePodConfig struct {
204204
NodeName string
205205
SchedulerName string
206206
Priority *int32
207+
PreemptionPolicy *v1.PreemptionPolicy
207208
PriorityClassName string
208209
}
209210

@@ -230,6 +231,7 @@ func initPausePod(conf *pausePodConfig) *v1.Pod {
230231
NodeName: conf.NodeName,
231232
SchedulerName: conf.SchedulerName,
232233
Priority: conf.Priority,
234+
PreemptionPolicy: conf.PreemptionPolicy,
233235
PriorityClassName: conf.PriorityClassName,
234236
},
235237
}
@@ -398,6 +400,12 @@ func waitForPodUnschedulable(cs clientset.Interface, pod *v1.Pod) error {
398400
return waitForPodUnschedulableWithTimeout(cs, pod, 30*time.Second)
399401
}
400402

403+
// waitForPodToScheduleWithTimeout waits for a pod to get scheduled and returns
404+
// an error if it does not scheduled within the given timeout.
405+
func waitForPodToScheduleWithTimeout(cs clientset.Interface, pod *v1.Pod, timeout time.Duration) error {
406+
return wait.Poll(100*time.Millisecond, timeout, podScheduled(cs, pod.Namespace, pod.Name))
407+
}
408+
401409
// waitForPDBsStable waits for PDBs to have "CurrentHealthy" status equal to
402410
// the expected values.
403411
func waitForPDBsStable(testCtx *testutils.TestContext, pdbs []*policy.PodDisruptionBudget, pdbPodNum []int32) error {
@@ -485,3 +493,18 @@ func cleanupPodsInNamespace(cs clientset.Interface, t *testing.T, ns string) {
485493
t.Errorf("error while waiting for pods in namespace %v: %v", ns, err)
486494
}
487495
}
496+
497+
// podScheduled returns true if a node is assigned to the given pod.
498+
func podScheduled(c clientset.Interface, podNamespace, podName string) wait.ConditionFunc {
499+
return func() (bool, error) {
500+
pod, err := c.CoreV1().Pods(podNamespace).Get(context.TODO(), podName, metav1.GetOptions{})
501+
if err != nil {
502+
// This could be a connection error so we want to retry.
503+
return false, nil
504+
}
505+
if pod.Spec.NodeName == "" {
506+
return false, nil
507+
}
508+
return true, nil
509+
}
510+
}

0 commit comments

Comments
 (0)