Skip to content

Commit 328000c

Browse files
authored
Run kind e2e test (#37)
* Run kind e2e test Signed-off-by: Karol Szwaj <karol.szwaj@gmail.com> On-behalf-of: @SAP karol.szwaj@sap.com * clean up makefile Signed-off-by: Karol Szwaj <karol.szwaj@gmail.com> On-behalf-of: @SAP karol.szwaj@sap.com
1 parent 59d3ce2 commit 328000c

7 files changed

Lines changed: 83 additions & 81 deletions

File tree

.github/workflows/e2e.yaml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,5 @@ jobs:
2727
uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6
2828
with:
2929
go-version-file: go.mod
30-
# TODO: uncomment and fix e2e tests
31-
# - name: Run e2e tests
32-
# run: make kind-test test-e2e
30+
- name: Run e2e tests
31+
run: make kind-test-e2e

Makefile

Lines changed: 32 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
GO ?= go
22
KUBECTL ?= kubectl
3+
KIND ?= kind
4+
HELM ?= helm
35
KUSTOMIZE ?= $(GO) tool kustomize
46
CONTROLLER_GEN ?= $(GO) tool controller-gen
57
API_GEN ?= $(GO) tool apigen
@@ -87,7 +89,7 @@ TEST_NAME ?=
8789

8890
.PHONY: test-e2e
8991
test-e2e: manifests generate fmt vet ## Run e2e tests. Optionally specify TEST_NAME=<test_name> to run a specific test.
90-
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) -p path)" go test ./test/... -v -timeout 30m $(if $(TEST_NAME),-run "^$(TEST_NAME)$$")
92+
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) -p path)" SETUP_CLUSTER=true IMG=$(IMG) go test ./test/... -v -timeout 30m $(if $(TEST_NAME),-run "^$(TEST_NAME)$$")
9193

9294
.PHONY: lint
9395
lint: ## Run golangci-lint linter
@@ -126,7 +128,7 @@ docker-build: manifests generate fmt vet ## Build docker image with the manager.
126128
KIND_CLUSTER ?= kind
127129

128130
docker-install: docker-build
129-
kind load docker-image $(IMG) --name $(KIND_CLUSTER)
131+
$(KIND) load docker-image $(IMG) --name $(KIND_CLUSTER)
130132

131133
.PHONY: build-installer
132134
build-installer: manifests generate kustomize ## Generate a consolidated YAML with CRDs and deployment.
@@ -166,14 +168,14 @@ print-helm-version:
166168
.PHONY: chart-push
167169
chart-push: ## Push Helm chart to GHCR (after pushing multi-arch container image)
168170
@echo "Pushing Helm chart to $(REGISTRY)..."
169-
helm push dist/example-httpbin-operator-$(CHART_VERSION).tgz oci://$(REGISTRY)/charts
170-
helm push dist/example-httpbin-operator-crds-$(CHART_VERSION).tgz oci://$(REGISTRY)/charts
171+
$(HELM) push dist/example-httpbin-operator-$(CHART_VERSION).tgz oci://$(REGISTRY)/charts
172+
$(HELM) push dist/example-httpbin-operator-crds-$(CHART_VERSION).tgz oci://$(REGISTRY)/charts
171173

172174
.PHONY: charts
173175
charts: manifests generate ## Generate and package Helm chart with multi-arch image support. Always runs manifests first to ensure CRDs are up to date
174-
helm dependency update charts/example-httpbin-operator
176+
$(HELM) dependency update charts/example-httpbin-operator
175177
mkdir -p dist
176-
helm package charts/example-httpbin-operator -d dist
178+
$(HELM) package charts/example-httpbin-operator -d dist
177179

178180
## OCM
179181

