From 921628ecd68052bf47c38ec6d16dbb9718284f32 Mon Sep 17 00:00:00 2001 From: Karl Isenberg Date: Tue, 15 Apr 2025 11:48:57 -0700 Subject: [PATCH] chore: Add VeryShortWatchError typed error - Add a new VeryShortWatchError struct for error matching, returned by `handleAnyWatch`, up through `Reflector.ListAndWatch`. - Update test expectations to match exact errors. Kubernetes-commit: 6eff9db0f10db72f2c64390e106a80621d136439 --- tools/cache/reflector.go | 15 ++++++++++++++- tools/cache/reflector_test.go | 6 ++---- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/tools/cache/reflector.go b/tools/cache/reflector.go index 019b3cf1..5a7113da 100644 --- a/tools/cache/reflector.go +++ b/tools/cache/reflector.go @@ -960,7 +960,7 @@ loop: watchDuration := clock.Since(start) if watchDuration < 1*time.Second && eventCount == 0 { - return watchListBookmarkReceived, fmt.Errorf("very short watch: %s: Unexpected watch close - watch lasted less than a second and no items received", name) + return watchListBookmarkReceived, &VeryShortWatchError{Name: name} } klog.FromContext(ctx).V(4).Info("Watch close", "reflector", name, "type", expectedTypeName, "totalItems", eventCount) return watchListBookmarkReceived, nil @@ -1162,3 +1162,16 @@ type noopTicker struct{} func (t *noopTicker) C() <-chan time.Time { return nil } func (t *noopTicker) Stop() {} + +// VeryShortWatchError is returned when the watch result channel is closed +// within one second, without having sent any events. +type VeryShortWatchError struct { + // Name of the Reflector + Name string +} + +// Error implements the error interface +func (e *VeryShortWatchError) Error() string { + return fmt.Sprintf("very short watch: %s: Unexpected watch close - "+ + "watch lasted less than a second and no items received", e.Name) +} diff --git a/tools/cache/reflector_test.go b/tools/cache/reflector_test.go index 56b53769..c1c3fef0 100644 --- a/tools/cache/reflector_test.go +++ b/tools/cache/reflector_test.go @@ -291,8 +291,7 @@ 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) - // TODO(karlkfi): Add exact error type for "very short watch" - require.Error(t, err) + require.Equal(t, &VeryShortWatchError{Name: g.name}, err) // Ensure handleWatch calls ResultChan and Stop assert.Equal(t, []string{"ResultChan", "Stop"}, calls) } @@ -323,8 +322,7 @@ 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) - // TODO(karlkfi): Add exact error type for "very short watch" - require.Error(t, err) + require.Equal(t, &VeryShortWatchError{Name: g.name}, err) // Ensure handleWatch calls ResultChan and Stop assert.Equal(t, []string{"ResultChan", "Stop"}, calls) }