Repository: kubernetes/kubernetes
Pull request #131266: fix: Watcher deadlock from Stop not being called
Author: login: karlkfi
Labels: name: kind/bug
description: Categorizes issue or PR as related to a bug.
name: kind/cleanup
description: Categorizes issue or PR as related to cleaning up code, process, or technical debt.
name: lgtm
description: "Looks good to me", indicates that a PR is ready to be merged.
name: sig/api-machinery
description: Categorizes an issue or PR as relevant to SIG API Machinery.
name: release-note
description: Denotes a PR that will be considered when it comes time to generate release notes.
name: size/L
description: Denotes a PR that changes 100-499 lines, ignoring generated files.
name: approved
description: Indicates a PR has been approved by an approver from all required OWNERS files.
name: cncf-cla: yes
description: Indicates the PR's author has signed the CNCF CLA.
name: needs-priority
description: Indicates a PR lacks a `priority/foo` label and requires one.
name: triage/accepted
description: Indicates an issue or PR is ready to be actively worked on.
Created: 2025-04-11T21:50:00Z | Merged: 2025-04-24T00:10:13Z

#### What type of PR is this?
/kind bug
/kind cleanup
/sig api-machinery

#### Changes
- Update Reflector.ListAndWatch and Reflector.watch to always call watcher.Stop.
- Update Reflector.handleAnyWatch to always call watcher.Stop, EXCEPT when exitOnWatchListBookmarkReceived && watchListBookmarkReceived.
- Update unit tests with these new expectations.

#### Motivation
- ensure watcher.Stop is always called at least once
- avoid possible deadlock in watcher implementations when watcher.Watch is called, but watcher.Stop is never called.

Note: It's impossible to guarantee that Stop will only be called once. So watch.Interface implementations must tolerate Stop being called multiple times.

#### Does this PR introduce a user-facing change?
```release-note
Fixed a possible deadlock in the watch client that could happen if the watch was not stopped. 
```

#### Supersedes
- https://github.com/kubernetes/kubernetes/pull/125301


Diff:
diff --git a/staging/src/k8s.io/client-go/tools/cache/reflector.go b/staging/src/k8s.io/client-go/tools/cache/reflector.go
index 8e2a827002702..019b3cf187bdf 100644
--- a/staging/src/k8s.io/client-go/tools/cache/reflector.go
+++ b/staging/src/k8s.io/client-go/tools/cache/reflector.go
@@ -406,6 +406,12 @@ func (r *Reflector) ListAndWatchWithContext(ctx context.Context) error {
 	useWatchList := ptr.Deref(r.UseWatchList, false)
 	fallbackToList := !useWatchList
 
+	defer func() {
+		if w != nil {
+			w.Stop()
+		}
+	}()
+
 	if useWatchList {
 		w, err = r.watchList(ctx)
 		if w == nil && err == nil {
@@ -476,12 +482,21 @@ func (r *Reflector) watchWithResync(ctx context.Context, w watch.Interface) erro
 	return r.watch(ctx, w, resyncerrc)
 }
 
-// watch simply starts a watch request with the server.
+// watch starts a watch request with the server, consumes watch events, and
+// restarts the watch until an exit scenario is reached.
+//
+// If a watch is provided, it will be used, otherwise another will be started.
+// If the watcher has started, it will always be stopped before returning.
 func (r *Reflector) watch(ctx context.Context, w watch.Interface, resyncerrc chan error) error {
 	stopCh := ctx.Done()
 	logger := klog.FromContext(ctx)
 	var err error
 	retry := NewRetryWithDeadline(r.MaxInternalErrorRetryDuration, time.Minute, apierrors.IsInternalError, r.clock)
+	defer func() {
+		if w != nil {
+			w.Stop()
+		}
+	}()
 
 	for {
 		// give the stopCh a chance to stop the loop, even in case of continue statements further down on errors
@@ -489,9 +504,6 @@ func (r *Reflector) watch(ctx context.Context, w watch.Interface, resyncerrc cha
 		case <-stopCh:
 			// we can only end up here when the stopCh
 			// was closed after a successful watchlist or list request
-			if w != nil {
-				w.Stop()
-			}
 			return nil
 		default:
 		}
@@ -529,8 +541,8 @@ func (r *Reflector) watch(ctx context.Context, w watch.Interface, resyncerrc cha
 
 		err = handleWatch(ctx, start, w, r.store, r.expectedType, r.expectedGVK, r.name, r.typeDescription, r.setLastSyncResourceVersion,
 			r.clock, resyncerrc)
-		// Ensure that watch will not be reused across iterations.
-		w.Stop()
+		// handleWatch always stops the watcher. So we don't need to here.
+		// Just set it to nil to trigger a retry on the next loop.
 		w = nil
 		retry.After(err)
 		if err != nil {
@@ -863,6 +875,12 @@ func handleAnyWatch(
 	logger := klog.FromContext(ctx)
 	initialEventsEndBookmarkWarningTicker := newInitialEventsEndBookmarkTicker(logger, name, clock, start, exitOnWatchListBookmarkReceived)
 	defer initialEventsEndBookmarkWarningTicker.Stop()
+	stopWatcher := true
+	defer func() {
+		if stopWatcher {
+			w.Stop()
+		}
+	}()
 
 loop:
 	for {
@@ -929,6 +947,7 @@ loop:
 			}
 			eventCount++
 			if exitOnWatchListBookmarkReceived && watchListBookmarkReceived {
+				stopWatcher = false
 				watchDuration := clock.Since(start)
 				klog.FromContext(ctx).V(4).Info("Exiting watch because received the bookmark that marks the end of initial events stream", "reflector", name, "totalItems", eventCount, "duration", watchDuration)
 				return watchListBookmarkReceived, nil
diff --git a/staging/src/k8s.io/client-go/tools/cache/reflector_test.go b/staging/src/k8s.io/client-go/tools/cache/reflector_test.go
index d7614f36411cc..56b53769381ec 100644
--- a/staging/src/k8s.io/client-go/tools/cache/reflector_test.go
+++ b/staging/src/k8s.io/client-go/tools/cache/reflector_test.go
@@ -31,6 +31,8 @@ import (
 	"testing"
 	"time"
 
+	"github.com/google/go-cmp/cmp"
+	"github.com/google/go-cmp/cmp/cmpopts"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 
@@ -48,6 +50,7 @@ import (
 	"k8s.io/klog/v2/ktesting"
 	"k8s.io/utils/clock"
 	testingclock "k8s.io/utils/clock/testing"
+	"k8s.io/utils/ptr"
 )
 
 var nevererrc chan error
@@ -161,8 +164,8 @@ func TestReflectorWatchStoppedBefore(t *testing.T) {
 	require.NoError(t, err)
 }
 
-// TestReflectorWatchStoppedAfter ensures that neither the watcher is stopped if
-// the stop channel is closed after Reflector.watch has started watching.
+// TestReflectorWatchStoppedAfter ensures that Reflector.watch always stops
+// the watcher when the stop channel is closed.
 func TestReflectorWatchStoppedAfter(t *testing.T) {
 	_, ctx := ktesting.NewTestContext(t)
 	ctx, cancel := context.WithCancelCause(ctx)
@@ -206,9 +209,9 @@ func BenchmarkReflectorResyncChanMany(b *testing.B) {
 	}
 }
 
-// TestReflectorHandleWatchStoppedBefore ensures that handleWatch stops when
+// TestReflectorHandleWatchStoppedBefore ensures that handleWatch returns when
 // stopCh is already closed before handleWatch was called. It also ensures that
-// ResultChan is only called once and that Stop is called after ResultChan.
+// ResultChan and Stop are both called once.
 func TestReflectorHandleWatchStoppedBefore(t *testing.T) {
 	s := NewStore(MetaNamespaceKeyFunc)
 	g := NewReflector(&ListWatch{}, &v1.Pod{}, s, 0)
@@ -218,7 +221,7 @@ func TestReflectorHandleWatchStoppedBefore(t *testing.T) {
 	cancel(errors.New("don't run"))
 	var calls []string
 	resultCh := make(chan watch.Event)
-	fw := watch.MockWatcher{
+	fw := &watch.MockWatcher{
 		StopFunc: func() {
 			calls = append(calls, "Stop")
 			close(resultCh)
@@ -229,18 +232,14 @@ func TestReflectorHandleWatchStoppedBefore(t *testing.T) {
 		},
 	}
 	err := handleWatch(ctx, time.Now(), fw, s, g.expectedType, g.expectedGVK, g.name, g.typeDescription, g.setLastSyncResourceVersion, g.clock, nevererrc)
-	if err == nil {
-		t.Errorf("unexpected non-error")
-	}
-	// Ensure the watcher methods are called exactly once in this exact order.
-	// TODO(karlkfi): Fix watchHandler to call Stop()
-	// assert.Equal(t, []string{"ResultChan", "Stop"}, calls)
-	assert.Equal(t, []string{"ResultChan"}, calls)
+	require.Equal(t, err, errorStopRequested)
+	// Ensure handleWatch calls ResultChan and Stop
+	assert.Equal(t, []string{"ResultChan", "Stop"}, calls)
 }
 
-// TestReflectorHandleWatchStoppedAfter ensures that handleWatch stops when
+// TestReflectorHandleWatchStoppedAfter ensures that handleWatch returns when
 // stopCh is closed after handleWatch was called. It also ensures that
-// ResultChan is only called once and that Stop is called after ResultChan.
+// ResultChan and Stop are both called once.
 func TestReflectorHandleWatchStoppedAfter(t *testing.T) {
 	s := NewStore(MetaNamespaceKeyFunc)
 	g := NewReflector(&ListWatch{}, &v1.Pod{}, s, 0)
@@ -248,7 +247,7 @@ func TestReflectorHandleWatchStoppedAfter(t *testing.T) {
 	_, ctx := ktesting.NewTestContext(t)
 	ctx, cancel := context.WithCancelCause(ctx)
 	resultCh := make(chan watch.Event)
-	fw := watch.MockWatcher{
+	fw := &watch.MockWatcher{
 		StopFunc: func() {
 			calls = append(calls, "Stop")
 			close(resultCh)
@@ -266,24 +265,21 @@ func TestReflectorHandleWatchStoppedAfter(t *testing.T) {
 		},
 	}
 	err := handleWatch(ctx, time.Now(), fw, s, g.expectedType, g.expectedGVK, g.name, g.typeDescription, g.setLastSyncResourceVersion, g.clock, nevererrc)
-	if err == nil {
-		t.Errorf("unexpected non-error")
-	}
-	// Ensure the watcher methods are called exactly once in this exact order.
-	// TODO(karlkfi): Fix watchHandler to call Stop()
-	// assert.Equal(t, []string{"ResultChan", "Stop"}, calls)
-	assert.Equal(t, []string{"ResultChan"}, calls)
+	require.Equal(t, err, errorStopRequested)
+	// Ensure handleWatch calls ResultChan and Stop
+	assert.Equal(t, []string{"ResultChan", "Stop"}, calls)
 }
 
 // TestReflectorHandleWatchResultChanClosedBefore ensures that handleWatch
-// stops when the result channel is closed before handleWatch was called.
+// returns when the result channel is closed before handleWatch was called.
+// It also ensures that ResultChan and Stop are both called once.
 func TestReflectorHandleWatchResultChanClosedBefore(t *testing.T) {
 	s := NewStore(MetaNamespaceKeyFunc)
 	g := NewReflector(&ListWatch{}, &v1.Pod{}, s, 0)
 	_, ctx := ktesting.NewTestContext(t)
 	var calls []string
 	resultCh := make(chan watch.Event)
-	fw := watch.MockWatcher{
+	fw := &watch.MockWatcher{
 		StopFunc: func() {
 			calls = append(calls, "Stop")
 		},
@@ -295,24 +291,22 @@ func TestReflectorHandleWatchResultChanClosedBefore(t *testing.T) {
 	// Simulate the result channel being closed by the producer before handleWatch is called.
 	close(resultCh)
 	err := handleWatch(ctx, time.Now(), fw, s, g.expectedType, g.expectedGVK, g.name, g.typeDescription, g.setLastSyncResourceVersion, g.clock, nevererrc)
-	if err == nil {
-		t.Errorf("unexpected non-error")
-	}
-	// Ensure the watcher methods are called exactly once in this exact order.
-	// TODO(karlkfi): Fix watchHandler to call Stop()
-	// assert.Equal(t, []string{"ResultChan", "Stop"}, calls)
-	assert.Equal(t, []string{"ResultChan"}, calls)
+	// TODO(karlkfi): Add exact error type for "very short watch"
+	require.Error(t, err)
+	// Ensure handleWatch calls ResultChan and Stop
+	assert.Equal(t, []string{"ResultChan", "Stop"}, calls)
 }
 
 // TestReflectorHandleWatchResultChanClosedAfter ensures that handleWatch
-// stops when the result channel is closed after handleWatch has started watching.
+// returns when the result channel is closed after handleWatch has started
+// watching. It also ensures that ResultChan and Stop are both called once.
 func TestReflectorHandleWatchResultChanClosedAfter(t *testing.T) {
 	s := NewStore(MetaNamespaceKeyFunc)
 	g := NewReflector(&ListWatch{}, &v1.Pod{}, s, 0)
 	_, ctx := ktesting.NewTestContext(t)
 	var calls []string
 	resultCh := make(chan watch.Event)
-	fw := watch.MockWatcher{
+	fw := &watch.MockWatcher{
 		StopFunc: func() {
 			calls = append(calls, "Stop")
 		},
@@ -329,22 +323,17 @@ func TestReflectorHandleWatchResultChanClosedAfter(t *testing.T) {
 		},
 	}
 	err := handleWatch(ctx, time.Now(), fw, s, g.expectedType, g.expectedGVK, g.name, g.typeDescription, g.setLastSyncResourceVersion, g.clock, nevererrc)
-	if err == nil {
-		t.Errorf("unexpected non-error")
-	}
-	// Ensure the watcher methods are called exactly once in this exact order.
-	// TODO(karlkfi): Fix watchHandler to call Stop()
-	// assert.Equal(t, []string{"ResultChan", "Stop"}, calls)
-	assert.Equal(t, []string{"ResultChan"}, calls)
+	// TODO(karlkfi): Add exact error type for "very short watch"
+	require.Error(t, err)
+	// Ensure handleWatch calls ResultChan and Stop
+	assert.Equal(t, []string{"ResultChan", "Stop"}, calls)
 }
 
 func TestReflectorWatchHandler(t *testing.T) {
 	s := NewStore(MetaNamespaceKeyFunc)
 	g := NewReflector(&ListWatch{}, &v1.Pod{}, s, 0)
 	// Wrap setLastSyncResourceVersion so we can tell the watchHandler to stop
-	// watching after all the events have been consumed. This avoids race
-	// conditions which can happen if the producer calls Stop(), instead of the
-	// consumer.
+	// watching after all the events have been consumed.
 	_, ctx := ktesting.NewTestContext(t)
 	ctx, cancel := context.WithCancelCause(ctx)
 	setLastSyncResourceVersion := func(rv string) {
@@ -361,13 +350,11 @@ func TestReflectorWatchHandler(t *testing.T) {
 		fw.Delete(&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo"}})
 		fw.Modify(&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "bar", ResourceVersion: "55"}})
 		fw.Add(&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "baz", ResourceVersion: "32"}})
-		fw.Stop()
+		// Stop means that the consumer is done reading events.
+		// So let handleWatch call fw.Stop, after the Context is cancelled.
 	}()
 	err := handleWatch(ctx, time.Now(), fw, s, g.expectedType, g.expectedGVK, g.name, g.typeDescription, setLastSyncResourceVersion, g.clock, nevererrc)
-	// TODO(karlkfi): Fix FakeWatcher to avoid race condition between watcher.Stop() & close(stopCh)
-	if err != nil && !errors.Is(err, errorStopRequested) {
-		t.Errorf("unexpected error %v", err)
-	}
+	require.Equal(t, err, errorStopRequested)
 
 	mkPod := func(id string, rv string) *v1.Pod {
 		return &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: id, ResourceVersion: rv}}
@@ -410,70 +397,226 @@ func TestReflectorStopWatch(t *testing.T) {
 	ctx, cancel := context.WithCancelCause(ctx)
 	cancel(errors.New("don't run"))
 	err := handleWatch(ctx, time.Now(), fw, s, g.expectedType, g.expectedGVK, g.name, g.typeDescription, g.setLastSyncResourceVersion, g.clock, nevererrc)
-	if err != errorStopRequested {
-		t.Errorf("expected stop error, got %q", err)
-	}
+	require.Equal(t, err, errorStopRequested)
 }
 
 func TestReflectorListAndWatch(t *testing.T) {
-	_, ctx := ktesting.NewTestContext(t)
-	ctx, cancel := context.WithCancel(ctx)
-	defer cancel()
-	createdFakes := make(chan *watch.FakeWatcher)
-
-	// The ListFunc says that it's at revision 1. Therefore, we expect our WatchFunc
-	// to get called at the beginning of the watch with 1, and again with 3 when we
-	// inject an error.
-	expectedRVs := []string{"1", "3"}
-	lw := &ListWatch{
-		WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
-			rv := options.ResourceVersion
-			fw := watch.NewFake()
-			if e, a := expectedRVs[0], rv; e != a {
-				t.Errorf("Expected rv %v, but got %v", e, a)
-			}
-			expectedRVs = expectedRVs[1:]
-			// channel is not buffered because the for loop below needs to block. But
-			// we don't want to block here, so report the new fake via a go routine.
-			go func() { createdFakes <- fw }()
-			return fw, nil
+	type listResult struct {
+		Object runtime.Object
+		Error  error
+	}
+	table := []struct {
+		name                 string
+		useWatchList         bool
+		listResults          []listResult
+		watchEvents          []watch.Event
+		expectedListOptions  []metav1.ListOptions
+		expectedWatchOptions []metav1.ListOptions
+		expectedStore        []metav1.Object
+	}{
+		{
+			name:         "UseWatchList enabled",
+			useWatchList: true,
+			watchEvents: []watch.Event{
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "1"}},
+				},
+				{
+					Type: watch.Bookmark,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{
+						Name:            "foo",
+						ResourceVersion: "1",
+						Annotations:     map[string]string{metav1.InitialEventsAnnotationKey: "true"},
+					}},
+				},
+				{
+					Type:   watch.Modified,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "2"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "bar", ResourceVersion: "3"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "baz", ResourceVersion: "4"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "qux", ResourceVersion: "5"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "zoo", ResourceVersion: "6"}},
+				},
+			},
+			expectedWatchOptions: []metav1.ListOptions{
+				{
+					AllowWatchBookmarks: true,
+					ResourceVersion:     "",
+					// ResourceVersionMatch defaults to "NotOlderThan" when
+					// ResourceVersion and Limit are empty.
+					ResourceVersionMatch: "NotOlderThan",
+					SendInitialEvents:    ptr.To(true),
+				},
+			},
+			expectedStore: []metav1.Object{
+				// Pod "foo" with rv "1" is de-duped by rv 2
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "2"}},
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "bar", ResourceVersion: "3"}},
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "baz", ResourceVersion: "4"}},
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "qux", ResourceVersion: "5"}},
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "zoo", ResourceVersion: "6"}},
+			},
 		},
-		ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
-			return &v1.PodList{ListMeta: metav1.ListMeta{ResourceVersion: "1"}}, nil
+		{
+			name:         "UseWatchList disabled",
+			useWatchList: false,
+			listResults: []listResult{
+				{
+					Object: &v1.PodList{
+						ListMeta: metav1.ListMeta{ResourceVersion: "1"},
+						Items: []v1.Pod{
+							{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "1"}},
+						},
+					},
+				},
+			},
+			watchEvents: []watch.Event{
+				{
+					Type:   watch.Modified,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "2"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "bar", ResourceVersion: "3"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "baz", ResourceVersion: "4"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "qux", ResourceVersion: "5"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "zoo", ResourceVersion: "6"}},
+				},
+			},
+			expectedListOptions: []metav1.ListOptions{
+				{
+					AllowWatchBookmarks: false,
+					ResourceVersion:     "0",
+					// ResourceVersionMatch defaults to "NotOlderThan" when
+					// ResourceVersion is set and non-zero.
+					Limit:             500,
+					SendInitialEvents: nil,
+				},
+			},
+			expectedWatchOptions: []metav1.ListOptions{
+				{
+					AllowWatchBookmarks: true,
+					ResourceVersion:     "1",
+					// ResourceVersionMatch is not used by Watch calls
+					SendInitialEvents: nil,
+				},
+			},
+			expectedStore: []metav1.Object{
+				// Pod "foo" with rv "1" is de-duped by rv 2
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "2"}},
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "bar", ResourceVersion: "3"}},
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "baz", ResourceVersion: "4"}},
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "qux", ResourceVersion: "5"}},
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "zoo", ResourceVersion: "6"}},
+			},
 		},
 	}
