Skip to content

Commit acfc9c4

Browse files
add integration test guide
1 parent 002c18b commit acfc9c4

File tree

2 files changed

+80
-0
lines changed

2 files changed

+80
-0
lines changed
File renamed without changes.

docs/testing/integration.md

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
**Writing and Running Integration Tests**
2+
3+
This article explores steps to write and run integration tests for Kubebuilder. Kubebuilder provides a template for writing integration tests. You can simply run all integration (and unit) tests within the project by running: `make test`
4+
5+
For example, there is a controller watches *Parent* objects. The *Parent* objects create *Child* objects. Note that the *Child* objects must have their `.ownerReferences` field setting to the `Parent` objects. You can find the template under `pkg/controller/parent/parent_controller_test.go`:
6+
```
7+
package parent
8+
9+
import (
10+
_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
11+
childapis "k8s.io/child/pkg/apis"
12+
childv1alpha1 "k8s.io/childrepo/pkg/apis/child/v1alpha1"
13+
parentapis "k8s.io/parent/pkg/apis"
14+
parentv1alpha1 "k8s.io/parentrepo/pkg/apis/parent/v1alpha1"
15+
16+
...<other import items>...
17+
)
18+
19+
const timeout = time.Second * 5
20+
21+
var c client.Client
22+
var expectedRequest = reconcile.Request{NamespacedName: types.NamespacedName{Name: "parent", Namespace: "default"}}
23+
var childKey = types.NamespacedName{Name: "child", Namespace: "default"}
24+
25+
func TestReconcile(t *testing.T) {
26+
g := gomega.NewGomegaWithT(t)
27+
28+
// Parent instance to be created.
29+
parent := &parentv1alpha1.Parent{
30+
ObjectMeta: metav1.ObjectMeta{
31+
Name: "parent",
32+
Namespace: "default",
33+
},
34+
Spec: metav1.ParentSpec{
35+
SomeSpecField: "SomeSpecValue",
36+
AnotherSpecField: "AnotherSpecValue",
37+
},
38+
}
39+
40+
// Setup the Manager and Controller. Wrap the Controller Reconcile function
41+
// so it writes each request to a channel when it is finished.
42+
mgr, err := manager.New(cfg, manager.Options{})
43+
44+
// Setup Scheme for all resources.
45+
if err = parentapis.AddToScheme(mgr.GetScheme()); err != nil {
46+
t.Logf("failed to add Parent scheme: %v", err)
47+
}
48+
if err = childapis.AddToScheme(mgr.GetScheme()); err != nil {
49+
t.Logf("failed to add Child scheme: %v", err)
50+
}
51+
52+
// Set up and start test manager.
53+
reconciler, err := newReconciler(mgr)
54+
g.Expect(err).NotTo(gomega.HaveOccurred())
55+
recFn, requests := SetupTestReconcile(reconciler)
56+
g.Expect(add(mgr, recFn)).NotTo(gomega.HaveOccurred())
57+
defer close(StartTestManager(mgr, g))
58+
59+
// Create the Parent object and expect the Reconcile and Child to be created.
60+
c = mgr.GetClient()
61+
err = c.Create(context.TODO(), parent)
62+
g.Expect(err).NotTo(gomega.HaveOccurred())
63+
defer c.Delete(context.TODO(), parent)
64+
g.Eventually(requests, timeout).Should(gomega.Receive(gomega.Equal(expectedRequest)))
65+
66+
// Verify Child is created.
67+
child := &childv1alpha1.Child{}
68+
g.Eventually(func() error { return c.Get(context.TODO(), childKey, child) }, timeout).
69+
Should(gomega.Succeed())
70+
71+
// Manually delete Child since GC isn't enabled in the test control plane.
72+
g.Expect(c.Delete(context.TODO(), child)).To(gomega.Succeed())
73+
}
74+
```
75+
76+
`SetupTestReconcile` function above brings up an API server and etcd instance. Note that there is no any node creation for integration testing environment. If you want to test your controller on a real node, you should write end-to-end tests.
77+
78+
The manager is started as part of the test itself (`StartTestManager` function).
79+
80+
Both functions are located in `pkg/controller/parent/parent_controller_suite_test.go` file. The file also contains a `TestMain` function that allows you to specify CRD directory paths for the testing environment.

0 commit comments

Comments
 (0)