1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package unmanageddetector_test
16
17 import (
18 "context"
19 "fmt"
20 "reflect"
21 "testing"
22
23 "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/apis/k8s/v1alpha1"
24 "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/controller/unmanageddetector"
25 "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/k8s"
26 "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/randomid"
27 "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/test"
28 testcontroller "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/test/controller"
29 testmain "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/test/main"
30 testvariable "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/test/resourcefixture/variable"
31 "github.com/google/go-cmp/cmp"
32
33 corev1 "k8s.io/api/core/v1"
34 apiextensions "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
35 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
36 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
37 "k8s.io/apimachinery/pkg/types"
38 "sigs.k8s.io/controller-runtime/pkg/client"
39 "sigs.k8s.io/controller-runtime/pkg/manager"
40 "sigs.k8s.io/controller-runtime/pkg/reconcile"
41 )
42
43 var (
44 mgr manager.Manager
45
46 fakeCRD = newTestKindCRD()
47 )
48
49 func TestReconcile_UnmanagedResource(t *testing.T) {
50 t.Parallel()
51 testID := testvariable.NewUniqueId()
52 client := mgr.GetClient()
53 testcontroller.EnsureNamespaceExistsT(t, client, k8s.SystemNamespace)
54 testcontroller.EnsureNamespaceExistsT(t, client, testID)
55
56 resourceNN := types.NamespacedName{
57 Namespace: testID,
58 Name: testID,
59 }
60 resource := newTestKindUnstructured(resourceNN)
61 test.EnsureObjectExists(t, resource, client)
62
63 reconciler, err := unmanageddetector.NewReconciler(mgr, fakeCRD)
64 if err != nil {
65 t.Fatalf("error creating reconciler: %v", err)
66 }
67 res, err := reconciler.Reconcile(context.TODO(), reconcile.Request{NamespacedName: resourceNN})
68 if err != nil {
69 t.Fatalf("unexpected error during reconciliation: %v", err)
70 }
71 emptyResult := reconcile.Result{}
72 if got, want := res, emptyResult; !reflect.DeepEqual(got, want) {
73 t.Fatalf("unexpected diff in reconcile result (-want +got): \n%v", cmp.Diff(want, got))
74 }
75
76 condition, found, err := getCurrentCondition(context.TODO(), client, resource)
77 if err != nil {
78 t.Fatalf("error getting resource's condition: %v", err)
79 }
80 if !found {
81 t.Fatalf("got nil condition for resource, want non-nil condition with reason '%v'", k8s.Unmanaged)
82 }
83 if gotReason, wantReason := condition.Reason, k8s.Unmanaged; gotReason != wantReason {
84 t.Fatalf("got condition with reason '%v' for resource, want condition with reason '%v'", gotReason, wantReason)
85 }
86 if gotStatus, wantStatus := condition.Status, corev1.ConditionFalse; gotStatus != wantStatus {
87 t.Fatalf("got condition with status '%v' for resource, want condition with status '%v'", gotStatus, wantStatus)
88 }
89 }
90
91 func TestReconcile_ManagedResource(t *testing.T) {
92 t.Parallel()
93 testID := testvariable.NewUniqueId()
94 client := mgr.GetClient()
95 testcontroller.EnsureNamespaceExistsT(t, client, k8s.SystemNamespace)
96 testcontroller.EnsureNamespaceExistsT(t, client, testID)
97
98 resourceNN := types.NamespacedName{
99 Namespace: testID,
100 Name: testID,
101 }
102 resource := newTestKindUnstructured(resourceNN)
103 test.EnsureObjectExists(t, resource, client)
104
105 controller := newControllerUnstructuredForNamespace(resourceNN.Namespace)
106 test.EnsureObjectExists(t, controller, client)
107
108 reconciler, err := unmanageddetector.NewReconciler(mgr, fakeCRD)
109 if err != nil {
110 t.Fatalf("error creating reconciler: %v", err)
111 }
112 res, err := reconciler.Reconcile(context.TODO(), reconcile.Request{NamespacedName: resourceNN})
113 if err != nil {
114 t.Fatalf("unexpected error during reconciliation: %v", err)
115 }
116 emptyResult := reconcile.Result{}
117 if got, want := res, emptyResult; !reflect.DeepEqual(got, want) {
118 t.Fatalf("unexpected diff in reconcile result (-want +got): \n%v", cmp.Diff(want, got))
119 }
120
121 condition, found, err := getCurrentCondition(context.TODO(), client, resource)
122 if err != nil {
123 t.Fatalf("error getting resource's condition: %v", err)
124 }
125 if found {
126 t.Fatalf("got non-nil condition '%v' for resource, want nil condition", condition)
127 }
128 }
129
130 func newTestKindCRD() *apiextensions.CustomResourceDefinition {
131 crd := test.CRDForGVK(metav1.GroupVersionKind{
132 Group: "test.cnrm.cloud.google.com",
133 Version: "v1beta1",
134 Kind: "TestKind",
135 })
136
137
138
139 crd.Spec.Versions[0].Subresources = &apiextensions.CustomResourceSubresources{
140 Status: &apiextensions.CustomResourceSubresourceStatus{},
141 }
142 return crd
143 }
144
145 func newTestKindUnstructured(nn types.NamespacedName) *unstructured.Unstructured {
146 return &unstructured.Unstructured{
147 Object: map[string]interface{}{
148 "apiVersion": fmt.Sprintf("%v/%v", fakeCRD.Spec.Group, k8s.GetVersionFromCRD(fakeCRD)),
149 "kind": fakeCRD.Spec.Names.Kind,
150 "metadata": map[string]interface{}{
151 "namespace": nn.Namespace,
152 "name": nn.Name,
153 },
154 },
155 }
156 }
157
158 func newControllerUnstructuredForNamespace(namespace string) *unstructured.Unstructured {
159 controllerName := fmt.Sprintf("%v-%v", k8s.ControllerManagerNamePrefix, randomid.New().String())
160 return &unstructured.Unstructured{
161 Object: map[string]interface{}{
162 "apiVersion": "apps/v1",
163 "kind": "StatefulSet",
164 "metadata": map[string]interface{}{
165 "labels": map[string]interface{}{
166 k8s.KCCComponentLabel: k8s.ControllerManagerNamePrefix,
167 k8s.ScopedNamespaceLabel: namespace,
168 },
169 "namespace": k8s.SystemNamespace,
170 "name": controllerName,
171 },
172 "spec": map[string]interface{}{
173 "selector": map[string]interface{}{
174 "matchLabels": map[string]interface{}{
175 k8s.KCCComponentLabel: k8s.ControllerManagerNamePrefix,
176 k8s.ScopedNamespaceLabel: namespace,
177 },
178 },
179 "serviceName": controllerName,
180 "template": map[string]interface{}{
181 "metadata": map[string]interface{}{
182 "labels": map[string]interface{}{
183 k8s.KCCComponentLabel: k8s.ControllerManagerNamePrefix,
184 k8s.ScopedNamespaceLabel: namespace,
185 },
186 },
187 },
188 },
189 },
190 }
191 }
192
193 func getCurrentCondition(ctx context.Context, c client.Client, u *unstructured.Unstructured) (condition v1alpha1.Condition, found bool, err error) {
194 nn := k8s.GetNamespacedName(u)
195 unstruct := &unstructured.Unstructured{}
196 unstruct.SetGroupVersionKind(u.GroupVersionKind())
197 if err := c.Get(ctx, nn, unstruct); err != nil {
198 return v1alpha1.Condition{}, false, fmt.Errorf("error getting resource from API server: %v", err)
199 }
200 resource, err := k8s.NewResource(unstruct)
201 if err != nil {
202 return v1alpha1.Condition{}, false, fmt.Errorf("error marhsalling unstruct to k8s resource: %v", err)
203 }
204 condition, found = k8s.GetReadyCondition(resource)
205 return condition, found, nil
206 }
207
208 func TestMain(m *testing.M) {
209 testmain.TestMainForUnitTestsWithCRDs(m, []*apiextensions.CustomResourceDefinition{fakeCRD}, &mgr)
210 }
211
View as plain text