-	s := NewFIFO(MetaNamespaceKeyFunc)
-	r := NewReflector(lw, &v1.Pod{}, s, 0)
-	go func() { assert.NoError(t, r.ListAndWatchWithContext(ctx)) }()
+	for _, tc := range table {
+		t.Run(tc.name, func(t *testing.T) {
+			watcherCh := make(chan *watch.FakeWatcher)
+			var listOpts, watchOpts []metav1.ListOptions
 
-	ids := []string{"foo", "bar", "baz", "qux", "zoo"}
-	var fw *watch.FakeWatcher
-	for i, id := range ids {
-		if fw == nil {
-			fw = <-createdFakes
-		}
-		sendingRV := strconv.FormatUint(uint64(i+2), 10)
-		fw.Add(&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: id, ResourceVersion: sendingRV}})
-		if sendingRV == "3" {
-			// Inject a failure.
-			fw.Stop()
-			fw = nil
-		}
-	}
+			// The ListFunc will never be called. So we expect Watch to only be called
+			// with options.ResourceVersion="" to start the WatchList.
+			lw := &ListWatch{
+				WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
+					watchOpts = append(watchOpts, options)
+					if len(watchOpts) > len(tc.expectedWatchOptions) {
+						return nil, fmt.Errorf("Expected ListerWatcher.Watch to only be called %d times",
+							len(tc.expectedWatchOptions))
+					}
+					w := watch.NewFake()
+					// Enqueue for event producer to use
+					go func() { watcherCh <- w }()
+					t.Log("Watcher Started")
+					return w, nil
+				},
+				ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
+					listOpts = append(listOpts, options)
+					if len(listOpts) > len(tc.listResults) {
+						return nil, fmt.Errorf("Expected ListerWatcher.List to only be called %d times",
+							len(tc.listResults))
+					}
+					listResult := tc.listResults[len(listOpts)-1]
+					return listResult.Object, listResult.Error
+				},
+			}
+			s := NewFIFO(MetaNamespaceKeyFunc)
+			r := NewReflector(lw, &v1.Pod{}, s, 0)
+			r.UseWatchList = ptr.To(tc.useWatchList)
 
-	// Verify we received the right ids with the right resource versions.
-	for i, id := range ids {
-		pod := Pop(s).(*v1.Pod)
-		if e, a := id, pod.Name; e != a {
-			t.Errorf("%v: Expected %v, got %v", i, e, a)
-		}
-		if e, a := strconv.FormatUint(uint64(i+2), 10), pod.ResourceVersion; e != a {
-			t.Errorf("%v: Expected %v, got %v", i, e, a)
-		}
-	}
+			// Start ListAndWatch in the background.
+			// When it returns, it will send an error or nil on the error
+			// channel and close the error channel.
+			_, ctx := ktesting.NewTestContext(t)
+			ctx, cancel := context.WithCancel(ctx)
+			defer cancel()
+			errCh := make(chan error)
+			go func() {
+				defer close(errCh)
+				errCh <- r.ListAndWatchWithContext(ctx)
+			}()
+			// Stop ListAndWatch and wait for the error channel to close.
+			// Validate it didn't error in Cleanup, not a defer.
+			t.Cleanup(func() {
+				cancel()
+				for err := range errCh {
+					assert.NoError(t, err)
+				}
+			})
 
-	if len(expectedRVs) != 0 {
-		t.Error("called watchStarter an unexpected number of times")
+			// Send watch events
+			var fw *watch.FakeWatcher
+			for _, event := range tc.watchEvents {
+				if fw == nil {
+					// Wait for ListerWatcher.Watch to be called
+					fw = <-watcherCh
+				}
+				obj := event.Object.(metav1.Object)
+				t.Logf("Sending %s event: name=%s, resourceVersion=%s",
+					event.Type, obj.GetName(), obj.GetResourceVersion())
+				fw.Action(event.Type, event.Object)
+			}
+
+			// Verify we received the right objects with the right resource versions.
+			for _, expectedObj := range tc.expectedStore {
+				storeObj := Pop(s).(metav1.Object)
+				assert.Equal(t, expectedObj.GetName(), storeObj.GetName())
+				assert.Equal(t, expectedObj.GetResourceVersion(), storeObj.GetResourceVersion())
+			}
+
+			// Verify we received the right number of List & Watch calls,
+			// with the expected options.
+			diffOpts := cmpopts.IgnoreFields(metav1.ListOptions{}, "TimeoutSeconds")
+			if diff := cmp.Diff(tc.expectedListOptions, listOpts, diffOpts); diff != "" {
+				t.Errorf("Unexpected List calls by ListAndWatch:\n%s", diff)
+			}
+			if diff := cmp.Diff(tc.expectedWatchOptions, watchOpts, diffOpts); diff != "" {
+				t.Errorf("Unexpected Watch calls by ListAndWatch:\n%s", diff)
+			}
+		})
 	}
 }
 


