Repository: istio/istio
File: pkg/kube/client.go (Go)

Code before:
		fc.PrependReactor("list", "*", listReactor)
		fc.PrependWatchReactor("*", watchReactor(fc.Tracker()))
		fc.PrependReactor("create", "*", createReactor)
	}

	c.fastSync = true
	c.isFake = true

	c.version = lazy.NewWithRetry(c.kube.Discovery().ServerVersion)

	if NewCrdWatcher != nil {
		c.crdWatcher = NewCrdWatcher(c)
	}

	return c
}

func NewFakeClientWithVersion(minor string, objects ...runtime.Object) CLIClient {
	c := NewFakeClient(objects...).(*client)
	c.Kube().Discovery().(*fakediscovery.FakeDiscovery).FakedServerVersion = &kubeVersion.Info{Major: "1", Minor: minor, GitVersion: fmt.Sprintf("v1.%v.0", minor)}
	return c
}

// NewFakeClientWithRetries creates a fake client that fails for pod/namespace get operations
// for the first failureCount attempts, then succeeds.
func NewFakeClientWithRetries(failureCount int, objects ...runtime.Object) CLIClient {
	c := NewFakeClient(objects...).(*client)

	// Track retry attempts per resource
	attempts := &sync.Map{}

	// Create a reactor that fails initially then succeeds
	retryReactor := func(action clienttesting.Action) (handled bool, ret runtime.Object, err error) {
		// Only handle Get actions for pods and namespaces
		if action.GetVerb() != "get" {
			return false, nil, nil
		}
		resource := action.GetResource().Resource
		if resource != "pods" && resource != "namespaces" {
			return false, nil, nil
		}

		getAction := action.(clienttesting.GetAction)
		key := fmt.Sprintf("%s/%s/%s", resource, action.GetNamespace(), getAction.GetName())

		val, _ := attempts.LoadOrStore(key, atomic.NewInt32(0))
		attemptCounter := val.(*atomic.Int32)

		currentAttempt := attemptCounter.Inc()

		if int(currentAttempt) <= failureCount {

Review comment (bug):
This could take a slice/set of kinds which fail. Only kinds in the failingKinds arg error out? It would let you tease out the different failure paths in the retry logic more directly.

Code after:
	} {
		fc.PrependReactor("list", "*", listReactor)
		fc.PrependWatchReactor("*", watchReactor(fc.Tracker()))
		fc.PrependReactor("create", "*", createReactor)
	}

	c.fastSync = true
	c.isFake = true

	c.version = lazy.NewWithRetry(c.kube.Discovery().ServerVersion)

	if NewCrdWatcher != nil {
		c.crdWatcher = NewCrdWatcher(c)
	}

	return c
}

func NewFakeClientWithVersion(minor string, objects ...runtime.Object) CLIClient {
	c := NewFakeClient(objects...).(*client)
	c.Kube().Discovery().(*fakediscovery.FakeDiscovery).FakedServerVersion = &kubeVersion.Info{Major: "1", Minor: minor, GitVersion: fmt.Sprintf("v1.%v.0", minor)}
	return c
}

// NewFakeClientWithNFailures creates a fake client that fails for get operations on the specified
// resource kinds for the first failureCount attempts, then succeeds.
// failingResources is a set of resource (e.g., "pods", "namespaces") that should fail.
func NewFakeClientWithNFailures(failureCount int, failingResources sets.Set[schema.GroupVersionResource], objects ...runtime.Object) CLIClient {
	c := NewFakeClient(objects...).(*client)

	// Track retry attempts per resource
	attempts := &sync.Map{}

	// Create a reactor that fails initially then succeeds
	retryReactor := func(action clienttesting.Action) (handled bool, ret runtime.Object, err error) {
		// Only handle Get actions for failingResources
		if action.GetVerb() != "get" {
			return false, nil, nil
		}
		resource := action.GetResource()
		if !failingResources.Contains(resource) {
			return false, nil, nil
		}

		getAction := action.(clienttesting.GetAction)
		key := fmt.Sprintf("%s/%s/%s", resource, action.GetNamespace(), getAction.GetName())

		val, _ := attempts.LoadOrStore(key, atomic.NewInt32(0))
		attemptCounter := val.(*atomic.Int32)

		currentAttempt := attemptCounter.Inc()