Provide a timeout function to fail quick on blocking operations

It works like the Linux `timeout` utility.
This commit is contained in:
Wei Huang 2021-09-17 10:22:51 -07:00
parent 6a84310f8b
commit d7bf9d724f
No known key found for this signature in database
GPG Key ID: BE5E9752F8B6E005
2 changed files with 41 additions and 4 deletions

View File

@ -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)
}

View File

@ -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
}