Reviews:
user: login: karlkfi
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-11T22:16:24Z
user: login: karlkfi
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-11T22:17:12Z
user: login: wojtek-t
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-14T09:37:49Z
user: login: karlkfi
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-14T19:12:14Z
user: login: karlkfi
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-14T20:03:25Z
user: login: karlkfi
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-14T20:04:47Z
user: login: karlkfi
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-14T22:26:03Z
user: login: wojtek-t
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-15T11:30:41Z
user: login: karlkfi
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-15T16:57:32Z
user: login: karlkfi
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-15T16:58:22Z
user: login: karlkfi
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-15T17:00:04Z
user: login: karlkfi
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-15T17:00:07Z
user: login: karlkfi
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-15T17:00:11Z
user: login: karlkfi
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-15T17:00:14Z
user: login: karlkfi
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-15T17:00:17Z
user: login: karlkfi
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-15T17:08:03Z
user: login: karlkfi
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-15T17:19:24Z
user: login: karlkfi
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-15T17:26:06Z

Review comments:
diff_hunk: @@ -545,19 +546,26 @@ func (r *Reflector) watch(ctx context.Context, w watch.Interface, resyncerrc cha
 					logger.V(2).Info("Watch returned 429 - backing off", "reflector", r.name, "type", r.typeDescription)
 					select {
 					case <-stopCh:
-						return nil
+						return w, nil
 					case <-r.backoffManager.Backoff().C():
+						w.Stop()
path: staging/src/k8s.io/client-go/tools/cache/reflector.go
user: login: karlkfi
body: We might be able to avoid calling this in 3 places in this function by extracting out an inner function, but that might make it harder to see what changed.
created_at: 2025-04-11T22:16:24Z
author_association: CONTRIBUTOR
diff_hunk: @@ -545,19 +546,26 @@ func (r *Reflector) watch(ctx context.Context, w watch.Interface, resyncerrc cha
 					logger.V(2).Info("Watch returned 429 - backing off", "reflector", r.name, "type", r.typeDescription)
 					select {
 					case <-stopCh:
-						return nil
+						return w, nil
 					case <-r.backoffManager.Backoff().C():
+						w.Stop()
path: staging/src/k8s.io/client-go/tools/cache/reflector.go
user: login: karlkfi
body: Basically, if we continue to the next iteration, we want to stop and nil the watcher, to tell the next iteration to start a new watcher. But we do not want to stop the watcher on error or if returning successfully.
created_at: 2025-04-11T22:17:12Z
author_association: CONTRIBUTOR
diff_hunk: @@ -518,20 +522,17 @@ func (r *Reflector) watch(ctx context.Context, w watch.Interface, resyncerrc cha
 					logger.V(4).Info("Watch failed - backing off", "reflector", r.name, "type", r.typeDescription, "err", err)
 					select {
 					case <-stopCh:
-						return nil
+						return w, nil
 					case <-r.backoffManager.Backoff().C():
 						continue
 					}
 				}
-				return err
+				return w, err
 			}
 		}
 
 		err = handleWatch(ctx, start, w, r.store, r.expectedType, r.expectedGVK, r.name, r.typeDescription, r.setLastSyncResourceVersion,
 			r.clock, resyncerrc)
-		// Ensure that watch will not be reused across iterations.
-		w.Stop()
-		w = nil
path: staging/src/k8s.io/client-go/tools/cache/reflector.go
user: login: wojtek-t
body: I'm not sure I understand what this change buys us.

If we do `w.Stop()  and w = nil` here, we would return `nil watcher` from the function and the defer you added in ListAndWatch would work fine.
And it seems simpler than putting it below in the branches that return below.

And it would allow not to modify:
https://github.com/kubernetes/kubernetes/pull/131266/files#diff-85633996b6961e6724338d96bd0662f433d322fa62391614e3adec74e2c15381R205


Putting it in other words - IIUC the only difference that we get with your change is `w.Stop()` is not called if `stopCh` is closed. So why is it worth the change?
created_at: 2025-04-14T09:23:39Z
author_association: MEMBER
diff_hunk: @@ -410,55 +442,162 @@ func TestReflectorStopWatch(t *testing.T) {
 	ctx, cancel := context.WithCancelCause(ctx)
 	cancel(errors.New("don't run"))
 	err := handleWatch(ctx, time.Now(), fw, s, g.expectedType, g.expectedGVK, g.name, g.typeDescription, g.setLastSyncResourceVersion, g.clock, nevererrc)
+	defer func() {
+		if fw != nil {
+			fw.Stop()
+		}
+	}()
 	if err != errorStopRequested {
 		t.Errorf("expected stop error, got %q", err)
 	}
 }
 
-func TestReflectorListAndWatch(t *testing.T) {
+func TestReflectorListAndWatchWithWatchList(t *testing.T) {
path: staging/src/k8s.io/client-go/tools/cache/reflector_test.go
user: login: wojtek-t
body: Can we merge those tests into a single one?

Isn't it that they really only differ with `expectedRVs` and `expectedListRVs` ? 
I would like to avoid code duplication and just share it and parametrize it different in those two cases.
created_at: 2025-04-14T09:37:37Z
author_association: MEMBER
diff_hunk: @@ -518,20 +522,17 @@ func (r *Reflector) watch(ctx context.Context, w watch.Interface, resyncerrc cha
 					logger.V(4).Info("Watch failed - backing off", "reflector", r.name, "type", r.typeDescription, "err", err)
 					select {
 					case <-stopCh:
-						return nil
+						return w, nil
 					case <-r.backoffManager.Backoff().C():
 						continue
 					}
 				}
-				return err
+				return w, err
 			}
 		}
 
 		err = handleWatch(ctx, start, w, r.store, r.expectedType, r.expectedGVK, r.name, r.typeDescription, r.setLastSyncResourceVersion,
 			r.clock, resyncerrc)
-		// Ensure that watch will not be reused across iterations.
-		w.Stop()
-		w = nil
path: staging/src/k8s.io/client-go/tools/cache/reflector.go
user: login: karlkfi
body: I was trying to do two things:
1. Prevent deadlock in the watch event producer from Stop never being called
2. Prevent panic from Stop being called twice, in watch impls without a lock guarding closure of the result channel.

But in retrospect, I think #2 effectively infeasible, for a few reasons:
1. We don't know if Stop will always close the result channel before it returns. 
2. Only the inner watch method currently knows if the result channel is closed.
3. Stop could be called by three different parties: the watch code, the reflector code, and the caller.

So I think the #1 goal is still good, but we need to assume that the Stop impl can be called multiple times, otherwise we can't guarantee it always gets called at least once with the current interface.

If that's the case, we might just need to call `defer w.Stop()` from multiple layers, and not worry about trying to de-dupe them.
created_at: 2025-04-14T19:12:13Z
author_association: CONTRIBUTOR
diff_hunk: @@ -518,20 +522,17 @@ func (r *Reflector) watch(ctx context.Context, w watch.Interface, resyncerrc cha
 					logger.V(4).Info("Watch failed - backing off", "reflector", r.name, "type", r.typeDescription, "err", err)
 					select {
 					case <-stopCh:
-						return nil
+						return w, nil
 					case <-r.backoffManager.Backoff().C():
 						continue
 					}
 				}
-				return err
+				return w, err
 			}
 		}
 
 		err = handleWatch(ctx, start, w, r.store, r.expectedType, r.expectedGVK, r.name, r.typeDescription, r.setLastSyncResourceVersion,
 			r.clock, resyncerrc)
-		// Ensure that watch will not be reused across iterations.
-		w.Stop()
-		w = nil
path: staging/src/k8s.io/client-go/tools/cache/reflector.go
user: login: karlkfi
body: I've updated the PR to call defer Stop at three different layers now. I think that's the only way to catch all the edge cases in a way that makes the inner private methods predictable and safe to test.
created_at: 2025-04-14T20:03:24Z
author_association: CONTRIBUTOR
diff_hunk: @@ -410,55 +442,162 @@ func TestReflectorStopWatch(t *testing.T) {
 	ctx, cancel := context.WithCancelCause(ctx)
 	cancel(errors.New("don't run"))
 	err := handleWatch(ctx, time.Now(), fw, s, g.expectedType, g.expectedGVK, g.name, g.typeDescription, g.setLastSyncResourceVersion, g.clock, nevererrc)
+	defer func() {
+		if fw != nil {
+			fw.Stop()
+		}
+	}()
 	if err != errorStopRequested {
 		t.Errorf("expected stop error, got %q", err)
 	}
 }
 
