cacher: apply key for initial events only if the call is not recursive

Kubernetes-commit: 7cb51b1c278f9eb57c43f929fcc80bfed8438e17
This commit is contained in:
Lukasz Szaszkiewicz 2024-09-10 10:58:26 +02:00 committed by Kubernetes Publisher
parent 197cd431b1
commit 8a764cf9c3
4 changed files with 67 additions and 0 deletions

View File

@ -390,6 +390,12 @@ func TestWatchSemanticInitialEventsExtended(t *testing.T) {
storagetesting.RunWatchSemanticInitialEventsExtended(context.TODO(), t, store)
}
func TestWatchListMatchSingle(t *testing.T) {
store, terminate := testSetupWithEtcdAndCreateWrapper(t)
t.Cleanup(terminate)
storagetesting.RunWatchListMatchSingle(context.TODO(), t, store)
}
// ===================================================
// Test-setup related function are following.
// ===================================================

View File

@ -696,6 +696,7 @@ func (w *watchCache) isIndexValidLocked(index int) bool {
// be called under the watchCache lock.
func (w *watchCache) getAllEventsSinceLocked(resourceVersion uint64, key string, opts storage.ListOptions) (*watchCacheInterval, error) {
_, matchesSingle := opts.Predicate.MatchesSingle()
matchesSingle = matchesSingle && !opts.Recursive
if opts.SendInitialEvents != nil && *opts.SendInitialEvents {
return w.getIntervalFromStoreLocked(key, matchesSingle)
}

View File

@ -144,6 +144,11 @@ func TestEtcdWatchSemanticInitialEventsExtended(t *testing.T) {
storagetesting.RunWatchSemanticInitialEventsExtended(ctx, t, store)
}
func TestWatchListMatchSingle(t *testing.T) {
ctx, store, _ := testSetup(t)
storagetesting.RunWatchListMatchSingle(ctx, t, store)
}
// =======================================================================
// Implementation-specific tests are following.
// The following tests are exercising the details of the implementation

View File

@ -1571,6 +1571,61 @@ func RunWatchSemanticInitialEventsExtended(ctx context.Context, t *testing.T, st
testCheckNoMoreResults(t, w)
}
func RunWatchListMatchSingle(ctx context.Context, t *testing.T, store storage.Interface) {
trueVal := true
expectedInitialEventsInStrictOrder := func(initialPod *example.Pod, globalResourceVersion string) []watch.Event {
watchEvents := []watch.Event{}
watchEvents = append(watchEvents, watch.Event{Type: watch.Added, Object: initialPod})
watchEvents = append(watchEvents, watch.Event{Type: watch.Bookmark, Object: &example.Pod{
ObjectMeta: metav1.ObjectMeta{
ResourceVersion: globalResourceVersion,
Annotations: map[string]string{metav1.InitialEventsAnnotationKey: "true"},
},
}})
return watchEvents
}
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.WatchList, true)
// add the pod for which the field selector will be constructed
ns := "ns-foo"
expectedPod := &example.Pod{}
initialPod := makePod("1")
initialPod.Namespace = ns
err := store.Create(ctx, computePodKey(initialPod), initialPod, expectedPod, 0)
require.NoError(t, err, "failed to add a pod: %v")
// add more pods that won't match the field selector
lastAddedPod := &example.Pod{}
for _, otherPod := range []*example.Pod{makePod("2"), makePod("3"), makePod("4"), makePod("5")} {
otherPod.Namespace = ns
err = store.Create(ctx, computePodKey(otherPod), otherPod, lastAddedPod, 0)
require.NoError(t, err, "failed to add a pod: %v")
}
opts := storage.ListOptions{
Predicate: storage.SelectionPredicate{
Label: labels.Everything(),
Field: fields.ParseSelectorOrDie("metadata.name=pod-1"),
GetAttrs: func(obj runtime.Object) (labels.Set, fields.Set, error) {
pod := obj.(*example.Pod)
return nil, fields.Set{"metadata.name": pod.Name}, nil
},
},
Recursive: true,
}
opts.SendInitialEvents = &trueVal
opts.Predicate.AllowWatchBookmarks = true
w, err := store.Watch(context.Background(), "/pods", opts)
require.NoError(t, err, "failed to create watch: %v")
defer w.Stop()
// make sure we only get a single pod matching the field selector
// followed by the bookmark with the global RV
testCheckResultsInStrictOrder(t, w, expectedInitialEventsInStrictOrder(expectedPod, lastAddedPod.ResourceVersion))
testCheckNoMoreResults(t, w)
}
func makePod(namePrefix string) *example.Pod {
return &example.Pod{
ObjectMeta: metav1.ObjectMeta{