Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,32 @@ jobs:

- name: Run tests against envtest
run: make test

e2e:
permissions:
contents: read
name: E2E tests
runs-on: ubuntu-latest
steps:
- name: Clone the code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false

- name: Setup Go
uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
with:
go-version-file: go.mod

- name: Install Kind
run: go install sigs.k8s.io/kind@v0.32.0

- name: Run e2e tests against Kind
env:
# Enterprise license for the Memgraph HA cluster the suite boots,
# following the HA chart CI's repository-secret practice.
MEMGRAPH_ENTERPRISE_LICENSE: ${{ secrets.MEMGRAPH_ENTERPRISE_LICENSE }}
MEMGRAPH_ORGANIZATION_NAME: ${{ secrets.MEMGRAPH_ORGANIZATION_NAME }}
# The operator has no webhooks in v1, so the suite needs no CertManager.
CERT_MANAGER_INSTALL_SKIP: "true"
run: make test-e2e
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ go test ./api/... -run TestName
Envtest packages need `KUBEBUILDER_ASSETS`; outside of `make test` set it with:
`KUBEBUILDER_ASSETS=$(bin/setup-envtest use <k8s-version> --bin-dir bin -p path)`

CI (`.github/workflows/`) runs `make lint-config`, `make lint`, `make test-unit`, and `make test` on every PR — all must be green.
CI (`.github/workflows/`) runs `make lint-config`, `make lint`, `make test-unit`, `make test`, and `make test-e2e` on every PR — all must be green. The e2e job boots a licensed Memgraph cluster on a multi-node Kind cluster, with the license flowing from the `MEMGRAPH_ENTERPRISE_LICENSE` / `MEMGRAPH_ORGANIZATION_NAME` repository secrets (set the same env vars to run it locally).

### Toolchain quirks (do not "fix" these)

Expand Down
9 changes: 6 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,10 @@ test: manifests generate fmt vet setup-envtest ## Run tests.
# CertManager is installed by default; skip with:
# - CERT_MANAGER_INSTALL_SKIP=true
KIND_CLUSTER ?= kubernetes-operator-test-e2e
KIND_CONFIG ?= test/e2e/kind-config.yaml

.PHONY: setup-test-e2e
setup-test-e2e: ## Set up a Kind cluster for e2e tests if it does not exist
setup-test-e2e: ## Set up a multi-node Kind cluster for e2e tests if it does not exist
@command -v $(KIND) >/dev/null 2>&1 || { \
echo "Kind is not installed. Please install Kind manually."; \
exit 1; \
Expand All @@ -92,12 +93,14 @@ setup-test-e2e: ## Set up a Kind cluster for e2e tests if it does not exist
echo "Kind cluster '$(KIND_CLUSTER)' already exists. Skipping creation." ;; \
*) \
echo "Creating Kind cluster '$(KIND_CLUSTER)'..."; \
$(KIND) create cluster --name $(KIND_CLUSTER) ;; \
$(KIND) create cluster --name $(KIND_CLUSTER) --config $(KIND_CONFIG) ;; \
esac

# The generous timeout covers the whole suite end to end: building the manager
# image, pulling real Memgraph images, and bootstrapping an HA cluster in Kind.
.PHONY: test-e2e
test-e2e: setup-test-e2e manifests generate fmt vet ## Run the e2e tests. Expected an isolated environment using Kind.
KIND=$(KIND) KIND_CLUSTER=$(KIND_CLUSTER) go test -tags=e2e ./test/e2e/ -v -ginkgo.v
KIND=$(KIND) KIND_CLUSTER=$(KIND_CLUSTER) go test -tags=e2e ./test/e2e/ -v -ginkgo.v -timeout 40m
$(MAKE) cleanup-test-e2e

.PHONY: cleanup-test-e2e
Expand Down
38 changes: 38 additions & 0 deletions test/e2e/e2e_suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ func TestE2E(t *testing.T) {
RunSpecs(t, "e2e suite")
}