-func TestReflectorListAndWatch(t *testing.T) {
+func TestReflectorListAndWatchWithWatchList(t *testing.T) {
path: staging/src/k8s.io/client-go/tools/cache/reflector_test.go
user: login: karlkfi
body: Realistically, this whole package of tests should be rewritten to test both branches. Most of them assume the old ListAndWatch behavior. But I can do it for just this one...
created_at: 2025-04-14T20:04:46Z
author_association: CONTRIBUTOR
diff_hunk: @@ -410,55 +442,162 @@ func TestReflectorStopWatch(t *testing.T) {
 	ctx, cancel := context.WithCancelCause(ctx)
 	cancel(errors.New("don't run"))
 	err := handleWatch(ctx, time.Now(), fw, s, g.expectedType, g.expectedGVK, g.name, g.typeDescription, g.setLastSyncResourceVersion, g.clock, nevererrc)
+	defer func() {
+		if fw != nil {
+			fw.Stop()
+		}
+	}()
 	if err != errorStopRequested {
 		t.Errorf("expected stop error, got %q", err)
 	}
 }
 
-func TestReflectorListAndWatch(t *testing.T) {
+func TestReflectorListAndWatchWithWatchList(t *testing.T) {
path: staging/src/k8s.io/client-go/tools/cache/reflector_test.go
user: login: karlkfi
body: Done
created_at: 2025-04-14T22:26:03Z
author_association: CONTRIBUTOR
diff_hunk: @@ -416,64 +413,211 @@ func TestReflectorStopWatch(t *testing.T) {
 }
 
 func TestReflectorListAndWatch(t *testing.T) {
-	_, ctx := ktesting.NewTestContext(t)
-	ctx, cancel := context.WithCancel(ctx)
-	defer cancel()
-	createdFakes := make(chan *watch.FakeWatcher)
-
-	// The ListFunc says that it's at revision 1. Therefore, we expect our WatchFunc
-	// to get called at the beginning of the watch with 1, and again with 3 when we
-	// inject an error.
-	expectedRVs := []string{"1", "3"}
-	lw := &ListWatch{
-		WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
-			rv := options.ResourceVersion
-			fw := watch.NewFake()
-			if e, a := expectedRVs[0], rv; e != a {
-				t.Errorf("Expected rv %v, but got %v", e, a)
-			}
-			expectedRVs = expectedRVs[1:]
-			// channel is not buffered because the for loop below needs to block. But
-			// we don't want to block here, so report the new fake via a go routine.
-			go func() { createdFakes <- fw }()
-			return fw, nil
+	type listResult struct {
+		Object runtime.Object
+		Error  error
+	}
+	table := []struct {
+		name                 string
+		useWatchList         bool
+		listResults          []listResult
+		watchEvents          []watch.Event
+		expectedListOptions  []metav1.ListOptions
+		expectedWatchOptions []metav1.ListOptions
+		expectedStore        []metav1.Object
+	}{
+		{
+			name:         "UseWatchList enabled",
+			useWatchList: true,
+			watchEvents: []watch.Event{
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "1"}},
+				},
+				{
+					Type: watch.Bookmark,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{
+						Name:            "foo",
+						ResourceVersion: "1",
+						Annotations:     map[string]string{metav1.InitialEventsAnnotationKey: "true"},
+					}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "2"}},
path: staging/src/k8s.io/client-go/tools/cache/reflector_test.go
user: login: wojtek-t
body: foo was already created above - we should remove it I think
created_at: 2025-04-15T10:11:26Z
author_association: MEMBER
diff_hunk: @@ -416,64 +413,211 @@ func TestReflectorStopWatch(t *testing.T) {
 }
 
 func TestReflectorListAndWatch(t *testing.T) {
-	_, ctx := ktesting.NewTestContext(t)
-	ctx, cancel := context.WithCancel(ctx)
-	defer cancel()
-	createdFakes := make(chan *watch.FakeWatcher)
-
-	// The ListFunc says that it's at revision 1. Therefore, we expect our WatchFunc
-	// to get called at the beginning of the watch with 1, and again with 3 when we
-	// inject an error.
-	expectedRVs := []string{"1", "3"}
-	lw := &ListWatch{
-		WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
-			rv := options.ResourceVersion
-			fw := watch.NewFake()
-			if e, a := expectedRVs[0], rv; e != a {
-				t.Errorf("Expected rv %v, but got %v", e, a)
-			}
-			expectedRVs = expectedRVs[1:]
-			// channel is not buffered because the for loop below needs to block. But
-			// we don't want to block here, so report the new fake via a go routine.
-			go func() { createdFakes <- fw }()
-			return fw, nil
+	type listResult struct {
+		Object runtime.Object
+		Error  error
+	}
+	table := []struct {
+		name                 string
+		useWatchList         bool
+		listResults          []listResult
+		watchEvents          []watch.Event
+		expectedListOptions  []metav1.ListOptions
+		expectedWatchOptions []metav1.ListOptions
+		expectedStore        []metav1.Object
+	}{
+		{
+			name:         "UseWatchList enabled",
+			useWatchList: true,
+			watchEvents: []watch.Event{
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "1"}},
+				},
+				{
+					Type: watch.Bookmark,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{
+						Name:            "foo",
+						ResourceVersion: "1",
+						Annotations:     map[string]string{metav1.InitialEventsAnnotationKey: "true"},
+					}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "2"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "bar", ResourceVersion: "3"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "baz", ResourceVersion: "4"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "qux", ResourceVersion: "5"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "zoo", ResourceVersion: "6"}},
+				},
+			},
+			expectedWatchOptions: []metav1.ListOptions{
+				{
+					AllowWatchBookmarks:  true,
+					ResourceVersion:      "",
+					ResourceVersionMatch: "NotOlderThan",
+					// TimeoutSeconds: // ignored
path: staging/src/k8s.io/client-go/tools/cache/reflector_test.go
user: login: wojtek-t
body: remove?
created_at: 2025-04-15T10:11:44Z
author_association: MEMBER
diff_hunk: @@ -416,64 +413,211 @@ func TestReflectorStopWatch(t *testing.T) {
 }
 
 func TestReflectorListAndWatch(t *testing.T) {
-	_, ctx := ktesting.NewTestContext(t)
-	ctx, cancel := context.WithCancel(ctx)
-	defer cancel()
-	createdFakes := make(chan *watch.FakeWatcher)
-
-	// The ListFunc says that it's at revision 1. Therefore, we expect our WatchFunc
-	// to get called at the beginning of the watch with 1, and again with 3 when we
-	// inject an error.
-	expectedRVs := []string{"1", "3"}
-	lw := &ListWatch{
-		WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
-			rv := options.ResourceVersion
-			fw := watch.NewFake()
-			if e, a := expectedRVs[0], rv; e != a {
-				t.Errorf("Expected rv %v, but got %v", e, a)
-			}
-			expectedRVs = expectedRVs[1:]
-			// channel is not buffered because the for loop below needs to block. But
-			// we don't want to block here, so report the new fake via a go routine.
-			go func() { createdFakes <- fw }()
-			return fw, nil
+	type listResult struct {
+		Object runtime.Object
+		Error  error
+	}
+	table := []struct {
+		name                 string
+		useWatchList         bool
+		listResults          []listResult
+		watchEvents          []watch.Event
+		expectedListOptions  []metav1.ListOptions
+		expectedWatchOptions []metav1.ListOptions
+		expectedStore        []metav1.Object
+	}{
+		{
+			name:         "UseWatchList enabled",
+			useWatchList: true,
+			watchEvents: []watch.Event{
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "1"}},
+				},
+				{
+					Type: watch.Bookmark,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{
+						Name:            "foo",
+						ResourceVersion: "1",
+						Annotations:     map[string]string{metav1.InitialEventsAnnotationKey: "true"},
+					}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "2"}},
path: staging/src/k8s.io/client-go/tools/cache/reflector_test.go
user: login: wojtek-t
body: Or switch to update event.
created_at: 2025-04-15T11:26:38Z
author_association: MEMBER
diff_hunk: @@ -416,64 +413,211 @@ func TestReflectorStopWatch(t *testing.T) {
 }
 
 func TestReflectorListAndWatch(t *testing.T) {
-	_, ctx := ktesting.NewTestContext(t)
-	ctx, cancel := context.WithCancel(ctx)
-	defer cancel()
-	createdFakes := make(chan *watch.FakeWatcher)
-
-	// The ListFunc says that it's at revision 1. Therefore, we expect our WatchFunc
-	// to get called at the beginning of the watch with 1, and again with 3 when we
-	// inject an error.
-	expectedRVs := []string{"1", "3"}
-	lw := &ListWatch{
-		WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
-			rv := options.ResourceVersion
-			fw := watch.NewFake()
-			if e, a := expectedRVs[0], rv; e != a {
-				t.Errorf("Expected rv %v, but got %v", e, a)
-			}
-			expectedRVs = expectedRVs[1:]
-			// channel is not buffered because the for loop below needs to block. But
-			// we don't want to block here, so report the new fake via a go routine.
-			go func() { createdFakes <- fw }()
-			return fw, nil
+	type listResult struct {
+		Object runtime.Object
+		Error  error
+	}
+	table := []struct {
+		name                 string
+		useWatchList         bool
+		listResults          []listResult
+		watchEvents          []watch.Event
+		expectedListOptions  []metav1.ListOptions
+		expectedWatchOptions []metav1.ListOptions
+		expectedStore        []metav1.Object
+	}{
+		{
+			name:         "UseWatchList enabled",
+			useWatchList: true,
+			watchEvents: []watch.Event{
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "1"}},
+				},
+				{
+					Type: watch.Bookmark,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{
+						Name:            "foo",
+						ResourceVersion: "1",
+						Annotations:     map[string]string{metav1.InitialEventsAnnotationKey: "true"},
+					}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "2"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "bar", ResourceVersion: "3"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "baz", ResourceVersion: "4"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "qux", ResourceVersion: "5"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "zoo", ResourceVersion: "6"}},
+				},
+			},
+			expectedWatchOptions: []metav1.ListOptions{
+				{
+					AllowWatchBookmarks:  true,
+					ResourceVersion:      "",
+					ResourceVersionMatch: "NotOlderThan",
+					// TimeoutSeconds: // ignored
+					SendInitialEvents: ptr.To(true),
+				},
+			},
+			expectedStore: []metav1.Object{
+				// Pod "foo" with rv "1" is de-duped by rv 2
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "2"}},
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "bar", ResourceVersion: "3"}},
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "baz", ResourceVersion: "4"}},
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "qux", ResourceVersion: "5"}},
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "zoo", ResourceVersion: "6"}},
+			},
 		},
-		ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
-			return &v1.PodList{ListMeta: metav1.ListMeta{ResourceVersion: "1"}}, nil
+		{
+			name:         "UseWatchList disabled",
+			useWatchList: false,
+			listResults: []listResult{
+				{
+					Object: &v1.PodList{
+						ListMeta: metav1.ListMeta{ResourceVersion: "1"},
+						Items: []v1.Pod{
+							{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "1"}},
+						},
+					},
+				},
+			},
+			watchEvents: []watch.Event{
+				{
+					Type:   watch.Added,
path: staging/src/k8s.io/client-go/tools/cache/reflector_test.go
user: login: wojtek-t
body: Same here
created_at: 2025-04-15T11:27:02Z
author_association: MEMBER
diff_hunk: @@ -416,64 +413,211 @@ func TestReflectorStopWatch(t *testing.T) {
 }
 
 func TestReflectorListAndWatch(t *testing.T) {
-	_, ctx := ktesting.NewTestContext(t)
-	ctx, cancel := context.WithCancel(ctx)
-	defer cancel()
-	createdFakes := make(chan *watch.FakeWatcher)
-
-	// The ListFunc says that it's at revision 1. Therefore, we expect our WatchFunc
-	// to get called at the beginning of the watch with 1, and again with 3 when we
-	// inject an error.
-	expectedRVs := []string{"1", "3"}
-	lw := &ListWatch{
-		WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
-			rv := options.ResourceVersion
-			fw := watch.NewFake()
-			if e, a := expectedRVs[0], rv; e != a {
-				t.Errorf("Expected rv %v, but got %v", e, a)
-			}
-			expectedRVs = expectedRVs[1:]
-			// channel is not buffered because the for loop below needs to block. But
-			// we don't want to block here, so report the new fake via a go routine.
-			go func() { createdFakes <- fw }()
-			return fw, nil
+	type listResult struct {
+		Object runtime.Object
+		Error  error
+	}
+	table := []struct {
+		name                 string
+		useWatchList         bool
+		listResults          []listResult
+		watchEvents          []watch.Event
+		expectedListOptions  []metav1.ListOptions
+		expectedWatchOptions []metav1.ListOptions
+		expectedStore        []metav1.Object
+	}{
+		{
+			name:         "UseWatchList enabled",
+			useWatchList: true,
+			watchEvents: []watch.Event{
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "1"}},
+				},
+				{
+					Type: watch.Bookmark,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{
+						Name:            "foo",
+						ResourceVersion: "1",
+						Annotations:     map[string]string{metav1.InitialEventsAnnotationKey: "true"},
+					}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "2"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "bar", ResourceVersion: "3"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "baz", ResourceVersion: "4"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "qux", ResourceVersion: "5"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "zoo", ResourceVersion: "6"}},
+				},
+			},
+			expectedWatchOptions: []metav1.ListOptions{
+				{
+					AllowWatchBookmarks:  true,
+					ResourceVersion:      "",
+					ResourceVersionMatch: "NotOlderThan",
+					// TimeoutSeconds: // ignored
+					SendInitialEvents: ptr.To(true),
+				},
+			},
+			expectedStore: []metav1.Object{
+				// Pod "foo" with rv "1" is de-duped by rv 2
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "2"}},
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "bar", ResourceVersion: "3"}},
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "baz", ResourceVersion: "4"}},
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "qux", ResourceVersion: "5"}},
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "zoo", ResourceVersion: "6"}},
+			},
 		},
-		ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
-			return &v1.PodList{ListMeta: metav1.ListMeta{ResourceVersion: "1"}}, nil
+		{
+			name:         "UseWatchList disabled",
+			useWatchList: false,
+			listResults: []listResult{
+				{
+					Object: &v1.PodList{
+						ListMeta: metav1.ListMeta{ResourceVersion: "1"},
+						Items: []v1.Pod{
+							{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "1"}},
+						},
+					},
+				},
+			},
+			watchEvents: []watch.Event{
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "2"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "bar", ResourceVersion: "3"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "baz", ResourceVersion: "4"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "qux", ResourceVersion: "5"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "zoo", ResourceVersion: "6"}},
+				},
+			},
+			expectedListOptions: []metav1.ListOptions{
+				{
+					AllowWatchBookmarks:  true,
+					ResourceVersion:      "1",
+					ResourceVersionMatch: "", // TODO: Why not NotOlderThan?
+					// TimeoutSeconds: // ignored
path: staging/src/k8s.io/client-go/tools/cache/reflector_test.go
user: login: wojtek-t
body: remove
created_at: 2025-04-15T11:27:32Z
author_association: MEMBER
diff_hunk: @@ -416,64 +413,211 @@ func TestReflectorStopWatch(t *testing.T) {
 }
 
 func TestReflectorListAndWatch(t *testing.T) {
-	_, ctx := ktesting.NewTestContext(t)
-	ctx, cancel := context.WithCancel(ctx)
-	defer cancel()
-	createdFakes := make(chan *watch.FakeWatcher)
-
-	// The ListFunc says that it's at revision 1. Therefore, we expect our WatchFunc
-	// to get called at the beginning of the watch with 1, and again with 3 when we
-	// inject an error.
-	expectedRVs := []string{"1", "3"}
-	lw := &ListWatch{
-		WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
-			rv := options.ResourceVersion
-			fw := watch.NewFake()
-			if e, a := expectedRVs[0], rv; e != a {
-				t.Errorf("Expected rv %v, but got %v", e, a)
-			}
-			expectedRVs = expectedRVs[1:]
-			// channel is not buffered because the for loop below needs to block. But
-			// we don't want to block here, so report the new fake via a go routine.
-			go func() { createdFakes <- fw }()
-			return fw, nil
+	type listResult struct {
+		Object runtime.Object
+		Error  error
+	}
+	table := []struct {
+		name                 string
+		useWatchList         bool
+		listResults          []listResult
+		watchEvents          []watch.Event
+		expectedListOptions  []metav1.ListOptions
+		expectedWatchOptions []metav1.ListOptions
+		expectedStore        []metav1.Object
+	}{
+		{
+			name:         "UseWatchList enabled",
+			useWatchList: true,
+			watchEvents: []watch.Event{
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "1"}},
+				},
+				{
+					Type: watch.Bookmark,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{
+						Name:            "foo",
+						ResourceVersion: "1",
+						Annotations:     map[string]string{metav1.InitialEventsAnnotationKey: "true"},
+					}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "2"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "bar", ResourceVersion: "3"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "baz", ResourceVersion: "4"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "qux", ResourceVersion: "5"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "zoo", ResourceVersion: "6"}},
+				},
+			},
+			expectedWatchOptions: []metav1.ListOptions{
+				{
+					AllowWatchBookmarks:  true,
+					ResourceVersion:      "",
+					ResourceVersionMatch: "NotOlderThan",
+					// TimeoutSeconds: // ignored
+					SendInitialEvents: ptr.To(true),
+				},
+			},
+			expectedStore: []metav1.Object{
+				// Pod "foo" with rv "1" is de-duped by rv 2
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "2"}},
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "bar", ResourceVersion: "3"}},
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "baz", ResourceVersion: "4"}},
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "qux", ResourceVersion: "5"}},
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "zoo", ResourceVersion: "6"}},
+			},
 		},
