Skip to content

Commit

Permalink
✨ (go/v4) e2e tests: improve e2e tests and make test-e2e target (kube…
Browse files Browse the repository at this point in the history
…rnetes-sigs#4106)

e2e tests: improve e2e tests and make test-e2e target

- Ensure that kind is installed and running before run the tests. Otherwise it will fail since we need to load the Manager(Operator) image
- Add logic to skip the installation of CertManager and/or Prometheus via envvars.
- Ensure that the promethues and certmanager are installed in the suite test instead of beafore each test
- Ensure that the image is build and load in the suite instead instead for each test
- Add more comments to clarify the purpose of the tests
- Add TODO(user) to clarify that is expected action for the users to suplement and/or customize their e2e tests according to their needs
  • Loading branch information
camilamacedo86 authored Aug 29, 2024
1 parent fb432c4 commit fa8b88f
Show file tree
Hide file tree
Showing 24 changed files with 864 additions and 384 deletions.
18 changes: 15 additions & 3 deletions docs/book/src/cronjob-tutorial/testdata/project/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,21 @@ vet: ## Run go vet against code.
test: manifests generate fmt vet envtest ## Run tests.
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" go test $$(go list ./... | grep -v /e2e) -coverprofile cover.out

# Utilize Kind or modify the e2e tests to load the image locally, enabling compatibility with other vendors.
.PHONY: test-e2e # Run the e2e tests against a Kind k8s instance that is spun up.
test-e2e:
# TODO(user): To use a different vendor for e2e tests, modify the setup under 'tests/e2e'.
# The default setup assumes Kind is pre-installed and builds/loads the Manager Docker image locally.
# Prometheus and CertManager are installed by default; skip with:
# - PROMETHEUS_INSTALL_SKIP=true
# - CERT_MANAGER_INSTALL_SKIP=true
.PHONY: test-e2e
test-e2e: ## Run the e2e tests. Expected an isolated environment using Kind.
@command -v kind >/dev/null 2>&1 || { \
echo "Kind is not installed. Please install Kind manually."; \
exit 1; \
}
@kind get clusters | grep -q 'kind' || { \
echo "No Kind cluster is running. Please start a Kind cluster before running the e2e tests."; \
exit 1; \
}
go test ./test/e2e/ -v -ginkgo.v

.PHONY: lint
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,71 @@ package e2e

import (
"fmt"
"os"
"os/exec"
"testing"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"

"tutorial.kubebuilder.io/project/test/utils"
)

var (
// Optional Environment Variables:
// - PROMETHEUS_INSTALL_SKIP=true: Skips Prometheus Operator installation during test setup.
// - CERT_MANAGER_INSTALL_SKIP=true: Skips CertManager installation during test setup.
// These variables are useful if Prometheus or CertManager is already installed, avoiding
// re-installation and conflicts.
skipPrometheusInstall = os.Getenv("PROMETHEUS_INSTALL_SKIP") == "true"
skipCertManagerInstall = os.Getenv("CERT_MANAGER_INSTALL_SKIP") == "true"

// projectImage is the name of the image which will be build and loaded
// with the code source changes to be tested.
projectImage = "example.com/project:v0.0.1"
)

// Run e2e tests using the Ginkgo runner.
// TestE2E runs the end-to-end (e2e) test suite for the project. These tests execute in an isolated,
// temporary environment to validate project changes with the the purposed to be used in CI jobs.
// The default setup requires Kind, builds/loads the Manager Docker image locally, and installs
// CertManager and Prometheus.
func TestE2E(t *testing.T) {
RegisterFailHandler(Fail)
_, _ = fmt.Fprintf(GinkgoWriter, "Starting project suite\n")
_, _ = fmt.Fprintf(GinkgoWriter, "Starting project integration test suite\n")
RunSpecs(t, "e2e suite")
}

var _ = BeforeSuite(func() {
By("building the manager(Operator) image")
cmd := exec.Command("make", "docker-build", fmt.Sprintf("IMG=%s", projectImage))
_, err := utils.Run(cmd)
ExpectWithOffset(1, err).NotTo(HaveOccurred(), "Failed to build the manager(Operator) image")

// TODO(user): If you want to change the e2e test vendor from Kind, ensure the image is
// built and available before running the tests. Also, remove the following block.
By("loading the manager(Operator) image on Kind")
err = utils.LoadImageToKindClusterWithName(projectImage)
ExpectWithOffset(1, err).NotTo(HaveOccurred(), "Failed to load the manager(Operator) image into Kind")

// Setup Prometheus and CertManager before the suite if not skipped
if !skipPrometheusInstall {
_, _ = fmt.Fprintf(GinkgoWriter, "Installing Prometheus Operator...\n")
Expect(utils.InstallPrometheusOperator()).To(Succeed(), "Failed to install Prometheus Operator")
}
if !skipCertManagerInstall {
_, _ = fmt.Fprintf(GinkgoWriter, "Installing CertManager...\n")
Expect(utils.InstallCertManager()).To(Succeed(), "Failed to install CertManager")
}
})

var _ = AfterSuite(func() {
// Teardown Prometheus and CertManager after the suite if not skipped
if !skipPrometheusInstall {
_, _ = fmt.Fprintf(GinkgoWriter, "Uninstalling Prometheus Operator...\n")
utils.UninstallPrometheusOperator()
}
if !skipCertManagerInstall {
_, _ = fmt.Fprintf(GinkgoWriter, "Uninstalling CertManager...\n")
utils.UninstallCertManager()
}
})
Original file line number Diff line number Diff line change
Expand Up @@ -29,63 +29,52 @@ import (

const namespace = "project-system"

// Define a set of end-to-end (e2e) tests to validate the behavior of the controller.
var _ = Describe("controller", Ordered, func() {
// Before running the tests, set up the environment by creating the namespace,
// installing CRDs, and deploying the controller.
BeforeAll(func() {
By("installing prometheus operator")
Expect(utils.InstallPrometheusOperator()).To(Succeed())

By("installing the cert-manager")
Expect(utils.InstallCertManager()).To(Succeed())

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

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

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

// After all tests have been executed, clean up by undeploying the controller, uninstalling CRDs,
// and deleting the namespace.
AfterAll(func() {
By("uninstalling the Prometheus manager bundle")
utils.UninstallPrometheusOperator()
By("undeploying the controller-manager")
cmd := exec.Command("make", "undeploy")
_, _ = utils.Run(cmd)

By("uninstalling the cert-manager bundle")
utils.UninstallCertManager()
By("uninstalling CRDs")
cmd = exec.Command("make", "uninstall")
_, _ = utils.Run(cmd)

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

// The Context block contains the actual tests that validate the operator's behavior.
Context("Operator", func() {
It("should run successfully", func() {
var controllerPodName string
var err error

// projectimage stores the name of the image used in the example
var projectimage = "example.com/project:v0.0.1"

By("building the manager(Operator) image")
cmd := exec.Command("make", "docker-build", fmt.Sprintf("IMG=%s", projectimage))
_, err = utils.Run(cmd)
ExpectWithOffset(1, err).NotTo(HaveOccurred())

By("loading the the manager(Operator) image on Kind")
err = utils.LoadImageToKindClusterWithName(projectimage)
ExpectWithOffset(1, err).NotTo(HaveOccurred())

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

By("deploying the controller-manager")
cmd = exec.Command("make", "deploy", fmt.Sprintf("IMG=%s", projectimage))
_, err = utils.Run(cmd)
ExpectWithOffset(1, err).NotTo(HaveOccurred())

By("validating that the controller-manager pod is running as expected")
verifyControllerUp := func() error {
// Get pod name

cmd = exec.Command("kubectl", "get",
// Get the name of the controller-manager pod
cmd := exec.Command("kubectl", "get",
"pods", "-l", "control-plane=controller-manager",
"-o", "go-template={{ range .items }}"+
"{{ if not .metadata.deletionTimestamp }}"+
Expand All @@ -95,28 +84,31 @@ var _ = Describe("controller", Ordered, func() {
)

podOutput, err := utils.Run(cmd)
ExpectWithOffset(2, err).NotTo(HaveOccurred())
ExpectWithOffset(2, err).NotTo(HaveOccurred(), "Failed to retrieve controller-manager pod information")
podNames := utils.GetNonEmptyLines(string(podOutput))
if len(podNames) != 1 {
return fmt.Errorf("expect 1 controller pods running, but got %d", len(podNames))
return fmt.Errorf("expected 1 controller pod running, but got %d", len(podNames))
}
controllerPodName = podNames[0]
ExpectWithOffset(2, controllerPodName).Should(ContainSubstring("controller-manager"))

// Validate pod status
// Validate the pod's status
cmd = exec.Command("kubectl", "get",
"pods", controllerPodName, "-o", "jsonpath={.status.phase}",
"-n", namespace,
)
status, err := utils.Run(cmd)
ExpectWithOffset(2, err).NotTo(HaveOccurred())
ExpectWithOffset(2, err).NotTo(HaveOccurred(), "Failed to retrieve controller-manager pod status")
if string(status) != "Running" {
return fmt.Errorf("controller pod in %s status", status)
}
return nil
}
// Repeatedly check if the controller-manager pod is running until it succeeds or times out.
EventuallyWithOffset(1, verifyControllerUp, time.Minute, time.Second).Should(Succeed())

})

// TODO(user): Customize the e2e test suite to include
// additional scenarios specific to your project.
})
})
18 changes: 15 additions & 3 deletions docs/book/src/getting-started/testdata/project/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,21 @@ vet: ## Run go vet against code.
test: manifests generate fmt vet envtest ## Run tests.
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" go test $$(go list ./... | grep -v /e2e) -coverprofile cover.out

# Utilize Kind or modify the e2e tests to load the image locally, enabling compatibility with other vendors.
.PHONY: test-e2e # Run the e2e tests against a Kind k8s instance that is spun up.
test-e2e:
# TODO(user): To use a different vendor for e2e tests, modify the setup under 'tests/e2e'.
# The default setup assumes Kind is pre-installed and builds/loads the Manager Docker image locally.
# Prometheus and CertManager are installed by default; skip with:
# - PROMETHEUS_INSTALL_SKIP=true
# - CERT_MANAGER_INSTALL_SKIP=true
.PHONY: test-e2e
test-e2e: ## Run the e2e tests. Expected an isolated environment using Kind.
@command -v kind >/dev/null 2>&1 || { \
echo "Kind is not installed. Please install Kind manually."; \
exit 1; \
}
@kind get clusters | grep -q 'kind' || { \
echo "No Kind cluster is running. Please start a Kind cluster before running the e2e tests."; \
exit 1; \
}
go test ./test/e2e/ -v -ginkgo.v

.PHONY: lint
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,71 @@ package e2e

import (
"fmt"
"os"
"os/exec"
"testing"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"

"example.com/memcached/test/utils"
)

var (
// Optional Environment Variables:
// - PROMETHEUS_INSTALL_SKIP=true: Skips Prometheus Operator installation during test setup.
// - CERT_MANAGER_INSTALL_SKIP=true: Skips CertManager installation during test setup.
// These variables are useful if Prometheus or CertManager is already installed, avoiding
// re-installation and conflicts.
skipPrometheusInstall = os.Getenv("PROMETHEUS_INSTALL_SKIP") == "true"
skipCertManagerInstall = os.Getenv("CERT_MANAGER_INSTALL_SKIP") == "true"

// projectImage is the name of the image which will be build and loaded
// with the code source changes to be tested.
projectImage = "example.com/project:v0.0.1"
)

// Run e2e tests using the Ginkgo runner.
// TestE2E runs the end-to-end (e2e) test suite for the project. These tests execute in an isolated,
// temporary environment to validate project changes with the the purposed to be used in CI jobs.
// The default setup requires Kind, builds/loads the Manager Docker image locally, and installs
// CertManager and Prometheus.
func TestE2E(t *testing.T) {
RegisterFailHandler(Fail)
_, _ = fmt.Fprintf(GinkgoWriter, "Starting project suite\n")
_, _ = fmt.Fprintf(GinkgoWriter, "Starting project integration test suite\n")
RunSpecs(t, "e2e suite")
}

var _ = BeforeSuite(func() {
By("building the manager(Operator) image")
cmd := exec.Command("make", "docker-build", fmt.Sprintf("IMG=%s", projectImage))
_, err := utils.Run(cmd)
ExpectWithOffset(1, err).NotTo(HaveOccurred(), "Failed to build the manager(Operator) image")

// TODO(user): If you want to change the e2e test vendor from Kind, ensure the image is
// built and available before running the tests. Also, remove the following block.
By("loading the manager(Operator) image on Kind")
err = utils.LoadImageToKindClusterWithName(projectImage)
ExpectWithOffset(1, err).NotTo(HaveOccurred(), "Failed to load the manager(Operator) image into Kind")

// Setup Prometheus and CertManager before the suite if not skipped
if !skipPrometheusInstall {
_, _ = fmt.Fprintf(GinkgoWriter, "Installing Prometheus Operator...\n")
Expect(utils.InstallPrometheusOperator()).To(Succeed(), "Failed to install Prometheus Operator")
}
if !skipCertManagerInstall {
_, _ = fmt.Fprintf(GinkgoWriter, "Installing CertManager...\n")
Expect(utils.InstallCertManager()).To(Succeed(), "Failed to install CertManager")
}
})

var _ = AfterSuite(func() {
// Teardown Prometheus and CertManager after the suite if not skipped
if !skipPrometheusInstall {
_, _ = fmt.Fprintf(GinkgoWriter, "Uninstalling Prometheus Operator...\n")
utils.UninstallPrometheusOperator()
}
if !skipCertManagerInstall {
_, _ = fmt.Fprintf(GinkgoWriter, "Uninstalling CertManager...\n")
utils.UninstallCertManager()
}
})
Loading

0 comments on commit fa8b88f

Please sign in to comment.