Repository: kubernetes/kubernetes (language: go)

Issue:
DRA: Unit test TestRegistrationHandler panics
The test panics in a goroutine after the test itself is finished, so it's only reproducible when this artificial delay is added to the test code:
```
$ git diff
diff --git a/pkg/kubelet/cm/dra/plugin/registration_test.go b/pkg/kubelet/cm/dra/plugin/registration_test.go
index 59f3099ab65..9dcb8613588 100644
--- a/pkg/kubelet/cm/dra/plugin/registration_test.go
+++ b/pkg/kubelet/cm/dra/plugin/registration_test.go
@@ -221,4 +221,5 @@ func TestRegistrationHandler(t *testing.T) {
                        assert.Equal(t, test.chosenService, plugin.chosenService, "chosen service")
                })
        }
+       time.Sleep(5 * time.Second)
 }
```

After that the issue can be reproduced just by running the test:
```
~/go/src/k8s.io/kubernetes (master) $ go test -race -v -run ^TestRegistrationHandler$ k8s.io/kubernetes/pkg/kubelet/cm/dra/plugin
=== RUN   TestRegistrationHandler
=== RUN   TestRegistrationHandler/no-services-provided
I0325 17:53:02.848455 1895722 registration.go:184] "Register new DRA plugin" logger="DRA registration handler" pluginName="pluginA" endpoint="endpointA"
    registration_test.go:180: I0325 17:53:02.848520] Removing plugin pluginA
I0325 17:53:02.848594 1895722 registration.go:267] "Deregister DRA plugin" logger="DRA registration handler" pluginName="pluginA" endpoint="endpointA" lastInstance=true
=== RUN   TestRegistrationHandler/current-service
I0325 17:53:02.848826 1895722 registration.go:184] "Register new DRA plugin" logger="DRA registration handler" pluginName="pluginA" endpoint="endpointA"
I0325 17:53:02.848875 1895722 registration.go:184] "Register new DRA plugin" logger="DRA registration handler" pluginName="pluginB" endpoint="endpointB"
    registration_test.go:213: I0325 17:53:02.848924] Removing plugin pluginB
I0325 17:53:02.848993 1895722 registration.go:267] "Deregister DRA plugin" logger="DRA registration handler" pluginName="pluginB" endpoint="endpointB" lastInstance=true
I0325 17:53:02.849122 1895722 registration.go:312] "Deregister DRA plugin not necessary, was already removed" logger="DRA registration handler"
    registration_test.go:180: I0325 17:53:02.849150] Removing plugin pluginA
I0325 17:53:02.849436 1895722 registration.go:267] "Deregister DRA plugin" logger="DRA registration handler" pluginName="pluginA" endpoint="endpointA" lastInstance=true
=== RUN   TestRegistrationHandler/two-services
I0325 17:53:02.850584 1895722 registration.go:184] "Register new DRA plugin" logger="DRA registration handler" pluginName="pluginA" endpoint="endpointA"
I0325 17:53:02.850754 1895722 registration.go:184] "Register new DRA plugin" logger="DRA registration handler" pluginName="pluginB" endpoint="endpointB"
    registration_test.go:213: I0325 17:53:02.850872] Removing plugin pluginB
I0325 17:53:02.851081 1895722 registration.go:267] "Deregister DRA plugin" logger="DRA registration handler" pluginName="pluginB" endpoint="endpointB" lastInstance=true
I0325 17:53:02.851191 1895722 registration.go:312] "Deregister DRA plugin not necessary, was already removed" logger="DRA registration handler"
    registration_test.go:180: I0325 17:53:02.851245] Removing plugin pluginA
I0325 17:53:02.851431 1895722 registration.go:267] "Deregister DRA plugin" logger="DRA registration handler" pluginName="pluginA" endpoint="endpointA" lastInstance=true
=== RUN   TestRegistrationHandler/old-service
I0325 17:53:02.852001 1895722 registration.go:184] "Register new DRA plugin" logger="DRA registration handler" pluginName="pluginA" endpoint="endpointA"
I0325 17:53:02.852127 1895722 registration.go:184] "Register new DRA plugin" logger="DRA registration handler" pluginName="pluginB" endpoint="endpointB"
    registration_test.go:213: I0325 17:53:02.852245] Removing plugin pluginB
I0325 17:53:02.852431 1895722 registration.go:267] "Deregister DRA plugin" logger="DRA registration handler" pluginName="pluginB" endpoint="endpointB" lastInstance=true
I0325 17:53:02.852534 1895722 registration.go:312] "Deregister DRA plugin not necessary, was already removed" logger="DRA registration handler"
    registration_test.go:180: I0325 17:53:02.852590] Removing plugin pluginA
I0325 17:53:02.852775 1895722 registration.go:267] "Deregister DRA plugin" logger="DRA registration handler" pluginName="pluginA" endpoint="endpointA" lastInstance=true
=== RUN   TestRegistrationHandler/version
I0325 17:53:02.853223 1895722 registration.go:184] "Register new DRA plugin" logger="DRA registration handler" pluginName="pluginA" endpoint="endpointA"
I0325 17:53:02.853270 1895722 registration.go:184] "Register new DRA plugin" logger="DRA registration handler" pluginName="pluginB" endpoint="endpointB"
    registration_test.go:213: I0325 17:53:02.853311] Removing plugin pluginB
I0325 17:53:02.853384 1895722 registration.go:267] "Deregister DRA plugin" logger="DRA registration handler" pluginName="pluginB" endpoint="endpointB" lastInstance=true
I0325 17:53:02.853424 1895722 registration.go:312] "Deregister DRA plugin not necessary, was already removed" logger="DRA registration handler"
    registration_test.go:180: I0325 17:53:02.853445] Removing plugin pluginA
I0325 17:53:02.853509 1895722 registration.go:267] "Deregister DRA plugin" logger="DRA registration handler" pluginName="pluginA" endpoint="endpointA" lastInstance=true
=== RUN   TestRegistrationHandler/replace
I0325 17:53:02.853710 1895722 registration.go:184] "Register new DRA plugin" logger="DRA registration handler" pluginName="pluginA" endpoint="endpointA"
I0325 17:53:02.853753 1895722 registration.go:184] "Register new DRA plugin" logger="DRA registration handler" pluginName="pluginA" endpoint="endpointB"
    registration_test.go:213: I0325 17:53:02.853788] Removing plugin pluginA
I0325 17:53:02.853853 1895722 registration.go:267] "Deregister DRA plugin" logger="DRA registration handler" pluginName="pluginA" endpoint="endpointB" lastInstance=false
I0325 17:53:02.853878 1895722 registration.go:312] "Deregister DRA plugin not necessary, was already removed" logger="DRA registration handler"
    registration_test.go:180: I0325 17:53:02.853897] Removing plugin pluginA
I0325 17:53:02.853959 1895722 registration.go:267] "Deregister DRA plugin" logger="DRA registration handler" pluginName="pluginA" endpoint="endpointA" lastInstance=true
=== RUN   TestRegistrationHandler/manage-resource-slices
I0325 17:53:03.358086 1895722 registration.go:149] "Deleted ResourceSlices" logger="DRA registration handler.startup" fieldSelector="spec.nodeName=worker"
I0325 17:53:04.358169 1895722 registration.go:184] "Register new DRA plugin" logger="DRA registration handler" pluginName="pluginA" endpoint="endpointA"
I0325 17:53:04.358360 1895722 registration.go:184] "Register new DRA plugin" logger="DRA registration handler" pluginName="pluginB" endpoint="endpointB"
    registration_test.go:213: I0325 17:53:04.361137] Removing plugin pluginB
I0325 17:53:04.361373 1895722 registration.go:267] "Deregister DRA plugin" logger="DRA registration handler" pluginName="pluginB" endpoint="endpointB" lastInstance=true
I0325 17:53:04.361493 1895722 registration.go:312] "Deregister DRA plugin not necessary, was already removed" logger="DRA registration handler"
I0325 17:53:04.361615 1895722 registration.go:114] "Starting to wait before wiping ResourceSlices" logger="DRA registration handler.driver-cleanup" pluginName="pluginB" delay="1s"
I0325 17:53:05.362238 1895722 registration.go:119] "Starting to wipe ResourceSlices after waiting" logger="DRA registration handler.driver-cleanup" pluginName="pluginB" delay="1s"
I0325 17:53:05.362815 1895722 registration.go:149] "Deleted ResourceSlices" logger="DRA registration handler.driver-cleanup" pluginName="pluginB" fieldSelector="spec.driver=pluginB,spec.nodeName=worker"
    registration_test.go:180: I0325 17:53:06.362364] Removing plugin pluginA
I0325 17:53:06.362632 1895722 registration.go:267] "Deregister DRA plugin" logger="DRA registration handler" pluginName="pluginA" endpoint="endpointA" lastInstance=true
I0325 17:53:06.362894 1895722 registration.go:114] "Starting to wait before wiping ResourceSlices" logger="DRA registration handler.driver-cleanup" pluginName="pluginA" delay="1s"
I0325 17:53:07.363472 1895722 registration.go:119] "Starting to wipe ResourceSlices after waiting" logger="DRA registration handler.driver-cleanup" pluginName="pluginA" delay="1s"
E0325 17:53:07.364902 1895722 testing.go:988] "Observed a panic" logger="DRA registration handler.driver-cleanup" pluginName="pluginA" panic="Fail in goroutine after TestRegistrationHandler/manage-resource-slices has completed" stacktrace=<
        goroutine 149 [running]:
        k8s.io/apimachinery/pkg/util/runtime.logPanic({0x3a70ec8, 0xc000e20660}, {0x31bb740, 0xc0001b3070})
                /home/ed/go/src/k8s.io/kubernetes/staging/src/k8s.io/apimachinery/pkg/util/runtime/runtime.go:132 +0xdd
        k8s.io/apimachinery/pkg/util/runtime.handleCrash({0x3a70ec8, 0xc0005f4540}, {0x31bb740, 0xc0001b3070}, {0x0, 0x0, 0x4b54f2?})
                /home/ed/go/src/k8s.io/kubernetes/staging/src/k8s.io/apimachinery/pkg/util/runtime/runtime.go:107 +0x185
        k8s.io/apimachinery/pkg/util/runtime.HandleCrashWithContext({0x3a70ec8, 0xc0005f4540}, {0x0, 0x0, 0x0})
                /home/ed/go/src/k8s.io/kubernetes/staging/src/k8s.io/apimachinery/pkg/util/runtime/runtime.go:78 +0x69
        panic({0x31bb740?, 0xc0001b3070?})
                /usr/local/go/src/runtime/panic.go:792 +0x132
        testing.(*common).Fail(0xc000503c00)
                /usr/local/go/src/testing/testing.go:988 +0x185
        testing.(*common).Errorf(0xc000503c00, {0x367ea26, 0x3}, {0xc0001b3030, 0x1, 0x1})
                /usr/local/go/src/testing/testing.go:1111 +0xa9
        github.com/stretchr/testify/assert.Fail({0x3a501c0, 0xc000503c00}, {0xc000504900, 0xf5}, {0xc0009beee0, 0x1, 0x1})
                /home/ed/go/src/k8s.io/kubernetes/vendor/github.com/stretchr/testify/assert/assertions.go:369 +0x44c
        github.com/stretchr/testify/assert.Equal({0x3a501c0, 0xc000503c00}, {0x31bb740, 0xc0001b2ea0}, {0x31bb740, 0xc0001b2eb0}, {0xc0009beee0, 0x1, 0x1})
                /home/ed/go/src/k8s.io/kubernetes/vendor/github.com/stretchr/testify/assert/assertions.go:472 +0x3d8
        k8s.io/kubernetes/pkg/kubelet/cm/dra/plugin.TestRegistrationHandler.func1.1({0x3a776f0, 0xc0005c2900})
                /home/ed/go/src/k8s.io/kubernetes/pkg/kubelet/cm/dra/plugin/registration_test.go:142 +0x369
        k8s.io/client-go/testing.(*SimpleReactor).React(0xc00112c720, {0x3a776f0, 0xc0005c2900})
                /home/ed/go/src/k8s.io/kubernetes/staging/src/k8s.io/client-go/testing/fixture.go:882 +0x53
        k8s.io/client-go/testing.(*Fake).Invokes(0xc000610000, {0x3a776f0, 0xc0005c2780}, {0x3a59408, 0xc001202380})
                /home/ed/go/src/k8s.io/kubernetes/staging/src/k8s.io/client-go/testing/fake.go:145 +0x36a
        k8s.io/client-go/gentype.(*alsoFakeLister[...]).DeleteCollection(_, {_, _}, {{{0x0, 0x0}, {0x0, 0x0}}, 0x0, 0x0, 0x0, ...}, ...)
                /home/ed/go/src/k8s.io/kubernetes/staging/src/k8s.io/client-go/gentype/fake.go:235 +0x29b
        k8s.io/kubernetes/pkg/kubelet/cm/dra/plugin.(*RegistrationHandler).wipeResourceSlices.func1({0x3a70ec8, 0xc0005f4540})
                /home/ed/go/src/k8s.io/kubernetes/pkg/kubelet/cm/dra/plugin/registration.go:146 +0x370
        k8s.io/apimachinery/pkg/util/wait.runConditionWithCrashProtectionWithContext({0x3a70ec8, 0xc0005f4540}, 0xc000029ed0)
                /home/ed/go/src/k8s.io/kubernetes/staging/src/k8s.io/apimachinery/pkg/util/wait/wait.go:159 +0xca
        k8s.io/apimachinery/pkg/util/wait.ExponentialBackoffWithContext({0x3a70ec8, 0xc0005f4540}, {0x3b9aca00, 0x4000000000000000, 0x3fc999999999999a, 0x64, 0x45d964b800}, 0xc0009bfed0)
                /home/ed/go/src/k8s.io/kubernetes/staging/src/k8s.io/apimachinery/pkg/util/wait/backoff.go:501 +0xc5
        k8s.io/kubernetes/pkg/kubelet/cm/dra/plugin.(*RegistrationHandler).wipeResourceSlices(0xc00112a980, {0x3a70ec8, 0xc0005f4540}, 0x3b9aca00, {0x36820e2, 0x7})
                /home/ed/go/src/k8s.io/kubernetes/pkg/kubelet/cm/dra/plugin/registration.go:132 +0x633
        k8s.io/kubernetes/pkg/kubelet/cm/dra/plugin.(*RegistrationHandler).DeRegisterPlugin.func1()
                /home/ed/go/src/k8s.io/kubernetes/pkg/kubelet/cm/dra/plugin/registration.go:306 +0x14f
        created by k8s.io/kubernetes/pkg/kubelet/cm/dra/plugin.(*RegistrationHandler).DeRegisterPlugin in goroutine 141
                /home/ed/go/src/k8s.io/kubernetes/pkg/kubelet/cm/dra/plugin/registration.go:294 +0x80a
 >
panic: Fail in goroutine after TestRegistrationHandler/manage-resource-slices has completed [recovered]
        panic: Fail in goroutine after TestRegistrationHandler/manage-resource-slices has completed

goroutine 149 [running]:
k8s.io/apimachinery/pkg/util/runtime.handleCrash({0x3a70ec8, 0xc0005f4540}, {0x31bb740, 0xc0001b3070}, {0x0, 0x0, 0x4b54f2?})
        /home/ed/go/src/k8s.io/kubernetes/staging/src/k8s.io/apimachinery/pkg/util/runtime/runtime.go:114 +0x23a
k8s.io/apimachinery/pkg/util/runtime.HandleCrashWithContext({0x3a70ec8, 0xc0005f4540}, {0x0, 0x0, 0x0})
        /home/ed/go/src/k8s.io/kubernetes/staging/src/k8s.io/apimachinery/pkg/util/runtime/runtime.go:78 +0x69
panic({0x31bb740?, 0xc0001b3070?})
        /usr/local/go/src/runtime/panic.go:792 +0x132
testing.(*common).Fail(0xc000503c00)
        /usr/local/go/src/testing/testing.go:988 +0x185
testing.(*common).Errorf(0xc000503c00, {0x367ea26, 0x3}, {0xc0001b3030, 0x1, 0x1})
        /usr/local/go/src/testing/testing.go:1111 +0xa9
github.com/stretchr/testify/assert.Fail({0x3a501c0, 0xc000503c00}, {0xc000504900, 0xf5}, {0xc0009beee0, 0x1, 0x1})
        /home/ed/go/src/k8s.io/kubernetes/vendor/github.com/stretchr/testify/assert/assertions.go:369 +0x44c
github.com/stretchr/testify/assert.Equal({0x3a501c0, 0xc000503c00}, {0x31bb740, 0xc0001b2ea0}, {0x31bb740, 0xc0001b2eb0}, {0xc0009beee0, 0x1, 0x1})
        /home/ed/go/src/k8s.io/kubernetes/vendor/github.com/stretchr/testify/assert/assertions.go:472 +0x3d8
k8s.io/kubernetes/pkg/kubelet/cm/dra/plugin.TestRegistrationHandler.func1.1({0x3a776f0, 0xc0005c2900})
        /home/ed/go/src/k8s.io/kubernetes/pkg/kubelet/cm/dra/plugin/registration_test.go:142 +0x369
k8s.io/client-go/testing.(*SimpleReactor).React(0xc00112c720, {0x3a776f0, 0xc0005c2900})
        /home/ed/go/src/k8s.io/kubernetes/staging/src/k8s.io/client-go/testing/fixture.go:882 +0x53
k8s.io/client-go/testing.(*Fake).Invokes(0xc000610000, {0x3a776f0, 0xc0005c2780}, {0x3a59408, 0xc001202380})
        /home/ed/go/src/k8s.io/kubernetes/staging/src/k8s.io/client-go/testing/fake.go:145 +0x36a
k8s.io/client-go/gentype.(*alsoFakeLister[...]).DeleteCollection(_, {_, _}, {{{0x0, 0x0}, {0x0, 0x0}}, 0x0, 0x0, 0x0, ...}, ...)
        /home/ed/go/src/k8s.io/kubernetes/staging/src/k8s.io/client-go/gentype/fake.go:235 +0x29b
k8s.io/kubernetes/pkg/kubelet/cm/dra/plugin.(*RegistrationHandler).wipeResourceSlices.func1({0x3a70ec8, 0xc0005f4540})
        /home/ed/go/src/k8s.io/kubernetes/pkg/kubelet/cm/dra/plugin/registration.go:146 +0x370
k8s.io/apimachinery/pkg/util/wait.runConditionWithCrashProtectionWithContext({0x3a70ec8, 0xc0005f4540}, 0xc000029ed0)
        /home/ed/go/src/k8s.io/kubernetes/staging/src/k8s.io/apimachinery/pkg/util/wait/wait.go:159 +0xca
k8s.io/apimachinery/pkg/util/wait.ExponentialBackoffWithContext({0x3a70ec8, 0xc0005f4540}, {0x3b9aca00, 0x4000000000000000, 0x3fc999999999999a, 0x64, 0x45d964b800}, 0xc0009bfed0)
        /home/ed/go/src/k8s.io/kubernetes/staging/src/k8s.io/apimachinery/pkg/util/wait/backoff.go:501 +0xc5
k8s.io/kubernetes/pkg/kubelet/cm/dra/plugin.(*RegistrationHandler).wipeResourceSlices(0xc00112a980, {0x3a70ec8, 0xc0005f4540}, 0x3b9aca00, {0x36820e2, 0x7})
        /home/ed/go/src/k8s.io/kubernetes/pkg/kubelet/cm/dra/plugin/registration.go:132 +0x633
k8s.io/kubernetes/pkg/kubelet/cm/dra/plugin.(*RegistrationHandler).DeRegisterPlugin.func1()
        /home/ed/go/src/k8s.io/kubernetes/pkg/kubelet/cm/dra/plugin/registration.go:306 +0x14f
created by k8s.io/kubernetes/pkg/kubelet/cm/dra/plugin.(*RegistrationHandler).DeRegisterPlugin in goroutine 141
        /home/ed/go/src/k8s.io/kubernetes/pkg/kubelet/cm/dra/plugin/registration.go:294 +0x80a
FAIL    k8s.io/kubernetes/pkg/kubelet/cm/dra/plugin     4.609s
FAIL
```