-		ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
-			return &v1.PodList{ListMeta: metav1.ListMeta{ResourceVersion: "1"}}, nil
+		{
+			name:         "UseWatchList disabled",
+			useWatchList: false,
+			listResults: []listResult{
+				{
+					Object: &v1.PodList{
+						ListMeta: metav1.ListMeta{ResourceVersion: "1"},
+						Items: []v1.Pod{
+							{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "1"}},
+						},
+					},
+				},
+			},
+			watchEvents: []watch.Event{
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "2"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "bar", ResourceVersion: "3"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "baz", ResourceVersion: "4"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "qux", ResourceVersion: "5"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "zoo", ResourceVersion: "6"}},
+				},
+			},
+			expectedListOptions: []metav1.ListOptions{
+				{
+					AllowWatchBookmarks:  true,
+					ResourceVersion:      "1",
+					ResourceVersionMatch: "", // TODO: Why not NotOlderThan?
+					// TimeoutSeconds: // ignored
+					SendInitialEvents: nil,
+				},
+			},
+			expectedWatchOptions: []metav1.ListOptions{
+				{
+					AllowWatchBookmarks:  true,
+					ResourceVersion:      "1",
+					ResourceVersionMatch: "", // TODO: Why not NotOlderThan?
+					// TimeoutSeconds: // ignored
path: staging/src/k8s.io/client-go/tools/cache/reflector_test.go
user: login: wojtek-t
body: remove
created_at: 2025-04-15T11:27:40Z
author_association: MEMBER
diff_hunk: @@ -416,64 +413,211 @@ func TestReflectorStopWatch(t *testing.T) {
 }
 
 func TestReflectorListAndWatch(t *testing.T) {
-	_, ctx := ktesting.NewTestContext(t)
-	ctx, cancel := context.WithCancel(ctx)
-	defer cancel()
-	createdFakes := make(chan *watch.FakeWatcher)
-
-	// The ListFunc says that it's at revision 1. Therefore, we expect our WatchFunc
-	// to get called at the beginning of the watch with 1, and again with 3 when we
-	// inject an error.
-	expectedRVs := []string{"1", "3"}
-	lw := &ListWatch{
-		WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
-			rv := options.ResourceVersion
-			fw := watch.NewFake()
-			if e, a := expectedRVs[0], rv; e != a {
-				t.Errorf("Expected rv %v, but got %v", e, a)
-			}
-			expectedRVs = expectedRVs[1:]
-			// channel is not buffered because the for loop below needs to block. But
-			// we don't want to block here, so report the new fake via a go routine.
-			go func() { createdFakes <- fw }()
-			return fw, nil
+	type listResult struct {
+		Object runtime.Object
+		Error  error
+	}
+	table := []struct {
+		name                 string
+		useWatchList         bool
+		listResults          []listResult
+		watchEvents          []watch.Event
+		expectedListOptions  []metav1.ListOptions
+		expectedWatchOptions []metav1.ListOptions
+		expectedStore        []metav1.Object
+	}{
+		{
+			name:         "UseWatchList enabled",
+			useWatchList: true,
+			watchEvents: []watch.Event{
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "1"}},
+				},
+				{
+					Type: watch.Bookmark,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{
+						Name:            "foo",
+						ResourceVersion: "1",
+						Annotations:     map[string]string{metav1.InitialEventsAnnotationKey: "true"},
+					}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "2"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "bar", ResourceVersion: "3"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "baz", ResourceVersion: "4"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "qux", ResourceVersion: "5"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "zoo", ResourceVersion: "6"}},
+				},
+			},
+			expectedWatchOptions: []metav1.ListOptions{
+				{
+					AllowWatchBookmarks:  true,
+					ResourceVersion:      "",
+					ResourceVersionMatch: "NotOlderThan",
+					// TimeoutSeconds: // ignored
+					SendInitialEvents: ptr.To(true),
+				},
+			},
+			expectedStore: []metav1.Object{
+				// Pod "foo" with rv "1" is de-duped by rv 2
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "2"}},
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "bar", ResourceVersion: "3"}},
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "baz", ResourceVersion: "4"}},
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "qux", ResourceVersion: "5"}},
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "zoo", ResourceVersion: "6"}},
+			},
 		},
-		ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
-			return &v1.PodList{ListMeta: metav1.ListMeta{ResourceVersion: "1"}}, nil
+		{
+			name:         "UseWatchList disabled",
+			useWatchList: false,
+			listResults: []listResult{
+				{
+					Object: &v1.PodList{
+						ListMeta: metav1.ListMeta{ResourceVersion: "1"},
+						Items: []v1.Pod{
+							{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "1"}},
+						},
+					},
+				},
+			},
+			watchEvents: []watch.Event{
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "2"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "bar", ResourceVersion: "3"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "baz", ResourceVersion: "4"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "qux", ResourceVersion: "5"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "zoo", ResourceVersion: "6"}},
+				},
+			},
+			expectedListOptions: []metav1.ListOptions{
+				{
+					AllowWatchBookmarks:  true,
+					ResourceVersion:      "1",
+					ResourceVersionMatch: "", // TODO: Why not NotOlderThan?
+					// TimeoutSeconds: // ignored
+					SendInitialEvents: nil,
+				},
+			},
+			expectedWatchOptions: []metav1.ListOptions{
+				{
+					AllowWatchBookmarks:  true,
+					ResourceVersion:      "1",
+					ResourceVersionMatch: "", // TODO: Why not NotOlderThan?
path: staging/src/k8s.io/client-go/tools/cache/reflector_test.go
user: login: wojtek-t
body: ResourceVersionMatch is not relevant to watch - it's used only to list requests
created_at: 2025-04-15T11:28:08Z
author_association: MEMBER
diff_hunk: @@ -416,64 +413,211 @@ func TestReflectorStopWatch(t *testing.T) {
 }
 
 func TestReflectorListAndWatch(t *testing.T) {
-	_, ctx := ktesting.NewTestContext(t)
-	ctx, cancel := context.WithCancel(ctx)
-	defer cancel()
-	createdFakes := make(chan *watch.FakeWatcher)
-
-	// The ListFunc says that it's at revision 1. Therefore, we expect our WatchFunc
-	// to get called at the beginning of the watch with 1, and again with 3 when we
-	// inject an error.
-	expectedRVs := []string{"1", "3"}
-	lw := &ListWatch{
-		WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
-			rv := options.ResourceVersion
-			fw := watch.NewFake()
-			if e, a := expectedRVs[0], rv; e != a {
-				t.Errorf("Expected rv %v, but got %v", e, a)
-			}
-			expectedRVs = expectedRVs[1:]
-			// channel is not buffered because the for loop below needs to block. But
-			// we don't want to block here, so report the new fake via a go routine.
-			go func() { createdFakes <- fw }()
-			return fw, nil
+	type listResult struct {
+		Object runtime.Object
+		Error  error
+	}
+	table := []struct {
+		name                 string
+		useWatchList         bool
+		listResults          []listResult
+		watchEvents          []watch.Event
+		expectedListOptions  []metav1.ListOptions
+		expectedWatchOptions []metav1.ListOptions
+		expectedStore        []metav1.Object
+	}{
+		{
+			name:         "UseWatchList enabled",
+			useWatchList: true,
+			watchEvents: []watch.Event{
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "1"}},
+				},
+				{
+					Type: watch.Bookmark,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{
+						Name:            "foo",
+						ResourceVersion: "1",
+						Annotations:     map[string]string{metav1.InitialEventsAnnotationKey: "true"},
+					}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "2"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "bar", ResourceVersion: "3"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "baz", ResourceVersion: "4"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "qux", ResourceVersion: "5"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "zoo", ResourceVersion: "6"}},
+				},
+			},
+			expectedWatchOptions: []metav1.ListOptions{
+				{
+					AllowWatchBookmarks:  true,
+					ResourceVersion:      "",
+					ResourceVersionMatch: "NotOlderThan",
+					// TimeoutSeconds: // ignored
+					SendInitialEvents: ptr.To(true),
+				},
+			},
+			expectedStore: []metav1.Object{
+				// Pod "foo" with rv "1" is de-duped by rv 2
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "2"}},
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "bar", ResourceVersion: "3"}},
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "baz", ResourceVersion: "4"}},
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "qux", ResourceVersion: "5"}},
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "zoo", ResourceVersion: "6"}},
+			},
 		},
-		ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
-			return &v1.PodList{ListMeta: metav1.ListMeta{ResourceVersion: "1"}}, nil
+		{
+			name:         "UseWatchList disabled",
+			useWatchList: false,
+			listResults: []listResult{
+				{
+					Object: &v1.PodList{
+						ListMeta: metav1.ListMeta{ResourceVersion: "1"},
+						Items: []v1.Pod{
+							{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "1"}},
+						},
+					},
+				},
+			},
+			watchEvents: []watch.Event{
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "2"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "bar", ResourceVersion: "3"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "baz", ResourceVersion: "4"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "qux", ResourceVersion: "5"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "zoo", ResourceVersion: "6"}},
+				},
+			},
+			expectedListOptions: []metav1.ListOptions{
+				{
+					AllowWatchBookmarks:  true,
+					ResourceVersion:      "1",
path: staging/src/k8s.io/client-go/tools/cache/reflector_test.go
user: login: wojtek-t
body: Hmm - shouldn't it be ""  here?
created_at: 2025-04-15T11:28:32Z
author_association: MEMBER
diff_hunk: @@ -518,20 +522,17 @@ func (r *Reflector) watch(ctx context.Context, w watch.Interface, resyncerrc cha
 					logger.V(4).Info("Watch failed - backing off", "reflector", r.name, "type", r.typeDescription, "err", err)
 					select {
 					case <-stopCh:
-						return nil
+						return w, nil
 					case <-r.backoffManager.Backoff().C():
 						continue
 					}
 				}
-				return err
+				return w, err
 			}
 		}
 
 		err = handleWatch(ctx, start, w, r.store, r.expectedType, r.expectedGVK, r.name, r.typeDescription, r.setLastSyncResourceVersion,
 			r.clock, resyncerrc)
