Skip to content

Commit

Permalink
Add controllers tests for real Reconcile loop running with setup-envtest
Browse files Browse the repository at this point in the history
  • Loading branch information
dmvolod committed Feb 8, 2024
1 parent 338306a commit 2e79336
Show file tree
Hide file tree
Showing 16 changed files with 1,803 additions and 215 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
*.dylib
bin
testbin/*
vendor

# Test binary, build with `go test -c`
*.test
Expand Down
14 changes: 11 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export GO111MODULE=on
#
# Kubebuilder.
#
export KUBEBUILDER_ENVTEST_KUBERNETES_VERSION ?= 1.26.0
export KUBEBUILDER_ENVTEST_KUBERNETES_VERSION ?= 1.27.1
export KUBEBUILDER_CONTROLPLANE_START_TIMEOUT ?= 60s
export KUBEBUILDER_CONTROLPLANE_STOP_TIMEOUT ?= 60s

Expand Down Expand Up @@ -93,7 +93,7 @@ _SKIP_ARGS := $(foreach arg,$(strip $(GINKGO_SKIP)),-skip="$(arg)")
endif

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

#
# Binaries.
Expand All @@ -104,7 +104,10 @@ KUSTOMIZE_BIN := kustomize
KUSTOMIZE := $(abspath $(TOOLS_BIN_DIR)/$(KUSTOMIZE_BIN)-$(KUSTOMIZE_VER))
KUSTOMIZE_PKG := sigs.k8s.io/kustomize/kustomize/v4

MOCKGEN_VER := v0.2.0
CLUSTER_API_VERSION := $(call get_go_version,sigs.k8s.io/cluster-api)
CLUSTER_API_CRD_LOCATION = test/controllers/data/crd

MOCKGEN_VER := v0.4.0
MOCKGEN_BIN := mockgen
MOCKGEN := $(TOOLS_BIN_DIR)/$(MOCKGEN_BIN)-$(MOCKGEN_VER)

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

.PHONY: download-cluster-api-crd
download-cluster-api-crd: generate-modules ## Run to download Cluster API CRDs for tests
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)
chmod 644 $(CLUSTER_API_CRD_LOCATION)/*

DOCKER_TEMPLATES := test/e2e/data/addons-helm

.PHONY: generate-e2e-templates
Expand Down
170 changes: 170 additions & 0 deletions controllers/controllers_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
/*
Copyright 2023 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 controllers_test

import (
"time"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
helmrelease "helm.sh/helm/v3/pkg/release"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/utils/ptr"
addonsv1alpha1 "sigs.k8s.io/cluster-api-addon-provider-helm/api/v1alpha1"
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
"sigs.k8s.io/cluster-api/util/conditions"
"sigs.k8s.io/controller-runtime/pkg/client"
)

var (
testNamespace = "test-namespace"
kubeconfig = "test-kubeconfig"
newVersion = "new-version"

defaultProxy = &addonsv1alpha1.HelmChartProxy{
TypeMeta: metav1.TypeMeta{
APIVersion: addonsv1alpha1.GroupVersion.String(),
Kind: "HelmChartProxy",
},
ObjectMeta: metav1.ObjectMeta{
Name: "test-hcp",
Namespace: testNamespace,
},
Spec: addonsv1alpha1.HelmChartProxySpec{
ClusterSelector: metav1.LabelSelector{
MatchLabels: map[string]string{
"test-label": "test-value",
},
},
ReleaseName: "test-release-name",
ChartName: "test-chart-name",
RepoURL: "https://test-repo-url",
ReleaseNamespace: "test-release-namespace",
Version: "test-version",
ValuesTemplate: "apiServerPort: {{ .Cluster.spec.clusterNetwork.apiServerPort }}",
},
}

cluster1 = &clusterv1.Cluster{
TypeMeta: metav1.TypeMeta{
APIVersion: clusterv1.GroupVersion.String(),
Kind: "Cluster",
},
ObjectMeta: metav1.ObjectMeta{
Name: "test-cluster-1",
Namespace: testNamespace,
Labels: map[string]string{
"test-label": "test-value",
},
},
Spec: clusterv1.ClusterSpec{
ClusterNetwork: &clusterv1.ClusterNetwork{
APIServerPort: ptr.To(int32(1234)),
},
},
}

helmReleaseDeployed = &helmrelease.Release{
Name: "test-release",
Version: 1,
Info: &helmrelease.Info{
Status: helmrelease.StatusDeployed,
},
}
)

var _ = Describe("Testing HelmChartProxy and HelmReleaseProxy reconcile", func() {
var (
waitForHelmChartProxyCondition = func(objectKey client.ObjectKey, condition func(helmChartProxy *addonsv1alpha1.HelmChartProxy) bool) {
hcp := &addonsv1alpha1.HelmChartProxy{}
Eventually(func() bool {
if err := k8sClient.Get(ctx, objectKey, hcp); err != nil {
return false
}

return condition != nil && condition(hcp)
}, timeout, interval).Should(BeTrue())
}

waitForHelmReleaseProxyCondition = func(helmChartProxyKey client.ObjectKey, condition func(helmReleaseProxyList []addonsv1alpha1.HelmReleaseProxy) bool) {
hrpList := &addonsv1alpha1.HelmReleaseProxyList{}
Eventually(func() bool {
if err := k8sClient.List(ctx, hrpList, client.InNamespace(helmChartProxyKey.Namespace), client.MatchingLabels(map[string]string{addonsv1alpha1.HelmChartProxyLabelName: helmChartProxyKey.Name})); err != nil {
return false
}

return condition != nil && condition(hrpList.Items)
}, timeout, interval).Should(BeTrue())
}
)

It("HelmChartProxy and HelmReleaseProxy lifecycle test", func() {
cluster := cluster1.DeepCopy()
err := k8sClient.Create(ctx, cluster)
Expect(err).ToNot(HaveOccurred())

patch := client.MergeFrom(cluster.DeepCopy())
cluster.Status.Conditions = clusterv1.Conditions{
{
Type: clusterv1.ControlPlaneInitializedCondition,
Status: corev1.ConditionTrue,
LastTransitionTime: metav1.NewTime(time.Now()),
},
}
err = k8sClient.Status().Patch(ctx, cluster, patch)
Expect(err).ToNot(HaveOccurred())

err = k8sClient.Create(ctx, defaultProxy)
Expect(err).ToNot(HaveOccurred())

waitForHelmChartProxyCondition(client.ObjectKeyFromObject(defaultProxy), func(helmChartProxy *addonsv1alpha1.HelmChartProxy) bool {
return conditions.IsTrue(helmChartProxy, clusterv1.ReadyCondition)
})

waitForHelmReleaseProxyCondition(client.ObjectKeyFromObject(defaultProxy), func(helmReleaseProxyList []addonsv1alpha1.HelmReleaseProxy) bool {
return len(helmReleaseProxyList) == 1 && conditions.IsTrue(&helmReleaseProxyList[0], clusterv1.ReadyCondition)
})

hcp := &addonsv1alpha1.HelmChartProxy{}
err = k8sClient.Get(ctx, client.ObjectKeyFromObject(defaultProxy), hcp)
Expect(err).ToNot(HaveOccurred())
patch = client.MergeFrom(hcp.DeepCopy())
hcp.Spec.Version = newVersion
err = k8sClient.Patch(ctx, hcp, patch)
Expect(err).ToNot(HaveOccurred())

waitForHelmReleaseProxyCondition(client.ObjectKeyFromObject(defaultProxy), func(helmReleaseProxyList []addonsv1alpha1.HelmReleaseProxy) bool {
return len(helmReleaseProxyList) == 1 && conditions.IsTrue(&helmReleaseProxyList[0], clusterv1.ReadyCondition) && helmReleaseProxyList[0].Spec.Version == "new-version"
})

err = k8sClient.Delete(ctx, hcp)
Expect(err).ToNot(HaveOccurred())

Eventually(func() bool {
if err := k8sClient.Get(ctx, client.ObjectKeyFromObject(hcp), hcp); client.IgnoreNotFound(err) != nil {
return false
}

return true
}, timeout, interval).Should(BeTrue())

waitForHelmReleaseProxyCondition(client.ObjectKeyFromObject(defaultProxy), func(helmReleaseProxyList []addonsv1alpha1.HelmReleaseProxy) bool {
return len(helmReleaseProxyList) == 0
})
})
})
12 changes: 12 additions & 0 deletions controllers/helmchartproxy/helmchartproxy_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,14 @@ import (
. "github.com/onsi/gomega"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/kubernetes/scheme"
"k8s.io/utils/ptr"
addonsv1alpha1 "sigs.k8s.io/cluster-api-addon-provider-helm/api/v1alpha1"
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
"sigs.k8s.io/cluster-api/util"
"sigs.k8s.io/cluster-api/util/conditions"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/client/fake"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
Expand All @@ -35,6 +38,9 @@ import (
var _ reconcile.Reconciler = &HelmChartProxyReconciler{}

var (
ctx = ctrl.SetupSignalHandler()
fakeScheme = runtime.NewScheme()

defaultProxy = &addonsv1alpha1.HelmChartProxy{
TypeMeta: metav1.TypeMeta{
APIVersion: addonsv1alpha1.GroupVersion.String(),
Expand Down Expand Up @@ -346,3 +352,9 @@ func TestReconcileNormal(t *testing.T) {
})
}
}

func init() {
_ = scheme.AddToScheme(fakeScheme)
_ = clusterv1.AddToScheme(fakeScheme)
_ = addonsv1alpha1.AddToScheme(fakeScheme)
}
88 changes: 0 additions & 88 deletions controllers/helmchartproxy/suite_test.go

This file was deleted.

Loading

0 comments on commit 2e79336

Please sign in to comment.