From e04d25c222acbcb03c51cb5dd2023fd140bff4ad Mon Sep 17 00:00:00 2001 From: Patrick Ohly Date: Thu, 12 Mar 2026 09:52:42 +0100 Subject: [PATCH] apiserver testing: fix support for pre-created TContext When StartTestServer is called with a TContext by the caller, tearing down the apiserver via its tear-down function would also cancel the context for everyone else using it, which is unexpected and not intended. Accidentally, scheduler_perf and scheduler/batch relied on this behavior: - The apiserver clients waited on a context that got its cancellation from the root context and thus gets canceled last. - The apiserver was told to stop earlier, but then waited because it still had active clients. - Shutdown gets slowed down enough that integration testing times out. The fix is to explicitly cancel the clients before the apiserver. Long-term ktesting should be changed to do the same as the new testing.T.Context: cancel the context *before* cleaning up, not *after* it. --- cmd/kube-apiserver/app/testing/testserver.go | 6 +++++- test/integration/scheduler/batch/batch_test.go | 5 ++++- test/integration/scheduler_perf/util.go | 5 ++++- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/cmd/kube-apiserver/app/testing/testserver.go b/cmd/kube-apiserver/app/testing/testserver.go index fd55cb1c602..5629bebe5f5 100644 --- a/cmd/kube-apiserver/app/testing/testserver.go +++ b/cmd/kube-apiserver/app/testing/testserver.go @@ -156,7 +156,11 @@ func NewDefaultTestServerOptions() *TestServerInstanceOptions { func StartTestServer(t ktesting.TB, instanceOptions *TestServerInstanceOptions, customFlags []string, storageConfig *storagebackend.Config) (result TestServer, err error) { // Some callers may have initialize ktesting already. tCtx, ok := t.(ktesting.TContext) - if !ok { + if ok { + // tCtx.Cancel below must not cancel whatever else might be using + // this existing TContext. + tCtx = tCtx.WithCancel() + } else { tCtx = ktesting.Init(t) } diff --git a/test/integration/scheduler/batch/batch_test.go b/test/integration/scheduler/batch/batch_test.go index d33a71d046b..2f6ca5d360a 100644 --- a/test/integration/scheduler/batch/batch_test.go +++ b/test/integration/scheduler/batch/batch_test.go @@ -597,9 +597,12 @@ func mustSetupCluster(tCtx ktesting.TContext, config *config.KubeSchedulerConfig tCtx.Fatalf("start apiserver: %v", err) } // Cleanup will be in reverse order: first the clients by canceling the - // child context (happens automatically), then the server. + // child context, then the server. tCtx.Cleanup(server.TearDownFn) tCtx = tCtx.WithCancel() + tCtx.Cleanup(func() { + tCtx.Cancel("test is done") + }) // TODO: client connection configuration, such as QPS or Burst is configurable in theory, this could be derived from the `config`, need to // support this when there is any testcase that depends on such configuration. diff --git a/test/integration/scheduler_perf/util.go b/test/integration/scheduler_perf/util.go index 5fcd1619c03..2edf84d1baa 100644 --- a/test/integration/scheduler_perf/util.go +++ b/test/integration/scheduler_perf/util.go @@ -112,9 +112,12 @@ func mustSetupCluster(tCtx ktesting.TContext, config *config.KubeSchedulerConfig tCtx.Fatalf("start apiserver: %v", err) } // Cleanup will be in reverse order: first the clients by canceling the - // child context (happens automatically), then the server. + // child context, then the server. tCtx.Cleanup(server.TearDownFn) tCtx = tCtx.WithCancel() + tCtx.Cleanup(func() { + tCtx.Cancel("test is done") + }) // TODO: client connection configuration, such as QPS or Burst is configurable in theory, this could be derived from the `config`, need to // support this when there is any testcase that depends on such configuration.