-		// Ensure that watch will not be reused across iterations.
-		w.Stop()
-		w = nil
path: staging/src/k8s.io/client-go/tools/cache/reflector.go
user: login: wojtek-t
body: OK - that makes sense to me now - the changes in this file lgtm.
created_at: 2025-04-15T11:30:28Z
author_association: MEMBER
diff_hunk: @@ -416,64 +413,211 @@ func TestReflectorStopWatch(t *testing.T) {
 }
 
 func TestReflectorListAndWatch(t *testing.T) {
-	_, ctx := ktesting.NewTestContext(t)
-	ctx, cancel := context.WithCancel(ctx)
-	defer cancel()
-	createdFakes := make(chan *watch.FakeWatcher)
-
-	// The ListFunc says that it's at revision 1. Therefore, we expect our WatchFunc
-	// to get called at the beginning of the watch with 1, and again with 3 when we
-	// inject an error.
-	expectedRVs := []string{"1", "3"}
-	lw := &ListWatch{
-		WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
-			rv := options.ResourceVersion
-			fw := watch.NewFake()
-			if e, a := expectedRVs[0], rv; e != a {
-				t.Errorf("Expected rv %v, but got %v", e, a)
-			}
-			expectedRVs = expectedRVs[1:]
-			// channel is not buffered because the for loop below needs to block. But
-			// we don't want to block here, so report the new fake via a go routine.
-			go func() { createdFakes <- fw }()
-			return fw, nil
+	type listResult struct {
+		Object runtime.Object
+		Error  error
+	}
+	table := []struct {
+		name                 string
+		useWatchList         bool
+		listResults          []listResult
+		watchEvents          []watch.Event
+		expectedListOptions  []metav1.ListOptions
+		expectedWatchOptions []metav1.ListOptions
+		expectedStore        []metav1.Object
+	}{
+		{
+			name:         "UseWatchList enabled",
+			useWatchList: true,
+			watchEvents: []watch.Event{
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "1"}},
+				},
+				{
+					Type: watch.Bookmark,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{
+						Name:            "foo",
+						ResourceVersion: "1",
+						Annotations:     map[string]string{metav1.InitialEventsAnnotationKey: "true"},
+					}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "2"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "bar", ResourceVersion: "3"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "baz", ResourceVersion: "4"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "qux", ResourceVersion: "5"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "zoo", ResourceVersion: "6"}},
+				},
+			},
+			expectedWatchOptions: []metav1.ListOptions{
+				{
+					AllowWatchBookmarks:  true,
+					ResourceVersion:      "",
+					ResourceVersionMatch: "NotOlderThan",
+					// TimeoutSeconds: // ignored
+					SendInitialEvents: ptr.To(true),
+				},
+			},
+			expectedStore: []metav1.Object{
+				// Pod "foo" with rv "1" is de-duped by rv 2
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "2"}},
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "bar", ResourceVersion: "3"}},
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "baz", ResourceVersion: "4"}},
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "qux", ResourceVersion: "5"}},
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "zoo", ResourceVersion: "6"}},
+			},
 		},
-		ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
-			return &v1.PodList{ListMeta: metav1.ListMeta{ResourceVersion: "1"}}, nil
+		{
+			name:         "UseWatchList disabled",
+			useWatchList: false,
+			listResults: []listResult{
+				{
+					Object: &v1.PodList{
+						ListMeta: metav1.ListMeta{ResourceVersion: "1"},
+						Items: []v1.Pod{
+							{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "1"}},
+						},
+					},
+				},
+			},
+			watchEvents: []watch.Event{
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "2"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "bar", ResourceVersion: "3"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "baz", ResourceVersion: "4"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "qux", ResourceVersion: "5"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "zoo", ResourceVersion: "6"}},
+				},
+			},
+			expectedListOptions: []metav1.ListOptions{
+				{
+					AllowWatchBookmarks:  true,
+					ResourceVersion:      "1",
+					ResourceVersionMatch: "", // TODO: Why not NotOlderThan?
+					// TimeoutSeconds: // ignored
+					SendInitialEvents: nil,
+				},
+			},
+			expectedWatchOptions: []metav1.ListOptions{
+				{
+					AllowWatchBookmarks:  true,
+					ResourceVersion:      "1",
+					ResourceVersionMatch: "", // TODO: Why not NotOlderThan?
path: staging/src/k8s.io/client-go/tools/cache/reflector_test.go
user: login: karlkfi
body: Ok, then why isn't NotOlderThan sent to the List call?
created_at: 2025-04-15T16:57:32Z
author_association: CONTRIBUTOR
diff_hunk: @@ -416,64 +413,211 @@ func TestReflectorStopWatch(t *testing.T) {
 }
 
 func TestReflectorListAndWatch(t *testing.T) {
-	_, ctx := ktesting.NewTestContext(t)
-	ctx, cancel := context.WithCancel(ctx)
-	defer cancel()
-	createdFakes := make(chan *watch.FakeWatcher)
-
-	// The ListFunc says that it's at revision 1. Therefore, we expect our WatchFunc
-	// to get called at the beginning of the watch with 1, and again with 3 when we
-	// inject an error.
-	expectedRVs := []string{"1", "3"}
-	lw := &ListWatch{
-		WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
-			rv := options.ResourceVersion
-			fw := watch.NewFake()
-			if e, a := expectedRVs[0], rv; e != a {
-				t.Errorf("Expected rv %v, but got %v", e, a)
-			}
-			expectedRVs = expectedRVs[1:]
-			// channel is not buffered because the for loop below needs to block. But
-			// we don't want to block here, so report the new fake via a go routine.
-			go func() { createdFakes <- fw }()
-			return fw, nil
+	type listResult struct {
+		Object runtime.Object
+		Error  error
+	}
+	table := []struct {
+		name                 string
+		useWatchList         bool
+		listResults          []listResult
+		watchEvents          []watch.Event
+		expectedListOptions  []metav1.ListOptions
+		expectedWatchOptions []metav1.ListOptions
+		expectedStore        []metav1.Object
+	}{
+		{
+			name:         "UseWatchList enabled",
+			useWatchList: true,
+			watchEvents: []watch.Event{
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "1"}},
+				},
+				{
+					Type: watch.Bookmark,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{
+						Name:            "foo",
+						ResourceVersion: "1",
+						Annotations:     map[string]string{metav1.InitialEventsAnnotationKey: "true"},
+					}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "2"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "bar", ResourceVersion: "3"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "baz", ResourceVersion: "4"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "qux", ResourceVersion: "5"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "zoo", ResourceVersion: "6"}},
+				},
+			},
+			expectedWatchOptions: []metav1.ListOptions{
+				{
+					AllowWatchBookmarks:  true,
+					ResourceVersion:      "",
+					ResourceVersionMatch: "NotOlderThan",
+					// TimeoutSeconds: // ignored
+					SendInitialEvents: ptr.To(true),
+				},
+			},
+			expectedStore: []metav1.Object{
+				// Pod "foo" with rv "1" is de-duped by rv 2
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "2"}},
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "bar", ResourceVersion: "3"}},
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "baz", ResourceVersion: "4"}},
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "qux", ResourceVersion: "5"}},
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "zoo", ResourceVersion: "6"}},
+			},
 		},
-		ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
-			return &v1.PodList{ListMeta: metav1.ListMeta{ResourceVersion: "1"}}, nil
+		{
+			name:         "UseWatchList disabled",
+			useWatchList: false,
+			listResults: []listResult{
+				{
+					Object: &v1.PodList{
+						ListMeta: metav1.ListMeta{ResourceVersion: "1"},
+						Items: []v1.Pod{
+							{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "1"}},
+						},
+					},
+				},
+			},
+			watchEvents: []watch.Event{
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "2"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "bar", ResourceVersion: "3"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "baz", ResourceVersion: "4"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "qux", ResourceVersion: "5"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "zoo", ResourceVersion: "6"}},
+				},
+			},
+			expectedListOptions: []metav1.ListOptions{
+				{
+					AllowWatchBookmarks:  true,
+					ResourceVersion:      "1",
path: staging/src/k8s.io/client-go/tools/cache/reflector_test.go
user: login: karlkfi
body: Nah. For normal ListAndWatch the Watch starts at the RV sent by the List response.
created_at: 2025-04-15T16:58:21Z
author_association: CONTRIBUTOR
diff_hunk: @@ -416,64 +413,211 @@ func TestReflectorStopWatch(t *testing.T) {
 }
 
 func TestReflectorListAndWatch(t *testing.T) {
-	_, ctx := ktesting.NewTestContext(t)
-	ctx, cancel := context.WithCancel(ctx)
-	defer cancel()
-	createdFakes := make(chan *watch.FakeWatcher)
-
-	// The ListFunc says that it's at revision 1. Therefore, we expect our WatchFunc
-	// to get called at the beginning of the watch with 1, and again with 3 when we
-	// inject an error.
-	expectedRVs := []string{"1", "3"}
-	lw := &ListWatch{
-		WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
-			rv := options.ResourceVersion
-			fw := watch.NewFake()
-			if e, a := expectedRVs[0], rv; e != a {
-				t.Errorf("Expected rv %v, but got %v", e, a)
-			}
-			expectedRVs = expectedRVs[1:]
-			// channel is not buffered because the for loop below needs to block. But
-			// we don't want to block here, so report the new fake via a go routine.
-			go func() { createdFakes <- fw }()
-			return fw, nil
+	type listResult struct {
+		Object runtime.Object
+		Error  error
+	}
+	table := []struct {
+		name                 string
+		useWatchList         bool
+		listResults          []listResult
+		watchEvents          []watch.Event
+		expectedListOptions  []metav1.ListOptions
+		expectedWatchOptions []metav1.ListOptions
+		expectedStore        []metav1.Object
+	}{
+		{
+			name:         "UseWatchList enabled",
+			useWatchList: true,
+			watchEvents: []watch.Event{
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "1"}},
+				},
+				{
+					Type: watch.Bookmark,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{
+						Name:            "foo",
+						ResourceVersion: "1",
+						Annotations:     map[string]string{metav1.InitialEventsAnnotationKey: "true"},
+					}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "2"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "bar", ResourceVersion: "3"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "baz", ResourceVersion: "4"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "qux", ResourceVersion: "5"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "zoo", ResourceVersion: "6"}},
+				},
+			},
+			expectedWatchOptions: []metav1.ListOptions{
+				{
+					AllowWatchBookmarks:  true,
+					ResourceVersion:      "",
+					ResourceVersionMatch: "NotOlderThan",
+					// TimeoutSeconds: // ignored
+					SendInitialEvents: ptr.To(true),
+				},
+			},
+			expectedStore: []metav1.Object{
+				// Pod "foo" with rv "1" is de-duped by rv 2
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "2"}},
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "bar", ResourceVersion: "3"}},
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "baz", ResourceVersion: "4"}},
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "qux", ResourceVersion: "5"}},
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "zoo", ResourceVersion: "6"}},
+			},
 		},
-		ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
-			return &v1.PodList{ListMeta: metav1.ListMeta{ResourceVersion: "1"}}, nil
+		{
+			name:         "UseWatchList disabled",
+			useWatchList: false,
+			listResults: []listResult{
+				{
+					Object: &v1.PodList{
+						ListMeta: metav1.ListMeta{ResourceVersion: "1"},
+						Items: []v1.Pod{
+							{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "1"}},
+						},
+					},
+				},
+			},
+			watchEvents: []watch.Event{
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "2"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "bar", ResourceVersion: "3"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "baz", ResourceVersion: "4"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "qux", ResourceVersion: "5"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "zoo", ResourceVersion: "6"}},
+				},
+			},
+			expectedListOptions: []metav1.ListOptions{
+				{
+					AllowWatchBookmarks:  true,
+					ResourceVersion:      "1",
+					ResourceVersionMatch: "", // TODO: Why not NotOlderThan?
+					// TimeoutSeconds: // ignored
+					SendInitialEvents: nil,
+				},
+			},
+			expectedWatchOptions: []metav1.ListOptions{
+				{
+					AllowWatchBookmarks:  true,
+					ResourceVersion:      "1",
+					ResourceVersionMatch: "", // TODO: Why not NotOlderThan?
+					// TimeoutSeconds: // ignored
path: staging/src/k8s.io/client-go/tools/cache/reflector_test.go
user: login: karlkfi
body: done
created_at: 2025-04-15T17:00:04Z
author_association: CONTRIBUTOR
diff_hunk: @@ -416,64 +413,211 @@ func TestReflectorStopWatch(t *testing.T) {
 }
 
 func TestReflectorListAndWatch(t *testing.T) {
-	_, ctx := ktesting.NewTestContext(t)
-	ctx, cancel := context.WithCancel(ctx)
-	defer cancel()
-	createdFakes := make(chan *watch.FakeWatcher)
-
-	// The ListFunc says that it's at revision 1. Therefore, we expect our WatchFunc
-	// to get called at the beginning of the watch with 1, and again with 3 when we
-	// inject an error.
-	expectedRVs := []string{"1", "3"}
-	lw := &ListWatch{
-		WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
-			rv := options.ResourceVersion
-			fw := watch.NewFake()
-			if e, a := expectedRVs[0], rv; e != a {
-				t.Errorf("Expected rv %v, but got %v", e, a)
-			}
-			expectedRVs = expectedRVs[1:]
-			// channel is not buffered because the for loop below needs to block. But
-			// we don't want to block here, so report the new fake via a go routine.
-			go func() { createdFakes <- fw }()
-			return fw, nil
+	type listResult struct {
+		Object runtime.Object
+		Error  error
+	}
+	table := []struct {
+		name                 string
+		useWatchList         bool
+		listResults          []listResult
+		watchEvents          []watch.Event
+		expectedListOptions  []metav1.ListOptions
+		expectedWatchOptions []metav1.ListOptions
+		expectedStore        []metav1.Object
+	}{
+		{
+			name:         "UseWatchList enabled",
+			useWatchList: true,
+			watchEvents: []watch.Event{
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "1"}},
+				},
+				{
+					Type: watch.Bookmark,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{
+						Name:            "foo",
+						ResourceVersion: "1",
+						Annotations:     map[string]string{metav1.InitialEventsAnnotationKey: "true"},
+					}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "2"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "bar", ResourceVersion: "3"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "baz", ResourceVersion: "4"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "qux", ResourceVersion: "5"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "zoo", ResourceVersion: "6"}},
+				},
+			},
+			expectedWatchOptions: []metav1.ListOptions{
+				{
+					AllowWatchBookmarks:  true,
+					ResourceVersion:      "",
+					ResourceVersionMatch: "NotOlderThan",
+					// TimeoutSeconds: // ignored
+					SendInitialEvents: ptr.To(true),
+				},
+			},
+			expectedStore: []metav1.Object{
+				// Pod "foo" with rv "1" is de-duped by rv 2
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "2"}},
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "bar", ResourceVersion: "3"}},
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "baz", ResourceVersion: "4"}},
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "qux", ResourceVersion: "5"}},
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "zoo", ResourceVersion: "6"}},
+			},
 		},
