Skip to content

Commit 2ab4e1a

Browse files
authored
Merge pull request #150 from dmvolod/issue-146-integration-tests
✨ Add controllers tests for real Reconcile loop running with setup-envtest
2 parents c3a07aa + 2e79336 commit 2ab4e1a

File tree

16 files changed

+1803
-215
lines changed

16 files changed

+1803
-215
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
*.dylib
88
bin
99
testbin/*
10+
vendor
1011

1112
# Test binary, build with `go test -c`
1213
*.test

Makefile

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ export GO111MODULE=on
3939
#
4040
# Kubebuilder.
4141
#
42-
export KUBEBUILDER_ENVTEST_KUBERNETES_VERSION ?= 1.26.0
42+
export KUBEBUILDER_ENVTEST_KUBERNETES_VERSION ?= 1.27.1
4343
export KUBEBUILDER_CONTROLPLANE_START_TIMEOUT ?= 60s
4444
export KUBEBUILDER_CONTROLPLANE_STOP_TIMEOUT ?= 60s
4545

@@ -93,7 +93,7 @@ _SKIP_ARGS := $(foreach arg,$(strip $(GINKGO_SKIP)),-skip="$(arg)")
9393
endif
9494

9595
# Helper function to get dependency version from go.mod
96-
get_go_version = $(shell go list -m $1 | awk '{print $$2}')
96+
get_go_version = $(shell go list -f "{{.Version}}" -m $1)
9797

9898
#
9999
# Binaries.
@@ -104,7 +104,10 @@ KUSTOMIZE_BIN := kustomize
104104
KUSTOMIZE := $(abspath $(TOOLS_BIN_DIR)/$(KUSTOMIZE_BIN)-$(KUSTOMIZE_VER))
105105
KUSTOMIZE_PKG := sigs.k8s.io/kustomize/kustomize/v4
106106

107-
MOCKGEN_VER := v0.2.0
107+
CLUSTER_API_VERSION := $(call get_go_version,sigs.k8s.io/cluster-api)
108+
CLUSTER_API_CRD_LOCATION = test/controllers/data/crd
109+
110+
MOCKGEN_VER := v0.4.0
108111
MOCKGEN_BIN := mockgen
109112
MOCKGEN := $(TOOLS_BIN_DIR)/$(MOCKGEN_BIN)-$(MOCKGEN_VER)
110113

@@ -264,6 +267,11 @@ generate-modules: ## Run go mod tidy to ensure modules are up to date
264267
go mod tidy
265268
cd $(TOOLS_DIR); go mod tidy
266269

270+
.PHONY: download-cluster-api-crd
271+
download-cluster-api-crd: generate-modules ## Run to download Cluster API CRDs for tests
272+
cp -r $(shell go env GOPATH)/pkg/mod/sigs.k8s.io/cluster-api@$(CLUSTER_API_VERSION)/config/crd/bases/cluster.x-k8s.io_clusters.yaml $(CLUSTER_API_CRD_LOCATION)
273+
chmod 644 $(CLUSTER_API_CRD_LOCATION)/*
274+
267275
DOCKER_TEMPLATES := test/e2e/data/addons-helm
268276

269277
.PHONY: generate-e2e-templates

controllers/controllers_test.go

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
/*
2+
Copyright 2023 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package controllers_test
18+
19+
import (
20+
"time"
21+
22+
. "github.com/onsi/ginkgo/v2"
23+
. "github.com/onsi/gomega"
24+
helmrelease "helm.sh/helm/v3/pkg/release"
25+
corev1 "k8s.io/api/core/v1"
26+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
27+
"k8s.io/utils/ptr"
28+
addonsv1alpha1 "sigs.k8s.io/cluster-api-addon-provider-helm/api/v1alpha1"
29+
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
30+
"sigs.k8s.io/cluster-api/util/conditions"
31+
"sigs.k8s.io/controller-runtime/pkg/client"
32+
)
33+
34+
var (
35+
testNamespace = "test-namespace"
36+
kubeconfig = "test-kubeconfig"
37+
newVersion = "new-version"
38+
39+
defaultProxy = &addonsv1alpha1.HelmChartProxy{
40+
TypeMeta: metav1.TypeMeta{
41+
APIVersion: addonsv1alpha1.GroupVersion.String(),
42+
Kind: "HelmChartProxy",
43+
},
44+
ObjectMeta: metav1.ObjectMeta{
45+
Name: "test-hcp",
46+
Namespace: testNamespace,
47+
},
48+
Spec: addonsv1alpha1.HelmChartProxySpec{
49+
ClusterSelector: metav1.LabelSelector{
50+
MatchLabels: map[string]string{
51+
"test-label": "test-value",
52+
},
53+
},
54+
ReleaseName: "test-release-name",
55+
ChartName: "test-chart-name",
56+
RepoURL: "https://test-repo-url",
57+
ReleaseNamespace: "test-release-namespace",
58+
Version: "test-version",
59+
ValuesTemplate: "apiServerPort: {{ .Cluster.spec.clusterNetwork.apiServerPort }}",
60+
},
61+
}
62+
63+
cluster1 = &clusterv1.Cluster{
64+
TypeMeta: metav1.TypeMeta{
65+
APIVersion: clusterv1.GroupVersion.String(),
66+
Kind: "Cluster",
67+
},
68+
ObjectMeta: metav1.ObjectMeta{
69+
Name: "test-cluster-1",
70+
Namespace: testNamespace,
71+
Labels: map[string]string{
72+
"test-label": "test-value",
73+
},
74+
},
75+
Spec: clusterv1.ClusterSpec{
76+
ClusterNetwork: &clusterv1.ClusterNetwork{
77+
APIServerPort: ptr.To(int32(1234)),
78+
},
79+
},
80+
}
81+
82+
helmReleaseDeployed = &helmrelease.Release{
83+
Name: "test-release",
84+
Version: 1,
85+
Info: &helmrelease.Info{
86+
Status: helmrelease.StatusDeployed,
87+
},
88+
}
89+
)
90+
91+
var _ = Describe("Testing HelmChartProxy and HelmReleaseProxy reconcile", func() {
92+
var (
93+
waitForHelmChartProxyCondition = func(objectKey client.ObjectKey, condition func(helmChartProxy *addonsv1alpha1.HelmChartProxy) bool) {
94+
hcp := &addonsv1alpha1.HelmChartProxy{}
95+
Eventually(func() bool {
96+
if err := k8sClient.Get(ctx, objectKey, hcp); err != nil {
97+
return false
98+
}
99+
100+
return condition != nil && condition(hcp)
101+
}, timeout, interval).Should(BeTrue())
102+
}
103+
104+
waitForHelmReleaseProxyCondition = func(helmChartProxyKey client.ObjectKey, condition func(helmReleaseProxyList []addonsv1alpha1.HelmReleaseProxy) bool) {
105+
hrpList := &addonsv1alpha1.HelmReleaseProxyList{}
106+
Eventually(func() bool {
107+
if err := k8sClient.List(ctx, hrpList, client.InNamespace(helmChartProxyKey.Namespace), client.MatchingLabels(map[string]string{addonsv1alpha1.HelmChartProxyLabelName: helmChartProxyKey.Name})); err != nil {
108+
return false
109+
}
110+
111+
return condition != nil && condition(hrpList.Items)
112+
}, timeout, interval).Should(BeTrue())
113+
}
114+
)
115+
116+
It("HelmChartProxy and HelmReleaseProxy lifecycle test", func() {
117+
cluster := cluster1.DeepCopy()
118+
err := k8sClient.Create(ctx, cluster)
119+
Expect(err).ToNot(HaveOccurred())
120+
121+
patch := client.MergeFrom(cluster.DeepCopy())
122+
cluster.Status.Conditions = clusterv1.Conditions{
123+
{
124+
Type: clusterv1.ControlPlaneInitializedCondition,
125+
Status: corev1.ConditionTrue,
126+
LastTransitionTime: metav1.NewTime(time.Now()),
127+
},
128+
}
129+
err = k8sClient.Status().Patch(ctx, cluster, patch)
130+
Expect(err).ToNot(HaveOccurred())
131+
132+
err = k8sClient.Create(ctx, defaultProxy)
133+
Expect(err).ToNot(HaveOccurred())
134+
135+
waitForHelmChartProxyCondition(client.ObjectKeyFromObject(defaultProxy), func(helmChartProxy *addonsv1alpha1.HelmChartProxy) bool {
136+
return conditions.IsTrue(helmChartProxy, clusterv1.ReadyCondition)
137+
})
138+
139+
waitForHelmReleaseProxyCondition(client.ObjectKeyFromObject(defaultProxy), func(helmReleaseProxyList []addonsv1alpha1.HelmReleaseProxy) bool {
140+
return len(helmReleaseProxyList) == 1 && conditions.IsTrue(&helmReleaseProxyList[0], clusterv1.ReadyCondition)
141+
})
142+
143+
hcp := &addonsv1alpha1.HelmChartProxy{}
144+
err = k8sClient.Get(ctx, client.ObjectKeyFromObject(defaultProxy), hcp)
145+
Expect(err).ToNot(HaveOccurred())
146+
patch = client.MergeFrom(hcp.DeepCopy())
147+
hcp.Spec.Version = newVersion
148+
err = k8sClient.Patch(ctx, hcp, patch)
149+
Expect(err).ToNot(HaveOccurred())
150+
151+
waitForHelmReleaseProxyCondition(client.ObjectKeyFromObject(defaultProxy), func(helmReleaseProxyList []addonsv1alpha1.HelmReleaseProxy) bool {
152+
return len(helmReleaseProxyList) == 1 && conditions.IsTrue(&helmReleaseProxyList[0], clusterv1.ReadyCondition) && helmReleaseProxyList[0].Spec.Version == "new-version"
153+
})
154+
155+
err = k8sClient.Delete(ctx, hcp)
156+
Expect(err).ToNot(HaveOccurred())
157+
158+
Eventually(func() bool {
159+
if err := k8sClient.Get(ctx, client.ObjectKeyFromObject(hcp), hcp); client.IgnoreNotFound(err) != nil {
160+
return false
161+
}
162+
163+
return true
164+
}, timeout, interval).Should(BeTrue())
165+
166+
waitForHelmReleaseProxyCondition(client.ObjectKeyFromObject(defaultProxy), func(helmReleaseProxyList []addonsv1alpha1.HelmReleaseProxy) bool {
167+
return len(helmReleaseProxyList) == 0
168+
})
169+
})
170+
})

controllers/helmchartproxy/helmchartproxy_controller_test.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,14 @@ import (
2222
. "github.com/onsi/gomega"
2323
corev1 "k8s.io/api/core/v1"
2424
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
25+
"k8s.io/apimachinery/pkg/runtime"
26+
"k8s.io/client-go/kubernetes/scheme"
2527
"k8s.io/utils/ptr"
2628
addonsv1alpha1 "sigs.k8s.io/cluster-api-addon-provider-helm/api/v1alpha1"
2729
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
2830
"sigs.k8s.io/cluster-api/util"
2931
"sigs.k8s.io/cluster-api/util/conditions"
32+
ctrl "sigs.k8s.io/controller-runtime"
3033
"sigs.k8s.io/controller-runtime/pkg/client"
3134
"sigs.k8s.io/controller-runtime/pkg/client/fake"
3235
"sigs.k8s.io/controller-runtime/pkg/reconcile"
@@ -35,6 +38,9 @@ import (
3538
var _ reconcile.Reconciler = &HelmChartProxyReconciler{}
3639

3740
var (
41+
ctx = ctrl.SetupSignalHandler()
42+
fakeScheme = runtime.NewScheme()
43+
3844
defaultProxy = &addonsv1alpha1.HelmChartProxy{
3945
TypeMeta: metav1.TypeMeta{
4046
APIVersion: addonsv1alpha1.GroupVersion.String(),
@@ -346,3 +352,9 @@ func TestReconcileNormal(t *testing.T) {
346352
})
347353
}
348354
}
355+
356+
func init() {
357+
_ = scheme.AddToScheme(fakeScheme)
358+
_ = clusterv1.AddToScheme(fakeScheme)
359+
_ = addonsv1alpha1.AddToScheme(fakeScheme)
360+
}

controllers/helmchartproxy/suite_test.go

Lines changed: 0 additions & 88 deletions
This file was deleted.

0 commit comments

Comments
 (0)