Merge pull request #95897 from roycaihw/doc/fake-client-with-informer

Fake client example: document how to handle a race with informer

Kubernetes-commit: 6f8a058e2c29680dccffd9df07765c10e1f69b53
This commit is contained in:
Kubernetes Publisher 2021-04-08 14:27:04 -07:00
commit c36b96a74b
4 changed files with 28 additions and 5 deletions

2
Godeps/Godeps.json generated
View File

@ -476,7 +476,7 @@
},
{
"ImportPath": "k8s.io/api",
"Rev": "3a2d6b5bb7f8"
"Rev": "2824ee61d1ae"
},
{
"ImportPath": "k8s.io/apimachinery",

View File

@ -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{})

4
go.mod
View File

@ -27,7 +27,7 @@ require (
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba
k8s.io/api v0.0.0-20210323190948-3a2d6b5bb7f8
k8s.io/api v0.0.0-20210408212643-2824ee61d1ae
k8s.io/apimachinery v0.0.0-20210313025227-57f2a0733447
k8s.io/klog/v2 v2.8.0
k8s.io/utils v0.0.0-20201110183641-67b214c5f920
@ -36,6 +36,6 @@ require (
)
replace (
k8s.io/api => k8s.io/api v0.0.0-20210323190948-3a2d6b5bb7f8
k8s.io/api => k8s.io/api v0.0.0-20210408212643-2824ee61d1ae
k8s.io/apimachinery => k8s.io/apimachinery v0.0.0-20210313025227-57f2a0733447
)

2
go.sum
View File

@ -431,7 +431,7 @@ honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
k8s.io/api v0.0.0-20210323190948-3a2d6b5bb7f8/go.mod h1:7Byi1J8zhqxObDDyvyvJdvEZioXQZDTsNqSFMk4JMMM=
k8s.io/api v0.0.0-20210408212643-2824ee61d1ae/go.mod h1:7Byi1J8zhqxObDDyvyvJdvEZioXQZDTsNqSFMk4JMMM=
k8s.io/apimachinery v0.0.0-20210313025227-57f2a0733447/go.mod h1:jbreFvJo3ov9rj7eWT7+sYiRx+qZuCYXwWT1bcDswPY=
k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=