-		ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
-			return &v1.PodList{ListMeta: metav1.ListMeta{ResourceVersion: "1"}}, nil
+		{
+			name:         "UseWatchList disabled",
+			useWatchList: false,
+			listResults: []listResult{
+				{
+					Object: &v1.PodList{
+						ListMeta: metav1.ListMeta{ResourceVersion: "1"},
+						Items: []v1.Pod{
+							{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "1"}},
+						},
+					},
+				},
+			},
+			watchEvents: []watch.Event{
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "2"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "bar", ResourceVersion: "3"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "baz", ResourceVersion: "4"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "qux", ResourceVersion: "5"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "zoo", ResourceVersion: "6"}},
+				},
+			},
+			expectedListOptions: []metav1.ListOptions{
+				{
+					AllowWatchBookmarks:  true,
+					ResourceVersion:      "1",
+					ResourceVersionMatch: "", // TODO: Why not NotOlderThan?
+					// TimeoutSeconds: // ignored
path: staging/src/k8s.io/client-go/tools/cache/reflector_test.go
user: login: karlkfi
body: done
created_at: 2025-04-15T17:00:07Z
author_association: CONTRIBUTOR
diff_hunk: @@ -416,64 +413,211 @@ func TestReflectorStopWatch(t *testing.T) {
 }
 
 func TestReflectorListAndWatch(t *testing.T) {
-	_, ctx := ktesting.NewTestContext(t)
-	ctx, cancel := context.WithCancel(ctx)
-	defer cancel()
-	createdFakes := make(chan *watch.FakeWatcher)
-
-	// The ListFunc says that it's at revision 1. Therefore, we expect our WatchFunc
-	// to get called at the beginning of the watch with 1, and again with 3 when we
-	// inject an error.
-	expectedRVs := []string{"1", "3"}
-	lw := &ListWatch{
-		WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
-			rv := options.ResourceVersion
-			fw := watch.NewFake()
-			if e, a := expectedRVs[0], rv; e != a {
-				t.Errorf("Expected rv %v, but got %v", e, a)
-			}
-			expectedRVs = expectedRVs[1:]
-			// channel is not buffered because the for loop below needs to block. But
-			// we don't want to block here, so report the new fake via a go routine.
-			go func() { createdFakes <- fw }()
-			return fw, nil
+	type listResult struct {
+		Object runtime.Object
+		Error  error
+	}
+	table := []struct {
+		name                 string
+		useWatchList         bool
+		listResults          []listResult
+		watchEvents          []watch.Event
+		expectedListOptions  []metav1.ListOptions
+		expectedWatchOptions []metav1.ListOptions
+		expectedStore        []metav1.Object
+	}{
+		{
+			name:         "UseWatchList enabled",
+			useWatchList: true,
+			watchEvents: []watch.Event{
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "1"}},
+				},
+				{
+					Type: watch.Bookmark,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{
+						Name:            "foo",
+						ResourceVersion: "1",
+						Annotations:     map[string]string{metav1.InitialEventsAnnotationKey: "true"},
+					}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "2"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "bar", ResourceVersion: "3"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "baz", ResourceVersion: "4"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "qux", ResourceVersion: "5"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "zoo", ResourceVersion: "6"}},
+				},
+			},
+			expectedWatchOptions: []metav1.ListOptions{
+				{
+					AllowWatchBookmarks:  true,
+					ResourceVersion:      "",
+					ResourceVersionMatch: "NotOlderThan",
+					// TimeoutSeconds: // ignored
+					SendInitialEvents: ptr.To(true),
+				},
+			},
+			expectedStore: []metav1.Object{
+				// Pod "foo" with rv "1" is de-duped by rv 2
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "2"}},
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "bar", ResourceVersion: "3"}},
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "baz", ResourceVersion: "4"}},
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "qux", ResourceVersion: "5"}},
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "zoo", ResourceVersion: "6"}},
+			},
 		},
-		ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
-			return &v1.PodList{ListMeta: metav1.ListMeta{ResourceVersion: "1"}}, nil
+		{
+			name:         "UseWatchList disabled",
+			useWatchList: false,
+			listResults: []listResult{
+				{
+					Object: &v1.PodList{
+						ListMeta: metav1.ListMeta{ResourceVersion: "1"},
+						Items: []v1.Pod{
+							{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "1"}},
+						},
+					},
+				},
+			},
+			watchEvents: []watch.Event{
+				{
+					Type:   watch.Added,
path: staging/src/k8s.io/client-go/tools/cache/reflector_test.go
user: login: karlkfi
body: done
created_at: 2025-04-15T17:00:11Z
author_association: CONTRIBUTOR
diff_hunk: @@ -416,64 +413,211 @@ func TestReflectorStopWatch(t *testing.T) {
 }
 
 func TestReflectorListAndWatch(t *testing.T) {
-	_, ctx := ktesting.NewTestContext(t)
-	ctx, cancel := context.WithCancel(ctx)
-	defer cancel()
-	createdFakes := make(chan *watch.FakeWatcher)
-
-	// The ListFunc says that it's at revision 1. Therefore, we expect our WatchFunc
-	// to get called at the beginning of the watch with 1, and again with 3 when we
-	// inject an error.
-	expectedRVs := []string{"1", "3"}
-	lw := &ListWatch{
-		WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
-			rv := options.ResourceVersion
-			fw := watch.NewFake()
-			if e, a := expectedRVs[0], rv; e != a {
-				t.Errorf("Expected rv %v, but got %v", e, a)
-			}
-			expectedRVs = expectedRVs[1:]
-			// channel is not buffered because the for loop below needs to block. But
-			// we don't want to block here, so report the new fake via a go routine.
-			go func() { createdFakes <- fw }()
-			return fw, nil
+	type listResult struct {
+		Object runtime.Object
+		Error  error
+	}
+	table := []struct {
+		name                 string
+		useWatchList         bool
+		listResults          []listResult
+		watchEvents          []watch.Event
+		expectedListOptions  []metav1.ListOptions
+		expectedWatchOptions []metav1.ListOptions
+		expectedStore        []metav1.Object
+	}{
+		{
+			name:         "UseWatchList enabled",
+			useWatchList: true,
+			watchEvents: []watch.Event{
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "1"}},
+				},
+				{
+					Type: watch.Bookmark,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{
+						Name:            "foo",
+						ResourceVersion: "1",
+						Annotations:     map[string]string{metav1.InitialEventsAnnotationKey: "true"},
+					}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "2"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "bar", ResourceVersion: "3"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "baz", ResourceVersion: "4"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "qux", ResourceVersion: "5"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "zoo", ResourceVersion: "6"}},
+				},
+			},
+			expectedWatchOptions: []metav1.ListOptions{
+				{
+					AllowWatchBookmarks:  true,
+					ResourceVersion:      "",
+					ResourceVersionMatch: "NotOlderThan",
+					// TimeoutSeconds: // ignored
path: staging/src/k8s.io/client-go/tools/cache/reflector_test.go
user: login: karlkfi
body: done
created_at: 2025-04-15T17:00:14Z
author_association: CONTRIBUTOR
diff_hunk: @@ -416,64 +413,211 @@ func TestReflectorStopWatch(t *testing.T) {
 }
 
 func TestReflectorListAndWatch(t *testing.T) {
-	_, ctx := ktesting.NewTestContext(t)
-	ctx, cancel := context.WithCancel(ctx)
-	defer cancel()
-	createdFakes := make(chan *watch.FakeWatcher)
-
-	// The ListFunc says that it's at revision 1. Therefore, we expect our WatchFunc
-	// to get called at the beginning of the watch with 1, and again with 3 when we
-	// inject an error.
-	expectedRVs := []string{"1", "3"}
-	lw := &ListWatch{
-		WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
-			rv := options.ResourceVersion
-			fw := watch.NewFake()
-			if e, a := expectedRVs[0], rv; e != a {
-				t.Errorf("Expected rv %v, but got %v", e, a)
-			}
-			expectedRVs = expectedRVs[1:]
-			// channel is not buffered because the for loop below needs to block. But
-			// we don't want to block here, so report the new fake via a go routine.
-			go func() { createdFakes <- fw }()
-			return fw, nil
+	type listResult struct {
+		Object runtime.Object
+		Error  error
+	}
+	table := []struct {
+		name                 string
+		useWatchList         bool
+		listResults          []listResult
+		watchEvents          []watch.Event
+		expectedListOptions  []metav1.ListOptions
+		expectedWatchOptions []metav1.ListOptions
+		expectedStore        []metav1.Object
+	}{
+		{
+			name:         "UseWatchList enabled",
+			useWatchList: true,
+			watchEvents: []watch.Event{
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "1"}},
+				},
+				{
+					Type: watch.Bookmark,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{
+						Name:            "foo",
+						ResourceVersion: "1",
+						Annotations:     map[string]string{metav1.InitialEventsAnnotationKey: "true"},
+					}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "2"}},
path: staging/src/k8s.io/client-go/tools/cache/reflector_test.go
user: login: karlkfi
body: Modified is what I intended, yeah. fixed.
created_at: 2025-04-15T17:00:16Z
author_association: CONTRIBUTOR
diff_hunk: @@ -416,64 +413,211 @@ func TestReflectorStopWatch(t *testing.T) {
 }
 
 func TestReflectorListAndWatch(t *testing.T) {
-	_, ctx := ktesting.NewTestContext(t)
-	ctx, cancel := context.WithCancel(ctx)
-	defer cancel()
-	createdFakes := make(chan *watch.FakeWatcher)
-
-	// The ListFunc says that it's at revision 1. Therefore, we expect our WatchFunc
-	// to get called at the beginning of the watch with 1, and again with 3 when we
-	// inject an error.
-	expectedRVs := []string{"1", "3"}
-	lw := &ListWatch{
-		WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
-			rv := options.ResourceVersion
-			fw := watch.NewFake()
-			if e, a := expectedRVs[0], rv; e != a {
-				t.Errorf("Expected rv %v, but got %v", e, a)
-			}
-			expectedRVs = expectedRVs[1:]
-			// channel is not buffered because the for loop below needs to block. But
-			// we don't want to block here, so report the new fake via a go routine.
-			go func() { createdFakes <- fw }()
-			return fw, nil
+	type listResult struct {
+		Object runtime.Object
+		Error  error
+	}
+	table := []struct {
+		name                 string
+		useWatchList         bool
+		listResults          []listResult
+		watchEvents          []watch.Event
+		expectedListOptions  []metav1.ListOptions
+		expectedWatchOptions []metav1.ListOptions
+		expectedStore        []metav1.Object
+	}{
+		{
+			name:         "UseWatchList enabled",
+			useWatchList: true,
+			watchEvents: []watch.Event{
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "1"}},
+				},
+				{
+					Type: watch.Bookmark,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{
+						Name:            "foo",
+						ResourceVersion: "1",
+						Annotations:     map[string]string{metav1.InitialEventsAnnotationKey: "true"},
+					}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "2"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "bar", ResourceVersion: "3"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "baz", ResourceVersion: "4"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "qux", ResourceVersion: "5"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "zoo", ResourceVersion: "6"}},
+				},
+			},
+			expectedWatchOptions: []metav1.ListOptions{
+				{
+					AllowWatchBookmarks:  true,
+					ResourceVersion:      "",
+					ResourceVersionMatch: "NotOlderThan",
+					// TimeoutSeconds: // ignored
+					SendInitialEvents: ptr.To(true),
+				},
+			},
+			expectedStore: []metav1.Object{
+				// Pod "foo" with rv "1" is de-duped by rv 2
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "2"}},
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "bar", ResourceVersion: "3"}},
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "baz", ResourceVersion: "4"}},
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "qux", ResourceVersion: "5"}},
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "zoo", ResourceVersion: "6"}},
+			},
 		},
