From 42c6b723f6bd08615e559631f52caaa90a7ecc3b Mon Sep 17 00:00:00 2001 From: Matthew Buckingham-Bishop Date: Thu, 5 Mar 2026 00:16:14 -0800 Subject: [PATCH] test(notifier): add regression test for stale unregister on re-register Add TestNotifierReRegisterKeepsNewestSlot to reproduce the race where an old unregister callback can remove a newer worker registration. This test fails without the follow-up notifier fix. --- internal/controller/notifier/notifier_test.go | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/internal/controller/notifier/notifier_test.go b/internal/controller/notifier/notifier_test.go index f5392fc..7a198c2 100644 --- a/internal/controller/notifier/notifier_test.go +++ b/internal/controller/notifier/notifier_test.go @@ -47,3 +47,36 @@ func TestNotifier(t *testing.T) { wg.Wait() } + +func TestNotifierReRegisterKeepsNewestSlot(t *testing.T) { + ctx := context.Background() + watcher := notifier.NewNotifier(zap.NewNop().Sugar()) + + const worker = "worker-a" + + _, staleCancel := watcher.Register(ctx, worker) + newestCh, newestCancel := watcher.Register(ctx, worker) + defer newestCancel() + + // Simulate stale connection cleanup arriving after the worker has already re-registered. + staleCancel() + + notifyCtx, notifyCancel := context.WithTimeout(ctx, 300*time.Millisecond) + defer notifyCancel() + + notifyErrCh := make(chan error, 1) + go func() { + notifyErrCh <- watcher.Notify(notifyCtx, worker, nil) + }() + + select { + case <-newestCh: + case err := <-notifyErrCh: + require.NoError(t, err) + t.Fatal("notify returned before delivering message to newest registration") + case <-time.After(time.Second): + t.Fatal("timed out waiting for notify delivery") + } + + require.NoError(t, <-notifyErrCh) +}