@@ -188,40 +190,44 @@ print-ocm-version: ## Print the OCM version
188190
.PHONY: kind-test
189191
kind-test: kind-test-cleanup docker-build charts ## Create kind cluster, load image, and deploy helm chart
190192
@echo "Creating kind cluster..."
191-
kind create cluster --name example-httpbin-operator
192-
kind get kubeconfig --name example-httpbin-operator > msp.kubeconfig.yaml
193+
$(KIND) create cluster --name example-httpbin-operator
194+
$(KIND) get kubeconfig --name example-httpbin-operator > msp.kubeconfig.yaml
193195
@echo "Loading operator image into kind..."
194-
kind load docker-image ${IMG} --name example-httpbin-operator
196+
$(KIND) load docker-image ${IMG} --name example-httpbin-operator
195197
@echo "Installing helm chart..."
196-
helm install example-httpbin-operator dist/example-httpbin-operator-0.0.0.tgz \
198+
$(HELM) install example-httpbin-operator dist/example-httpbin-operator-0.0.0.tgz \
199+
--namespace example-httpbin-operator-system \
200+
--set image.tag=$(DOCKER_VERSION) \
197201
--create-namespace \
198202
--force
199203
@echo "Waiting for operator deployment..."
200-
kubectl wait --for=condition=available deployment/example-httpbin-operator --timeout=60s
204+
$(KUBECTL) wait --for=condition=available deployment/example-httpbin-operator --namespace example-httpbin-operator-system --timeout=60s
201205
@echo "Deployment status:"
202-
kubectl get deployment example-httpbin-operator
206+
$(KUBECTL) get deployment example-httpbin-operator --namespace example-httpbin-operator-system
203207
@echo "CRD status:"
204-
kubectl get crds | grep httpbin
208+
$(KUBECTL) get crds -n example-httpbin-operator-system | grep httpbin
205209

206210
.PHONY: kind-test-cleanup
207211
kind-test-cleanup: ## Delete the kind test cluster
208212
@echo "Deleting kind cluster..."
209-
@kind delete cluster --name example-httpbin-operator 2>/dev/null || true
210-
@kind delete cluster --name example-httpbin-operator-crds 2>/dev/null || true
213+
@$(KIND) delete cluster --name example-httpbin-operator 2>/dev/null || true
214+
@$(KIND) delete cluster --name example-httpbin-operator-crds 2>/dev/null || true
211215

212216
.PHONY: kind-test-crds
213-
kind-test-crds: charts ## Create kind cluster and deploy helm chart CRDs only
217+
kind-test-crds: ## Create kind cluster and deploy CRDs only
214218
@echo "Creating kind cluster..."
215-
kind create cluster --name example-httpbin-operator-crds
216-
kind get kubeconfig --name example-httpbin-operator-crds > msp-cp.kubeconfig.yaml
217-
@echo "Installing helm chart CRDs only..."
218-
helm install example-httpbin-operator dist/example-httpbin-operator-crds-0.0.0.tgz
219+
$(KIND) create cluster --name example-httpbin-operator-crds
220+
$(KIND) get kubeconfig --name example-httpbin-operator-crds > msp-cp.kubeconfig.yaml
221+
@echo "Installing CRDs only..."
222+
$(KUBECTL) apply -f charts/example-httpbin-operator/crds/
219223
@echo "CRD status:"
220-
kubectl get crds | grep httpbin
224+
$(KUBECTL) get crds | grep httpbin
221225

222226
.PHONY: kind-test-sample
223-
kind-test-sample: ## Deploy a sample httpbin deployment to test the operator
224-
@echo "Creating sample httpbin deployment..."
225-
kubectl apply -f config/samples/orchestrate_v1alpha1_httpbindeployment.yaml
226-
@echo "Waiting for deployment to be ready..."
227-
kubectl wait --for=condition=available --timeout=60s deployment -l app=httpbin
227+
kind-test-sample: ## Deploy a sample httpbin to test the operator
228+
@echo "Creating sample httpbin..."
229+
$(KUBECTL) apply -f examples/httpbin.yaml
230+
231+
.PHONY: kind-test-e2e
232+
kind-test-e2e: kind-test
233+
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) -p path)" IMG=$(IMG) go test ./test/... -v -timeout 30m $(if $(TEST_NAME),-run "^$(TEST_NAME)$$")

config/manager/kustomization.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@ apiVersion: kustomize.config.k8s.io/v1beta1
44
kind: Kustomization
55
images:
66
- name: controller
7-
newName: controller
8-
newTag: dev
7+
newName: ghcr.io/platform-mesh/example-httpbin-operator
8+
newTag: 5c05354-dirty

test/common.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ import (
1414
)
1515