-		ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
-			return &v1.PodList{ListMeta: metav1.ListMeta{ResourceVersion: "1"}}, nil
+		{
+			name:         "UseWatchList disabled",
+			useWatchList: false,
+			listResults: []listResult{
+				{
+					Object: &v1.PodList{
+						ListMeta: metav1.ListMeta{ResourceVersion: "1"},
+						Items: []v1.Pod{
+							{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "1"}},
+						},
+					},
+				},
+			},
+			watchEvents: []watch.Event{
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "2"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "bar", ResourceVersion: "3"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "baz", ResourceVersion: "4"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "qux", ResourceVersion: "5"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "zoo", ResourceVersion: "6"}},
+				},
+			},
+			expectedListOptions: []metav1.ListOptions{
+				{
+					AllowWatchBookmarks:  true,
+					ResourceVersion:      "1",
+					ResourceVersionMatch: "", // TODO: Why not NotOlderThan?
+					// TimeoutSeconds: // ignored
+					SendInitialEvents: nil,
+				},
+			},
+			expectedWatchOptions: []metav1.ListOptions{
+				{
+					AllowWatchBookmarks:  true,
+					ResourceVersion:      "1",
+					ResourceVersionMatch: "", // TODO: Why not NotOlderThan?
path: staging/src/k8s.io/client-go/tools/cache/reflector_test.go
user: login: karlkfi
body: Looks like the docs say it's recommended to set, but when RV is set to something other than "0" RVM defaults to NotOlderThan. So it sounds optional in this case.
created_at: 2025-04-15T17:08:03Z
author_association: CONTRIBUTOR
diff_hunk: @@ -416,64 +413,211 @@ func TestReflectorStopWatch(t *testing.T) {
 }
 
 func TestReflectorListAndWatch(t *testing.T) {
-	_, ctx := ktesting.NewTestContext(t)
-	ctx, cancel := context.WithCancel(ctx)
-	defer cancel()
-	createdFakes := make(chan *watch.FakeWatcher)
-
-	// The ListFunc says that it's at revision 1. Therefore, we expect our WatchFunc
-	// to get called at the beginning of the watch with 1, and again with 3 when we
-	// inject an error.
-	expectedRVs := []string{"1", "3"}
-	lw := &ListWatch{
-		WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
-			rv := options.ResourceVersion
-			fw := watch.NewFake()
-			if e, a := expectedRVs[0], rv; e != a {
-				t.Errorf("Expected rv %v, but got %v", e, a)
-			}
-			expectedRVs = expectedRVs[1:]
-			// channel is not buffered because the for loop below needs to block. But
-			// we don't want to block here, so report the new fake via a go routine.
-			go func() { createdFakes <- fw }()
-			return fw, nil
+	type listResult struct {
+		Object runtime.Object
+		Error  error
+	}
+	table := []struct {
+		name                 string
+		useWatchList         bool
+		listResults          []listResult
+		watchEvents          []watch.Event
+		expectedListOptions  []metav1.ListOptions
+		expectedWatchOptions []metav1.ListOptions
+		expectedStore        []metav1.Object
+	}{
+		{
+			name:         "UseWatchList enabled",
+			useWatchList: true,
+			watchEvents: []watch.Event{
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "1"}},
+				},
+				{
+					Type: watch.Bookmark,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{
+						Name:            "foo",
+						ResourceVersion: "1",
+						Annotations:     map[string]string{metav1.InitialEventsAnnotationKey: "true"},
+					}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "2"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "bar", ResourceVersion: "3"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "baz", ResourceVersion: "4"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "qux", ResourceVersion: "5"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "zoo", ResourceVersion: "6"}},
+				},
+			},
+			expectedWatchOptions: []metav1.ListOptions{
+				{
+					AllowWatchBookmarks:  true,
+					ResourceVersion:      "",
+					ResourceVersionMatch: "NotOlderThan",
+					// TimeoutSeconds: // ignored
+					SendInitialEvents: ptr.To(true),
+				},
+			},
+			expectedStore: []metav1.Object{
+				// Pod "foo" with rv "1" is de-duped by rv 2
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "2"}},
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "bar", ResourceVersion: "3"}},
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "baz", ResourceVersion: "4"}},
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "qux", ResourceVersion: "5"}},
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "zoo", ResourceVersion: "6"}},
+			},
 		},
-		ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
-			return &v1.PodList{ListMeta: metav1.ListMeta{ResourceVersion: "1"}}, nil
+		{
+			name:         "UseWatchList disabled",
+			useWatchList: false,
+			listResults: []listResult{
+				{
+					Object: &v1.PodList{
+						ListMeta: metav1.ListMeta{ResourceVersion: "1"},
+						Items: []v1.Pod{
+							{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "1"}},
+						},
+					},
+				},
+			},
+			watchEvents: []watch.Event{
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "2"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "bar", ResourceVersion: "3"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "baz", ResourceVersion: "4"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "qux", ResourceVersion: "5"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "zoo", ResourceVersion: "6"}},
+				},
+			},
+			expectedListOptions: []metav1.ListOptions{
+				{
+					AllowWatchBookmarks:  true,
+					ResourceVersion:      "1",
+					ResourceVersionMatch: "", // TODO: Why not NotOlderThan?
+					// TimeoutSeconds: // ignored
+					SendInitialEvents: nil,
+				},
+			},
+			expectedWatchOptions: []metav1.ListOptions{
+				{
+					AllowWatchBookmarks:  true,
+					ResourceVersion:      "1",
+					ResourceVersionMatch: "", // TODO: Why not NotOlderThan?
path: staging/src/k8s.io/client-go/tools/cache/reflector_test.go
user: login: karlkfi
body: It's actually also optional in the ListWatch case, since Limit and RV are empty, but it sends it anyway. Slightly odd inconsistency, but I guess it's not broken.
created_at: 2025-04-15T17:19:24Z
author_association: CONTRIBUTOR
diff_hunk: @@ -416,64 +413,211 @@ func TestReflectorStopWatch(t *testing.T) {
 }
 
 func TestReflectorListAndWatch(t *testing.T) {
-	_, ctx := ktesting.NewTestContext(t)
-	ctx, cancel := context.WithCancel(ctx)
-	defer cancel()
-	createdFakes := make(chan *watch.FakeWatcher)
-
-	// The ListFunc says that it's at revision 1. Therefore, we expect our WatchFunc
-	// to get called at the beginning of the watch with 1, and again with 3 when we
-	// inject an error.
-	expectedRVs := []string{"1", "3"}
-	lw := &ListWatch{
-		WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
-			rv := options.ResourceVersion
-			fw := watch.NewFake()
-			if e, a := expectedRVs[0], rv; e != a {
-				t.Errorf("Expected rv %v, but got %v", e, a)
-			}
-			expectedRVs = expectedRVs[1:]
-			// channel is not buffered because the for loop below needs to block. But
-			// we don't want to block here, so report the new fake via a go routine.
-			go func() { createdFakes <- fw }()
-			return fw, nil
+	type listResult struct {
+		Object runtime.Object
+		Error  error
+	}
+	table := []struct {
+		name                 string
+		useWatchList         bool
+		listResults          []listResult
+		watchEvents          []watch.Event
+		expectedListOptions  []metav1.ListOptions
+		expectedWatchOptions []metav1.ListOptions
+		expectedStore        []metav1.Object
+	}{
+		{
+			name:         "UseWatchList enabled",
+			useWatchList: true,
+			watchEvents: []watch.Event{
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "1"}},
+				},
+				{
+					Type: watch.Bookmark,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{
+						Name:            "foo",
+						ResourceVersion: "1",
+						Annotations:     map[string]string{metav1.InitialEventsAnnotationKey: "true"},
+					}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "2"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "bar", ResourceVersion: "3"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "baz", ResourceVersion: "4"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "qux", ResourceVersion: "5"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "zoo", ResourceVersion: "6"}},
+				},
+			},
+			expectedWatchOptions: []metav1.ListOptions{
+				{
+					AllowWatchBookmarks:  true,
+					ResourceVersion:      "",
+					ResourceVersionMatch: "NotOlderThan",
+					// TimeoutSeconds: // ignored
+					SendInitialEvents: ptr.To(true),
+				},
+			},
+			expectedStore: []metav1.Object{
+				// Pod "foo" with rv "1" is de-duped by rv 2
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "2"}},
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "bar", ResourceVersion: "3"}},
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "baz", ResourceVersion: "4"}},
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "qux", ResourceVersion: "5"}},
+				&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "zoo", ResourceVersion: "6"}},
+			},
 		},
-		ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
-			return &v1.PodList{ListMeta: metav1.ListMeta{ResourceVersion: "1"}}, nil
+		{
+			name:         "UseWatchList disabled",
+			useWatchList: false,
+			listResults: []listResult{
+				{
+					Object: &v1.PodList{
+						ListMeta: metav1.ListMeta{ResourceVersion: "1"},
+						Items: []v1.Pod{
+							{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "1"}},
+						},
+					},
+				},
+			},
+			watchEvents: []watch.Event{
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "2"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "bar", ResourceVersion: "3"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "baz", ResourceVersion: "4"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "qux", ResourceVersion: "5"}},
+				},
+				{
+					Type:   watch.Added,
+					Object: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "zoo", ResourceVersion: "6"}},
+				},
+			},
+			expectedListOptions: []metav1.ListOptions{
+				{
+					AllowWatchBookmarks:  true,
+					ResourceVersion:      "1",
path: staging/src/k8s.io/client-go/tools/cache/reflector_test.go
user: login: karlkfi
body: Oh, this is the List. It should be "0" actually.

Turns out I forgot to add the validation for that new expectation.
Fixed.
created_at: 2025-04-15T17:26:06Z
author_association: CONTRIBUTOR

PR comments:
user: login: k8s-ci-robot
created_at: 2025-04-11T21:50:04Z
body: Please note that we're already in [Test Freeze](https://github.com/kubernetes/sig-release/blob/master/releases/release_phases.md#test-freeze) for the `release-1.33` branch. This means every merged PR will be automatically fast-forwarded via the periodic [ci-fast-forward](https://testgrid.k8s.io/sig-release-releng-blocking#git-repo-kubernetes-fast-forward) job to the release branch of the upcoming v1.33.0 release.

Fast forwards are scheduled to happen every 6 hours, whereas the most recent run was: Fri Apr 11 19:28:57 UTC 2025.

author_association: CONTRIBUTOR
user: login: karlkfi
created_at: 2025-04-15T19:03:44Z
body: Followup: 
- https://github.com/kubernetes/kubernetes/pull/131321
author_association: CONTRIBUTOR
user: login: cici37
created_at: 2025-04-15T20:25:13Z
body: /triage accepted
author_association: CONTRIBUTOR
user: login: wojtek-t
created_at: 2025-04-16T06:45:06Z
body: /lgtm
/approve
author_association: MEMBER
user: login: k8s-ci-robot
created_at: 2025-04-16T06:45:13Z
body: LGTM label has been added.  <details>Git tree hash: e2ce315fe49050898c462d8f0fd9b64d841c7e60</details>
author_association: CONTRIBUTOR
user: login: k8s-ci-robot
created_at: 2025-04-16T06:45:20Z
body: [APPROVALNOTIFIER] This PR is **APPROVED**

This pull-request has been approved by: *<a href="https://github.com/kubernetes/kubernetes/pull/131266#" title="Author self-approved">karlkfi</a>*, *<a href="https://github.com/kubernetes/kubernetes/pull/131266#issuecomment-2808554596" title="Approved">wojtek-t</a>*

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=kubernetes%2Fkubernetes).

The pull request process is described [here](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process)

<details >
Needs approval from an approver in each of these files:

- ~~[staging/src/k8s.io/client-go/tools/cache/OWNERS](https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/client-go/tools/cache/OWNERS)~~ [wojtek-t]

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":[]} -->
author_association: CONTRIBUTOR