diff --git a/examples/README.md b/examples/README.md index 4bdc6b1c..0bbc5672 100644 --- a/examples/README.md +++ b/examples/README.md @@ -25,3 +25,7 @@ for client-go. the custom resources. [informer]: https://godoc.org/k8s.io/client-go/tools/cache#NewInformer + +### Testing + +- [**Fake Client**](./fake-client): Use a fake client in tests. \ No newline at end of file diff --git a/examples/fake-client/README.md b/examples/fake-client/README.md new file mode 100644 index 00000000..89874460 --- /dev/null +++ b/examples/fake-client/README.md @@ -0,0 +1,14 @@ +# Fake Client Example + +This example demonstrates how to use a fake client with SharedInformerFactory in tests. + +It covers: + * Creating the fake client + * Setting up real informers + * Injecting events into those informers + +## Running + +``` +go test -v k8s.io/client-go/examples/fake-client +``` \ No newline at end of file diff --git a/examples/fake-client/main_test.go b/examples/fake-client/main_test.go new file mode 100644 index 00000000..d77d7ecb --- /dev/null +++ b/examples/fake-client/main_test.go @@ -0,0 +1,77 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package fakeclient + +import ( + "context" + "testing" + "time" + + "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/informers" + "k8s.io/client-go/kubernetes/fake" + "k8s.io/client-go/tools/cache" +) + +// TestFakeClient demonstrates how to use a fake client with SharedInformerFactory in tests. +func TestFakeClient(t *testing.T) { + // Use a timeout to keep the test from hanging. + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + + // Create the fake client. + client := fake.NewSimpleClientset() + + // We will create an informer that writes added pods to a channel. + pods := make(chan *v1.Pod, 1) + informers := informers.NewSharedInformerFactory(client, 0) + podInformer := informers.Core().V1().Pods().Informer() + podInformer.AddEventHandler(&cache.ResourceEventHandlerFuncs{ + AddFunc: func(obj interface{}) { + pod := obj.(*v1.Pod) + t.Logf("pod added: %s/%s", pod.Namespace, pod.Name) + pods <- pod + cancel() + }, + }) + + // Make sure informers are running. + informers.Start(ctx.Done()) + + // This is not required in tests, but it serves as a proof-of-concept by + // ensuring that the informer goroutine have warmed up and called List before + // we send any events to it. + for !podInformer.HasSynced() { + time.Sleep(10 * time.Millisecond) + } + + // Inject an event into the fake client. + p := &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "my-pod"}} + _, err := client.Core().Pods("test-ns").Create(p) + if err != nil { + t.Errorf("error injecting pod add: %v", err) + } + + // Wait and check result. + <-ctx.Done() + select { + case pod := <-pods: + t.Logf("Got pod from channel: %s/%s", pod.Namespace, pod.Name) + default: + t.Error("Informer did not get the added pod") + } +}