// The suite deploys the operator once, before any scenario runs: build and
// load the manager image, install the CRDs, and deploy the controller into its
// namespace. Scenario containers (Describe blocks) then only exercise
// MemgraphCluster behavior, so a new scenario is a new test case, never new
// pipeline or deployment plumbing.
var _ = BeforeSuite(func() {
By("building the manager image")
cmd := exec.Command("make", "docker-build", fmt.Sprintf("IMG=%s", managerImage))
Expand All @@ -64,9 +69,42 @@ var _ = BeforeSuite(func() {

configureKubectlKubeRC()
setupCertManager()

By("creating manager namespace")
cmd = exec.Command("kubectl", "create", "ns", namespace)
_, err = utils.Run(cmd)
Expect(err).NotTo(HaveOccurred(), "Failed to create namespace")

By("labeling the namespace to enforce the restricted security policy")
cmd = exec.Command("kubectl", "label", "--overwrite", "ns", namespace,
"pod-security.kubernetes.io/enforce=restricted")
_, err = utils.Run(cmd)
Expect(err).NotTo(HaveOccurred(), "Failed to label namespace with restricted policy")

By("installing CRDs")
cmd = exec.Command("make", "install")
_, err = utils.Run(cmd)
Expect(err).NotTo(HaveOccurred(), "Failed to install CRDs")

By("deploying the controller-manager")
cmd = exec.Command("make", "deploy", fmt.Sprintf("IMG=%s", managerImage))
_, err = utils.Run(cmd)
Expect(err).NotTo(HaveOccurred(), "Failed to deploy the controller-manager")
})

var _ = AfterSuite(func() {
By("undeploying the controller-manager")
cmd := exec.Command("make", "undeploy")
_, _ = utils.Run(cmd)

By("uninstalling CRDs")
cmd = exec.Command("make", "uninstall")
_, _ = utils.Run(cmd)

By("removing manager namespace")
cmd = exec.Command("kubectl", "delete", "ns", namespace)
_, _ = utils.Run(cmd)

teardownCertManager()
})

Expand Down
43 changes: 4 additions & 39 deletions test/e2e/e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,50 +48,15 @@ const metricsRoleBindingName = "kubernetes-operator-metrics-binding"
var _ = Describe("Manager", Ordered, func() {
var controllerPodName string

// Before running the tests, set up the environment by creating the namespace,
// enforce the restricted security policy to the namespace, installing CRDs,
// and deploying the controller.
BeforeAll(func() {
By("creating manager namespace")
cmd := exec.Command("kubectl", "create", "ns", namespace)
_, err := utils.Run(cmd)
Expect(err).NotTo(HaveOccurred(), "Failed to create namespace")

By("labeling the namespace to enforce the restricted security policy")
cmd = exec.Command("kubectl", "label", "--overwrite", "ns", namespace,
"pod-security.kubernetes.io/enforce=restricted")
_, err = utils.Run(cmd)
Expect(err).NotTo(HaveOccurred(), "Failed to label namespace with restricted policy")

By("installing CRDs")
cmd = exec.Command("make", "install")
_, err = utils.Run(cmd)
Expect(err).NotTo(HaveOccurred(), "Failed to install CRDs")

By("deploying the controller-manager")
cmd = exec.Command("make", "deploy", fmt.Sprintf("IMG=%s", managerImage))
_, err = utils.Run(cmd)
Expect(err).NotTo(HaveOccurred(), "Failed to deploy the controller-manager")
})
// The operator itself (namespace, CRDs, controller Deployment) is set up
// once for the whole suite in BeforeSuite; this container only validates
// the already-deployed manager.

// After all tests have been executed, clean up by undeploying the controller, uninstalling CRDs,
// and deleting the namespace.
// After all tests have been executed, clean up resources created by this container.
AfterAll(func() {
By("cleaning up the curl pod for metrics")
cmd := exec.Command("kubectl", "delete", "pod", "curl-metrics", "-n", namespace)
_, _ = utils.Run(cmd)

By("undeploying the controller-manager")
cmd = exec.Command("make", "undeploy")
_, _ = utils.Run(cmd)

By("uninstalling CRDs")
cmd = exec.Command("make", "uninstall")
_, _ = utils.Run(cmd)

By("removing manager namespace")
cmd = exec.Command("kubectl", "delete", "ns", namespace)
_, _ = utils.Run(cmd)
})

// After each test, check for failures and collect logs, events,
Expand Down
10 changes: 10 additions & 0 deletions test/e2e/kind-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Multi-node Kind cluster for the e2e suite. A Memgraph HA cluster is only a
# meaningful end-to-end proof when its coordinators and data instances spread
# across several nodes, mirroring the HA chart's multi-node CI.
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: worker
- role: worker
- role: worker
Loading