Discussion / hints:
This issue is currently awaiting triage.

If a SIG or subproject determines this is a relevant issue, they will accept it by applying the `triage/accepted` label and provide further guidance.

The `triage/accepted` label can be added by org members by writing `/triage accepted` in a comment.


<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes-sigs/prow](https://github.com/kubernetes-sigs/prow/issues/new?title=Prow%20issue:) repository.
</details>
/sig node
/assign 
/cc @pohly 
/sig node

Fix patch:
diff --git a/pkg/kubelet/cm/dra/plugin/registration.go b/pkg/kubelet/cm/dra/plugin/registration.go
index 1d95e582e0a85..0f410c4290b89 100644
--- a/pkg/kubelet/cm/dra/plugin/registration.go
+++ b/pkg/kubelet/cm/dra/plugin/registration.go
@@ -52,10 +52,12 @@ type RegistrationHandler struct {
 	// This is necessary because it implements APIs which don't
 	// provide a context.
 	backgroundCtx context.Context
+	cancel        func(err error)
 	kubeClient    kubernetes.Interface
 	getNode       func() (*v1.Node, error)
 	wipingDelay   time.Duration
 
+	wg    sync.WaitGroup
 	mutex sync.Mutex
 
 	// pendingWipes maps a plugin name to a cancel function for
@@ -76,9 +78,15 @@ var _ cache.PluginHandler = &RegistrationHandler{}
 // If a kubeClient is provided, then it synchronizes ResourceSlices
 // with the resource information provided by plugins.
 func NewRegistrationHandler(kubeClient kubernetes.Interface, getNode func() (*v1.Node, error), wipingDelay time.Duration) *RegistrationHandler {
+	// The context and thus logger should come from the caller.
+	return newRegistrationHandler(context.TODO(), kubeClient, getNode, wipingDelay)
+}
+
+func newRegistrationHandler(ctx context.Context, kubeClient kubernetes.Interface, getNode func() (*v1.Node, error), wipingDelay time.Duration) *RegistrationHandler {
+	ctx, cancel := context.WithCancelCause(ctx)
 	handler := &RegistrationHandler{
-		// The context and thus logger should come from the caller.
-		backgroundCtx: klog.NewContext(context.TODO(), klog.LoggerWithName(klog.TODO(), "DRA registration handler")),
+		backgroundCtx: klog.NewContext(ctx, klog.LoggerWithName(klog.FromContext(ctx), "DRA registration handler")),
+		cancel:        cancel,
 		kubeClient:    kubeClient,
 		getNode:       getNode,
 		wipingDelay:   wipingDelay,
@@ -92,13 +100,24 @@ func NewRegistrationHandler(kubeClient kubernetes.Interface, getNode func() (*v1
 	// to start up.
 	//
 	// This has to run in the background.
-	logger := klog.LoggerWithName(klog.FromContext(handler.backgroundCtx), "startup")
-	ctx := klog.NewContext(handler.backgroundCtx, logger)
-	go handler.wipeResourceSlices(ctx, 0 /* no delay */, "" /* all drivers */)
+	handler.wg.Add(1)
+	go func() {
+		defer handler.wg.Done()
+
+		logger := klog.LoggerWithName(klog.FromContext(handler.backgroundCtx), "startup")
+		ctx := klog.NewContext(handler.backgroundCtx, logger)
+		handler.wipeResourceSlices(ctx, 0 /* no delay */, "" /* all drivers */)
+	}()
 
 	return handler
 }
 
+// Stop cancels any remaining background activities and blocks until all goroutines have stopped.
+func (h *RegistrationHandler) Stop() {
+	h.cancel(errors.New("Stop was called"))
+	h.wg.Wait()
+}
+
 // wipeResourceSlices deletes ResourceSlices of the node, optionally just for a specific driver.
 // Wiping will delay for a while and can be canceled by canceling the context.
 func (h *RegistrationHandler) wipeResourceSlices(ctx context.Context, delay time.Duration, driver string) {
@@ -291,7 +310,9 @@ func (h *RegistrationHandler) DeRegisterPlugin(pluginName, endpoint string) {
 		}
 		h.pendingWipes[pluginName] = &cancel
 
+		h.wg.Add(1)
 		go func() {
+			defer h.wg.Done()
 			defer func() {
 				h.mutex.Lock()
 				defer h.mutex.Unlock()


Test patch:
diff --git a/pkg/kubelet/cm/dra/plugin/registration_test.go b/pkg/kubelet/cm/dra/plugin/registration_test.go
index 59f3099ab6500..2013563b74442 100644
--- a/pkg/kubelet/cm/dra/plugin/registration_test.go
+++ b/pkg/kubelet/cm/dra/plugin/registration_test.go
@@ -149,15 +149,26 @@ func TestRegistrationHandler(t *testing.T) {
 					// Set expected slice fields for the next call of this reactor.
 					// The reactor will be called next time when resourceslices object is deleted
 					// by the kubelet after plugin deregistration.
-					expectedSliceFields = fields.Set{"spec.nodeName": nodeName, "spec.driver": test.pluginName}
-
+					switch len(expectedSliceFields) {
+					case 1:
+						// Startup cleanup done, now expect cleanup for test plugin.
+						expectedSliceFields = fields.Set{"spec.nodeName": nodeName, "spec.driver": test.pluginName}
+					case 2:
+						// Test plugin cleanup done, now expect cleanup for the other plugin.
+						otherPlugin := pluginA
+						if otherPlugin == test.pluginName {
+							otherPlugin = pluginB
+						}
+						expectedSliceFields = fields.Set{"spec.nodeName": nodeName, "spec.driver": otherPlugin}
+					}
 					return true, nil, err
 				})
 				client = fakeClient
 			}
 
 			// The handler wipes all slices at startup.
-			handler := NewRegistrationHandler(client, getFakeNode, time.Second /* very short wiping delay for testing */)
+			handler := newRegistrationHandler(tCtx, client, getFakeNode, time.Second /* very short wiping delay for testing */)
+			tCtx.Cleanup(handler.Stop)
 			requireNoSlices := func() {
 				t.Helper()
 				if client == nil {