From 7dddf976b8ec6a81afc0dcf9eac722d6015b5a69 Mon Sep 17 00:00:00 2001 From: Haowei Cai Date: Mon, 26 Oct 2020 22:50:32 -0700 Subject: [PATCH] fix the fake client example: how to handle a race between the fake client and informer Note that the fake client isn't designed to work with informer. It doesn't support resource version. It's encouraged to use a real client in an integration/E2E test if you need to test complex behavior with informer/controllers. Kubernetes-commit: 942bc9b32e39bb9c6ca045c02b48cc84dfa86633 --- examples/fake-client/main_test.go | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/examples/fake-client/main_test.go b/examples/fake-client/main_test.go index 456a4bbc..a2f0eeef 100644 --- a/examples/fake-client/main_test.go +++ b/examples/fake-client/main_test.go @@ -21,11 +21,13 @@ import ( "testing" "time" - "k8s.io/api/core/v1" + v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/apimachinery/pkg/watch" "k8s.io/client-go/informers" "k8s.io/client-go/kubernetes/fake" + clienttesting "k8s.io/client-go/testing" "k8s.io/client-go/tools/cache" ) @@ -34,8 +36,20 @@ func TestFakeClient(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() + watcherStarted := make(chan struct{}) // Create the fake client. client := fake.NewSimpleClientset() + // A catch-all watch reactor that allows us to inject the watcherStarted channel. + client.PrependWatchReactor("*", func(action clienttesting.Action) (handled bool, ret watch.Interface, err error) { + gvr := action.GetResource() + ns := action.GetNamespace() + watch, err := client.Tracker().Watch(gvr, ns) + if err != nil { + return false, nil, err + } + close(watcherStarted) + return true, watch, nil + }) // We will create an informer that writes added pods to a channel. pods := make(chan *v1.Pod, 1) @@ -57,6 +71,15 @@ func TestFakeClient(t *testing.T) { // we send any events to it. cache.WaitForCacheSync(ctx.Done(), podInformer.HasSynced) + // The fake client doesn't support resource version. Any writes to the client + // after the informer's initial LIST and before the informer establishing the + // watcher will be missed by the informer. Therefore we wait until the watcher + // starts. + // Note that the fake client isn't designed to work with informer. It + // doesn't support resource version. It's encouraged to use a real client + // in an integration/E2E test if you need to test complex behavior with + // informer/controllers. + <-watcherStarted // Inject an event into the fake client. p := &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "my-pod"}} _, err := client.CoreV1().Pods("test-ns").Create(context.TODO(), p, metav1.CreateOptions{})