From c33ab72262e5cadfa5cfb0c3d923ea504f5b302f Mon Sep 17 00:00:00 2001 From: Camila Macedo Date: Sun, 22 Sep 2024 09:10:57 +0100 Subject: [PATCH] cleanup/refactory: Implement and refactor e2e tests for 'alpha generate' command - Added comprehensive end-to-end tests for the 'generate' command. - Ensured proper validation of the 'PROJECT' file after project initialization and regeneration. - Verified correct handling of multigroup layouts, Grafana, and DeployImage plugins. - Refactored the test structure to align with existing patterns used in other tests. - Improved maintainability and test coverage to support future growth and more scenarios. --- test/e2e/alphagenerate/generate_test.go | 270 ------------------ .../e2e_suite_test.go | 2 +- test/e2e/generate/generate_test.go | 194 +++++++++++++ test/e2e/setup.sh | 2 +- 4 files changed, 196 insertions(+), 272 deletions(-) delete mode 100644 test/e2e/alphagenerate/generate_test.go rename test/e2e/{alphagenerate => generate}/e2e_suite_test.go (97%) create mode 100644 test/e2e/generate/generate_test.go diff --git a/test/e2e/alphagenerate/generate_test.go b/test/e2e/alphagenerate/generate_test.go deleted file mode 100644 index fb93663f0f9..00000000000 --- a/test/e2e/alphagenerate/generate_test.go +++ /dev/null @@ -1,270 +0,0 @@ -/* -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 alphagenerate - -import ( - "fmt" - "io" - "os" - "path/filepath" - - pluginutil "sigs.k8s.io/kubebuilder/v4/pkg/plugin/util" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - - "sigs.k8s.io/kubebuilder/v4/test/e2e/utils" -) - -var _ = Describe("kubebuilder", func() { - Context("alpha generate ", func() { - var ( - kbc *utils.TestContext - ) - - BeforeEach(func() { - var err error - kbc, err = utils.NewTestContext(pluginutil.KubebuilderBinName, "GO111MODULE=on") - Expect(err).NotTo(HaveOccurred()) - Expect(kbc.Prepare()).To(Succeed()) - }) - - AfterEach(func() { - kbc.Destroy() - }) - - It("should regenerate the project with success", func() { - ReGenerateProject(kbc) - }) - - }) -}) - -// ReGenerateProject implements a project that is regenerated by kubebuilder. -func ReGenerateProject(kbc *utils.TestContext) { - var err error - - By("initializing a project") - err = kbc.Init( - "--plugins", "go/v4", - "--project-version", "3", - "--domain", kbc.Domain, - ) - ExpectWithOffset(1, err).NotTo(HaveOccurred()) - - By("regenerating the project") - err = kbc.Regenerate( - "--input-dir", kbc.Dir, - "--output-dir", filepath.Join(kbc.Dir, "testdir"), - ) - ExpectWithOffset(1, err).NotTo(HaveOccurred()) - - By("checking if the project file was generated with the expected layout") - var layout = `layout: -- go.kubebuilder.io/v4 -` - fileContainsExpr, err := pluginutil.HasFileContentWith( - filepath.Join(kbc.Dir, "testdir", "PROJECT"), layout) - ExpectWithOffset(1, err).NotTo(HaveOccurred()) - ExpectWithOffset(1, fileContainsExpr).To(BeTrue()) - - By("checking if the project file was generated with the expected domain") - var domain = fmt.Sprintf("domain: %s", kbc.Domain) - fileContainsExpr, err = pluginutil.HasFileContentWith( - filepath.Join(kbc.Dir, "testdir", "PROJECT"), domain) - ExpectWithOffset(1, err).NotTo(HaveOccurred()) - ExpectWithOffset(1, fileContainsExpr).To(BeTrue()) - - By("checking if the project file was generated with the expected version") - var version = `version: "3"` - fileContainsExpr, err = pluginutil.HasFileContentWith( - filepath.Join(kbc.Dir, "testdir", "PROJECT"), version) - ExpectWithOffset(1, err).NotTo(HaveOccurred()) - ExpectWithOffset(1, fileContainsExpr).To(BeTrue()) - - By("editing a project with multigroup=true") - err = kbc.Edit( - "--multigroup=true", - ) - ExpectWithOffset(1, err).NotTo(HaveOccurred()) - - By("create APIs with resource and controller") - err = kbc.CreateAPI( - "--group", "crew", - "--version", "v1", - "--kind", "Captain", - "--namespaced", - "--resource", - "--controller", - ) - ExpectWithOffset(1, err).NotTo(HaveOccurred()) - - By("create Webhooks with conversion and validating webhook") - err = kbc.CreateWebhook( - "--group", "crew", - "--version", "v1", - "--kind", "Captain", - "--programmatic-validation", - "--conversion", - ) - ExpectWithOffset(1, err).NotTo(HaveOccurred()) - - By("create APIs non namespaced with resource and controller") - err = kbc.CreateAPI( - "--group", "crew", - "--version", "v1", - "--kind", "Admiral", - "--namespaced=false", - "--resource", - "--controller", - ) - ExpectWithOffset(1, err).NotTo(HaveOccurred()) - - By("create APIs with deploy-image plugin") - err = kbc.CreateAPI( - "--group", "crew", - "--version", "v1", - "--kind", "Memcached", - "--image=memcached:1.6.15-alpine", - "--image-container-command=memcached,--memory-limit=64,modern,-v", - "--image-container-port=11211", - "--run-as-user=1001", - "--plugins=\"deploy-image/v1-alpha\"", - ) - ExpectWithOffset(1, err).NotTo(HaveOccurred()) - - By("Enable grafana plugin to an existing project") - err = kbc.Edit( - "--plugins", "grafana.kubebuilder.io/v1-alpha", - ) - ExpectWithOffset(1, err).NotTo(HaveOccurred()) - - By("Edit the grafana config file") - grafanaConfig, err := os.OpenFile(filepath.Join(kbc.Dir, "grafana/custom-metrics/config.yaml"), - os.O_APPEND|os.O_WRONLY, 0644) - ExpectWithOffset(1, err).NotTo(HaveOccurred()) - newLine := "test_new_line" - _, err = io.WriteString(grafanaConfig, newLine) - ExpectWithOffset(1, err).NotTo(HaveOccurred()) - err = grafanaConfig.Close() - ExpectWithOffset(1, err).NotTo(HaveOccurred()) - - By("regenerating the project at another output directory") - err = kbc.Regenerate( - "--input-dir", kbc.Dir, - "--output-dir", filepath.Join(kbc.Dir, "testdir2"), - ) - ExpectWithOffset(1, err).NotTo(HaveOccurred()) - - By("checking if the project file was generated with the expected multigroup flag") - var multiGroup = `multigroup: true` - fileContainsExpr, err = pluginutil.HasFileContentWith( - filepath.Join(kbc.Dir, "testdir2", "PROJECT"), multiGroup) - ExpectWithOffset(1, err).NotTo(HaveOccurred()) - ExpectWithOffset(1, fileContainsExpr).To(BeTrue()) - - By("checking if the project file was generated with the expected group") - var APIGroup = "group: crew" - fileContainsExpr, err = pluginutil.HasFileContentWith( - filepath.Join(kbc.Dir, "testdir2", "PROJECT"), APIGroup) - ExpectWithOffset(1, err).NotTo(HaveOccurred()) - ExpectWithOffset(1, fileContainsExpr).To(BeTrue()) - - By("checking if the project file was generated with the expected kind") - var APIKind = "kind: Captain" - fileContainsExpr, err = pluginutil.HasFileContentWith( - filepath.Join(kbc.Dir, "testdir2", "PROJECT"), APIKind) - ExpectWithOffset(1, err).NotTo(HaveOccurred()) - ExpectWithOffset(1, fileContainsExpr).To(BeTrue()) - - By("checking if the project file was generated with the expected version") - var APIVersion = "version: v1" - fileContainsExpr, err = pluginutil.HasFileContentWith( - filepath.Join(kbc.Dir, "testdir2", "PROJECT"), APIVersion) - ExpectWithOffset(1, err).NotTo(HaveOccurred()) - ExpectWithOffset(1, fileContainsExpr).To(BeTrue()) - - By("checking if the project file was generated with the expected namespaced") - var namespaced = "namespaced: true" - fileContainsExpr, err = pluginutil.HasFileContentWith( - filepath.Join(kbc.Dir, "testdir2", "PROJECT"), namespaced) - ExpectWithOffset(1, err).NotTo(HaveOccurred()) - ExpectWithOffset(1, fileContainsExpr).To(BeTrue()) - - By("checking if the project file was generated with the expected controller") - var controller = "controller: true" - fileContainsExpr, err = pluginutil.HasFileContentWith( - filepath.Join(kbc.Dir, "testdir2", "PROJECT"), controller) - ExpectWithOffset(1, err).NotTo(HaveOccurred()) - ExpectWithOffset(1, fileContainsExpr).To(BeTrue()) - - By("checking if the project file was generated with the expected webhook") - var webhook = `webhooks: - conversion: true - validation: true` - fileContainsExpr, err = pluginutil.HasFileContentWith( - filepath.Join(kbc.Dir, "testdir2", "PROJECT"), webhook) - ExpectWithOffset(1, err).NotTo(HaveOccurred()) - ExpectWithOffset(1, fileContainsExpr).To(BeTrue()) - - By("checking if the project file was generated without namespace: true") - var nonNamespacedFields = fmt.Sprintf(`api: - crdVersion: v1 - controller: true - domain: %s - group: crew - kind: Admiral`, kbc.Domain) - fileContainsExpr, err = pluginutil.HasFileContentWith( - filepath.Join(kbc.Dir, "testdir2", "PROJECT"), nonNamespacedFields) - ExpectWithOffset(1, err).NotTo(HaveOccurred()) - Expect(fileContainsExpr).To(BeTrue()) - - By("checking if the project file was generated with the expected deploy-image plugin fields") - var deployImagePlugin = "deploy-image.go.kubebuilder.io/v1-alpha" - fileContainsExpr, err = pluginutil.HasFileContentWith( - filepath.Join(kbc.Dir, "testdir2", "PROJECT"), deployImagePlugin) - Expect(err).NotTo(HaveOccurred()) - Expect(fileContainsExpr).To(BeTrue()) - var deployImagePluginFields = `kind: Memcached - options: - containerCommand: memcached,--memory-limit=64,modern,-v - containerPort: "11211" - image: memcached:1.6.15-alpine - runAsUser: "1001"` - fileContainsExpr, err = pluginutil.HasFileContentWith( - filepath.Join(kbc.Dir, "testdir2", "PROJECT"), deployImagePluginFields) - Expect(err).NotTo(HaveOccurred()) - Expect(fileContainsExpr).To(BeTrue()) - - By("checking if the project file was generated with the expected grafana plugin fields") - var grafanaPlugin = "grafana.kubebuilder.io/v1-alpha" - fileContainsExpr, err = pluginutil.HasFileContentWith( - filepath.Join(kbc.Dir, "testdir2", "PROJECT"), grafanaPlugin) - ExpectWithOffset(1, err).NotTo(HaveOccurred()) - ExpectWithOffset(1, fileContainsExpr).To(BeTrue()) - - By("checking if the generated grafana config file has the same content as the old one") - grafanaConfigPath := filepath.Join(kbc.Dir, "grafana/custom-metrics/config.yaml") - generatedGrafanaConfigPath := filepath.Join(kbc.Dir, "testdir2", "grafana/custom-metrics/config.yaml") - Expect(grafanaConfigPath).Should(BeARegularFile()) - Expect(generatedGrafanaConfigPath).Should(BeARegularFile()) - bytesBefore, err := os.ReadFile(grafanaConfigPath) - Expect(err).NotTo(HaveOccurred()) - bytesAfter, err := os.ReadFile(generatedGrafanaConfigPath) - Expect(err).NotTo(HaveOccurred()) - Expect(bytesBefore).Should(Equal(bytesAfter)) -} diff --git a/test/e2e/alphagenerate/e2e_suite_test.go b/test/e2e/generate/e2e_suite_test.go similarity index 97% rename from test/e2e/alphagenerate/e2e_suite_test.go rename to test/e2e/generate/e2e_suite_test.go index 7f3d82bf0ea..da778e3a875 100644 --- a/test/e2e/alphagenerate/e2e_suite_test.go +++ b/test/e2e/generate/e2e_suite_test.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package alphagenerate +package generate import ( "fmt" diff --git a/test/e2e/generate/generate_test.go b/test/e2e/generate/generate_test.go new file mode 100644 index 00000000000..c915811921a --- /dev/null +++ b/test/e2e/generate/generate_test.go @@ -0,0 +1,194 @@ +/* +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 generate + +import ( + "fmt" + "os" + "path/filepath" + + pluginutil "sigs.k8s.io/kubebuilder/v4/pkg/plugin/util" + "sigs.k8s.io/kubebuilder/v4/test/e2e/utils" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +var _ = Describe("kubebuilder", func() { + Context("alpha generate", func() { + var ( + kbc *utils.TestContext + projectRegeneratedPath string + ) + + BeforeEach(func() { + var err error + kbc, err = utils.NewTestContext(pluginutil.KubebuilderBinName, "GO111MODULE=on") + Expect(err).NotTo(HaveOccurred()) + Expect(kbc.Prepare()).To(Succeed()) + + By("initializing a project") + err = kbc.Init( + "--plugins", "go/v4", + "--project-version", "3", + "--domain", kbc.Domain, + ) + Expect(err).NotTo(HaveOccurred(), "Failed to create project") + + By("setting and creating the output directory before regenerating") + projectRegeneratedPath = filepath.Join(kbc.Dir, "regenerated") + err = os.MkdirAll(projectRegeneratedPath, os.ModePerm) + Expect(err).NotTo(HaveOccurred(), "Failed to create output directory") + }) + + AfterEach(func() { + kbc.Destroy() + }) + + It("should regenerate the project with success", func() { + generateProject(kbc, projectRegeneratedPath) + validateProjectFile(kbc, projectRegeneratedPath) + }) + + It("should regenerate the project with multigroup layout", func() { + generateProjectWithMultiGroup(kbc) + validateMultigroupProjectFile(projectRegeneratedPath) + }) + + It("should regenerate project with grafana plugin with success", func() { + generateProjectWithGrafanaPlugin(kbc) + validateGrafanaPlugin(projectRegeneratedPath) + }) + + It("should regenerate project with DeployImage plugin with success", func() { + generateProjectWithDeployImagePlugin(kbc) + validateDeployImagePlugin(projectRegeneratedPath) + }) + }) +}) + +func generateProject(kbc *utils.TestContext, projectRegeneratedPath string) { + By("creating API definition") + err := kbc.CreateAPI( + "--group", kbc.Group, + "--version", kbc.Version, + "--kind", kbc.Kind, + "--namespaced", + "--resource", + "--controller", + "--make=false", + ) + Expect(err).NotTo(HaveOccurred(), "Failed to scaffold api with resource and controller") + + By("regenerating the project") + err = kbc.Regenerate( + "--input-dir", kbc.Dir, + "--output-dir", projectRegeneratedPath, + ) + Expect(err).NotTo(HaveOccurred(), "Failed to regenerate project") +} + +func generateProjectWithMultiGroup(kbc *utils.TestContext) { + By("editing project to enable multigroup layout") + err := kbc.Edit("--multigroup", "true") + Expect(err).NotTo(HaveOccurred(), "Failed to edit project for multigroup layout") +} + +func generateProjectWithGrafanaPlugin(kbc *utils.TestContext) { + By("editing project to enable Grafana plugin") + err := kbc.Edit("--plugins", "grafana.kubebuilder.io/v1-alpha") + Expect(err).NotTo(HaveOccurred(), "Failed to edit project to enable Grafana Plugin") +} + +func generateProjectWithDeployImagePlugin(kbc *utils.TestContext) { + By("creating an API with DeployImage plugin") + err := kbc.CreateAPI( + "--group", "crew", + "--version", "v1", + "--kind", "Memcached", + "--image=memcached:1.6.15-alpine", + "--image-container-command=memcached,--memory-limit=64,modern,-v", + "--image-container-port=11211", + "--run-as-user=1001", + "--plugins=deploy-image/v1-alpha", + ) + Expect(err).NotTo(HaveOccurred(), "Failed to create API with Deploy Image Plugin") +} + +// Validate the PROJECT file for basic content +func validateProjectFile(kbc *utils.TestContext, projectRegeneratedPath string) { + projectPath := filepath.Join(projectRegeneratedPath, "PROJECT") + Expect(projectPath).To(BeARegularFile()) + + By("checking the layout in the PROJECT file") + layout := "layout:\n- go.kubebuilder.io/v4\n" + validateFileContent(projectPath, layout) + + By("checking the domain in the PROJECT file") + domain := fmt.Sprintf("domain: %s", kbc.Domain) + validateFileContent(projectPath, domain) + + By("checking the version in the PROJECT file") + version := `version: "3"` + validateFileContent(projectPath, version) +} + +// Validate the PROJECT file for multigroup layout +func validateMultigroupProjectFile(projectRegeneratedPath string) { + projectPath := filepath.Join(projectRegeneratedPath, "PROJECT") + Expect(projectPath).To(BeARegularFile()) + + By("checking the multigroup flag in the PROJECT file") + multigroup := "multigroup: true" + validateFileContent(projectPath, multigroup) +} + +// Validate the PROJECT file for the Grafana plugin +func validateGrafanaPlugin(projectRegeneratedPath string) { + projectPath := filepath.Join(projectRegeneratedPath, "PROJECT") + Expect(projectPath).To(BeARegularFile()) + + By("checking the Grafana plugin in the PROJECT file") + plugin := "grafana.kubebuilder.io/v1-alpha" + validateFileContent(projectPath, plugin) +} + +// Validate the PROJECT file for the DeployImage plugin +func validateDeployImagePlugin(projectRegeneratedPath string) { + projectPath := filepath.Join(projectRegeneratedPath, "PROJECT") + Expect(projectPath).To(BeARegularFile()) + + By("checking the DeployImage plugin in the PROJECT file") + deployImagePlugin := "deploy-image.go.kubebuilder.io/v1-alpha" + validateFileContent(projectPath, deployImagePlugin) + + By("checking the DeployImage fields in the PROJECT file") + deployImageFields := `kind: Memcached + options: + containerCommand: memcached,--memory-limit=64,modern,-v + containerPort: "11211" + image: memcached:1.6.15-alpine + runAsUser: "1001"` + validateFileContent(projectPath, deployImageFields) +} + +// Helper function to validate content in the PROJECT file +func validateFileContent(filePath, expectedContent string) { + fileContainsExpr, err := pluginutil.HasFileContentWith(filePath, expectedContent) + ExpectWithOffset(1, err).NotTo(HaveOccurred()) + ExpectWithOffset(1, fileContainsExpr).To(BeTrue()) +} diff --git a/test/e2e/setup.sh b/test/e2e/setup.sh index 18f96e24945..364aad2f13f 100755 --- a/test/e2e/setup.sh +++ b/test/e2e/setup.sh @@ -70,7 +70,7 @@ function test_cluster { go test $(dirname "$0")/deployimage $flags -timeout 30m go test $(dirname "$0")/v4 $flags -timeout 30m go test $(dirname "$0")/externalplugin $flags -timeout 30m - go test $(dirname "$0")/alphagenerate $flags -timeout 30m + go test $(dirname "$0")/generate $flags -timeout 30m } function build_sample_external_plugin {