diff --git a/test/integration/scheduler/queue_test.go b/test/integration/scheduler/queue_test.go index 35e0fecdb35..42902195cca 100644 --- a/test/integration/scheduler/queue_test.go +++ b/test/integration/scheduler/queue_test.go @@ -139,7 +139,7 @@ func TestServiceAffinityEnqueue(t *testing.T) { } // Pop Pod2 out. It should be unschedulable. - podInfo := testCtx.Scheduler.NextPod() + podInfo := nextPodOrDie(t, testCtx) fwk, ok := testCtx.Scheduler.Profiles[podInfo.Pod.Spec.SchedulerName] if !ok { t.Fatalf("Cannot find the profile for Pod %v", podInfo.Pod.Name) @@ -164,7 +164,7 @@ func TestServiceAffinityEnqueue(t *testing.T) { } // Now we should be able to pop the Pod from activeQ again. - podInfo = testCtx.Scheduler.NextPod() + podInfo = nextPodOrDie(t, testCtx) if podInfo.Attempts != 2 { t.Errorf("Expected the Pod to be attempted 2 times, but got %v", podInfo.Attempts) } @@ -304,7 +304,7 @@ func TestCustomResourceEnqueue(t *testing.T) { } // Pop fake-pod out. It should be unschedulable. - podInfo := testCtx.Scheduler.NextPod() + podInfo := nextPodOrDie(t, testCtx) fwk, ok := testCtx.Scheduler.Profiles[podInfo.Pod.Spec.SchedulerName] if !ok { t.Fatalf("Cannot find the profile for Pod %v", podInfo.Pod.Name) @@ -336,7 +336,7 @@ func TestCustomResourceEnqueue(t *testing.T) { } // Now we should be able to pop the Pod from activeQ again. - podInfo = testCtx.Scheduler.NextPod() + podInfo = nextPodOrDie(t, testCtx) if podInfo.Attempts != 2 { t.Errorf("Expected the Pod to be attempted 2 times, but got %v", podInfo.Attempts) } diff --git a/test/integration/scheduler/util.go b/test/integration/scheduler/util.go index e28be7d063f..dc43ae1b285 100644 --- a/test/integration/scheduler/util.go +++ b/test/integration/scheduler/util.go @@ -40,6 +40,7 @@ import ( "k8s.io/kubernetes/pkg/controller/disruption" "k8s.io/kubernetes/pkg/scheduler" configtesting "k8s.io/kubernetes/pkg/scheduler/apis/config/testing" + "k8s.io/kubernetes/pkg/scheduler/framework" "k8s.io/kubernetes/pkg/scheduler/framework/plugins/defaultpreemption" st "k8s.io/kubernetes/pkg/scheduler/testing" testutils "k8s.io/kubernetes/test/integration/util" @@ -511,3 +512,39 @@ func createNamespacesWithLabels(cs clientset.Interface, namespaces []string, lab } return nil } + +// timeout returns a timeout error if the given `f` function doesn't +// complete within `d` duration; otherwise it returns nil. +func timeout(ctx context.Context, d time.Duration, f func()) error { + ctx, cancel := context.WithTimeout(ctx, d) + defer cancel() + + done := make(chan struct{}) + go func() { + f() + done <- struct{}{} + }() + + select { + case <-done: + return nil + case <-ctx.Done(): + return ctx.Err() + } +} + +// nextPodOrDie returns the next Pod in the scheduler queue. +// The operation needs to be completed within 15 seconds; otherwise the test gets aborted. +func nextPodOrDie(t *testing.T, testCtx *testutils.TestContext) *framework.QueuedPodInfo { + t.Helper() + + var podInfo *framework.QueuedPodInfo + // NextPod() is a blocking operation. Wrap it in timeout() to avoid relying on + // default go testing timeout (10m) to abort. + if err := timeout(testCtx.Ctx, time.Second*15, func() { + podInfo = testCtx.Scheduler.NextPod() + }); err != nil { + t.Fatalf("Timed out waiting for the Pod to be popped: %v", err) + } + return podInfo +}