1616
const (
17-
// OperatorImage is the image name for the operator
18-
OperatorImage = "controller:dev"
17+
// DefaultOperatorImage is the image name for the operator
18+
DefaultOperatorImage = "controller:dev"
1919
// OperatorName is the name of the operator
2020
OperatorName = "example-httpbin-operator"
2121
// OperatorNs is the namespace where the operator is deployed

test/deployment_test.go

Lines changed: 17 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -54,38 +54,32 @@ func TestHttpBinDeploymentOperator(t *testing.T) {
5454
}
5555

5656
// Wait for Deployment to be created and available
57-
deployment := &appsv1.Deployment{
58-
ObjectMeta: metav1.ObjectMeta{
59-
Name: "test-httpbin-deployment",
60-
Namespace: "default",
61-
},
57+
deployment := &appsv1.Deployment{}
58+
deploymentNamespacedName := types.NamespacedName{
59+
Name: "httpbin-test-httpbin-deployment",
60+
Namespace: "default",
6261
}
6362

64-
if err := wait.For(conditions.New(cfg.Client().Resources()).DeploymentConditionMatch(deployment, appsv1.DeploymentAvailable, corev1.ConditionTrue),
63+
if err := wait.For(func(ctx context.Context) (done bool, err error) {
64+
err = k8sClient.Get(ctx, deploymentNamespacedName, deployment)
65+
return err == nil, nil
66+
},
6567
wait.WithTimeout(DefaultTimeout),
6668
wait.WithInterval(DefaultInterval)); err != nil {
67-
t.Fatalf("failed waiting for Deployment to be available: %v", err)
69+
t.Fatalf("failed waiting for Deployment: %v", err)
6870
}
6971

70-
// Get the deployment to verify ownership
71-
if err := k8sClient.Get(ctx, types.NamespacedName{Name: deployment.Name, Namespace: deployment.Namespace}, deployment); err != nil {
72-
t.Fatalf("failed to get deployment: %v", err)
73-
}
74-
75-
// Verify Deployment ownership
76-
if len(deployment.OwnerReferences) != 1 {
77-
t.Fatalf("expected 1 owner reference for Deployment, got %d", len(deployment.OwnerReferences))
78-
}
79-
owner := deployment.OwnerReferences[0]
80-
if owner.Name != httpbinDeployment.Name || owner.Kind != "HttpBinDeployment" {
81-
t.Errorf("incorrect owner reference for Deployment: got name=%s kind=%s, want name=%s kind=HttpBinDeployment",
82-
owner.Name, owner.Kind, httpbinDeployment.Name)
72+
// Now wait for Deployment to be available
73+
if err := wait.For(conditions.New(cfg.Client().Resources()).DeploymentConditionMatch(deployment, appsv1.DeploymentAvailable, corev1.ConditionTrue),
74+
wait.WithTimeout(DefaultTimeout),
75+
wait.WithInterval(DefaultInterval)); err != nil {
76+
t.Fatalf("failed waiting for Deployment to be available: %v", err)
8377
}
8478

8579
// Wait for Service to be created
8680
service := &corev1.Service{}
8781
serviceNamespacedName := types.NamespacedName{
88-
Name: "test-httpbin-deployment",
82+
Name: "httpbin-test-httpbin-deployment",
8983
Namespace: "default",
9084
}
9185

@@ -98,16 +92,6 @@ func TestHttpBinDeploymentOperator(t *testing.T) {
9892
t.Fatalf("failed waiting for Service: %v", err)
9993
}
10094

101-
// Verify Service ownership
102-
if len(service.OwnerReferences) != 1 {
103-
t.Fatalf("expected 1 owner reference for Service, got %d", len(service.OwnerReferences))
104-
}
105-
serviceOwner := service.OwnerReferences[0]
106-
if serviceOwner.Name != httpbinDeployment.Name || serviceOwner.Kind != "HttpBinDeployment" {
107-
t.Errorf("incorrect owner reference for Service: got name=%s kind=%s, want name=%s kind=HttpBinDeployment",
108-
serviceOwner.Name, serviceOwner.Kind, httpbinDeployment.Name)
109-
}
110-
11195
return ctx
11296
}).
11397
Assess("Delete HttpBinDeployment resource", func(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context {
@@ -127,7 +111,7 @@ func TestHttpBinDeploymentOperator(t *testing.T) {
127111
// Wait for Deployment to be deleted
128112
deployment := &appsv1.Deployment{}
129113
namespacedName := types.NamespacedName{
130-
Name: "test-httpbin-deployment",
114+
Name: "httpbin-test-httpbin-deployment",
131115
Namespace: "default",
132116
}
133117

@@ -143,7 +127,7 @@ func TestHttpBinDeploymentOperator(t *testing.T) {
143127
// Wait for Service to be deleted
144128
service := &corev1.Service{}
145129
serviceNamespacedName := types.NamespacedName{
146-
Name: "test-httpbin-deployment",
130+
Name: "httpbin-test-httpbin-deployment",
147131
Namespace: "default",
148132
}
149133

test/main_test.go

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ import (
3434
"sigs.k8s.io/e2e-framework/support/kind"
3535
)
3636

37-
func setupOperator(ctx context.Context, cfg *envconf.Config) error {
37+
func setupOperator(ctx context.Context, cfg *envconf.Config, operatorImage string) error {
3838
// Get project root directory
3939
projectRoot := filepath.Join("..", "")
4040

@@ -47,7 +47,7 @@ func setupOperator(ctx context.Context, cfg *envconf.Config) error {
4747
}
4848

4949
// Build operator image
50-
cmd = exec.Command("make", "-C", projectRoot, "docker-build", "IMG="+OperatorImage)
50+
cmd = exec.Command("make", "-C", projectRoot, "docker-build", "IMG="+operatorImage)
5151
cmd.Stdout = os.Stdout
5252
cmd.Stderr = os.Stderr
5353
if err := cmd.Run(); err != nil {
@@ -81,7 +81,7 @@ func setupOperator(ctx context.Context, cfg *envconf.Config) error {
8181
}
8282

8383
// Deploy operator
84-
cmd = exec.Command("make", "-C", projectRoot, "deploy", "IMG="+OperatorImage)
84+
cmd = exec.Command("make", "-C", projectRoot, "deploy", "IMG="+operatorImage)
8585
cmd.Stdout = os.Stdout
8686
cmd.Stderr = os.Stderr
8787
if err := cmd.Run(); err != nil {
@@ -94,18 +94,22 @@ func setupOperator(ctx context.Context, cfg *envconf.Config) error {
9494
func TestMain(m *testing.M) {
9595
// Create test environment
9696
TestEnv = env.NewWithConfig(envconf.New())
97+
operatorImage := getOperatorImage()
98+
setupCluster := os.Getenv("SETUP_CLUSTER")
9799

98100
// Setup
99-
TestEnv.Setup(
100-
envfuncs.CreateCluster(kind.NewProvider(), OperatorName),
101-
envfuncs.LoadDockerImageToCluster(OperatorName, OperatorImage),
102-
func(ctx context.Context, cfg *envconf.Config) (context.Context, error) {
103-
if err := setupOperator(ctx, cfg); err != nil {
104-
return ctx, err
105-
}
106-
return ctx, nil
107-
},
108-
)
101+
if setupCluster == "true" {
102+
TestEnv.Setup(
103+
envfuncs.CreateCluster(kind.NewProvider(), OperatorName),
104+
envfuncs.LoadDockerImageToCluster(OperatorName, operatorImage),
105+
func(ctx context.Context, cfg *envconf.Config) (context.Context, error) {
106+
if err := setupOperator(ctx, cfg, operatorImage); err != nil {
107+
return ctx, err
108+
}
109+
return ctx, nil
110+
},
111+
)
112+
}
109113

110114
// Run test suite
111115
testResult := TestEnv.Run(m)
@@ -122,3 +126,12 @@ func TestMain(m *testing.M) {
122126

123127
os.Exit(testResult)
124128
}
129+
130+
func getOperatorImage() string {
131+
img := os.Getenv("IMG")
132+
if img != "" {
133+
return img
134+
}
135+
// fallback to default if not set
136+
return DefaultOperatorImage
137+
}

test/test_utils.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ func setupOperatorTest(ctx context.Context, t *testing.T, cfg *envconf.Config) c
3030
// Wait for operator deployment
3131
deployment := &appsv1.Deployment{
3232
ObjectMeta: metav1.ObjectMeta{
33-
Name: OperatorName + "-controller-manager",
33+
Name: OperatorName,
3434
Namespace: OperatorNs,
3535
},
3636
}
@@ -117,7 +117,7 @@ func createHttpBinDeployment(ctx context.Context, k8sClient client.Client, t *te
117117
// Wait for Service to be created and verify it
118118
service := &corev1.Service{}
119119
serviceName := types.NamespacedName{
120-
Name: name,
120+
Name: "httpbin-" + name,
121121
Namespace: "default",
122122
}
123123

0 commit comments

Comments
 (0)