@@ -111,6 +111,7 @@ func (sp *Sample) UpdateTutorial() {
111111 sp .updateConversionFiles ()
112112 sp .updateSampleV2 ()
113113 sp .updateMain ()
114+ sp .updateE2EWebhookConversion ()
114115}
115116
116117func (sp * Sample ) updateCronjobV1DueForce () {
@@ -790,3 +791,119 @@ func (sp *Sample) CodeGen() {
790791 err = sp .ctx .EditHelmPlugin ()
791792 hackutils .CheckError ("Failed to enable helm plugin" , err )
792793}
794+
795+ const webhookConversionE2ETest = `
796+ It("should successfully convert between v1 and v2 versions", func() {
797+ By("waiting for the webhook service to be ready")
798+ Eventually(func(g Gomega) {
799+ cmd := exec.Command("kubectl", "get", "endpoints", "-n", namespace,
800+ "-l", "control-plane=controller-manager",
801+ "-o", "jsonpath={.items[0].subsets[0].addresses[0].ip}")
802+ output, err := utils.Run(cmd)
803+ g.Expect(err).NotTo(HaveOccurred(), "Failed to get webhook service endpoints")
804+ g.Expect(strings.TrimSpace(output)).NotTo(BeEmpty(), "Webhook endpoint should have an IP")
805+ }, time.Minute, time.Second).Should(Succeed())
806+
807+ By("creating a v1 CronJob with a specific schedule")
808+ cmd := exec.Command("kubectl", "apply", "-f", "config/samples/batch_v1_cronjob.yaml", "-n", namespace)
809+ _, err := utils.Run(cmd)
810+ Expect(err).NotTo(HaveOccurred(), "Failed to create v1 CronJob")
811+
812+ By("waiting for the v1 CronJob to be created")
813+ Eventually(func(g Gomega) {
814+ cmd := exec.Command("kubectl", "get", "cronjob.batch.tutorial.kubebuilder.io", "cronjob-sample", "-n", namespace)
815+ output, err := utils.Run(cmd)
816+ if err != nil {
817+ // Log controller logs on failure for debugging
818+ logCmd := exec.Command("kubectl", "logs", "-l", "control-plane=controller-manager", "-n", namespace, "--tail=50")
819+ logs, _ := utils.Run(logCmd)
820+ _, _ = fmt.Fprintf(GinkgoWriter, "Controller logs when CronJob not found:\n%s\n", logs)
821+ }
822+ g.Expect(err).NotTo(HaveOccurred(), "v1 CronJob should exist, output: "+output)
823+ }, time.Minute, time.Second).Should(Succeed())
824+
825+ By("fetching the v1 CronJob and verifying the schedule format")
826+ cmd = exec.Command("kubectl", "get", "cronjob.v1.batch.tutorial.kubebuilder.io", "cronjob-sample",
827+ "-n", namespace, "-o", "jsonpath={.spec.schedule}")
828+ v1Schedule, err := utils.Run(cmd)
829+ Expect(err).NotTo(HaveOccurred(), "Failed to get v1 CronJob schedule")
830+ Expect(strings.TrimSpace(v1Schedule)).To(Equal("*/1 * * * *"),
831+ "v1 schedule should be in cron format")
832+
833+ By("fetching the same CronJob as v2 and verifying the converted schedule")
834+ Eventually(func(g Gomega) {
835+ cmd := exec.Command("kubectl", "get", "cronjob.v2.batch.tutorial.kubebuilder.io", "cronjob-sample",
836+ "-n", namespace, "-o", "jsonpath={.spec.schedule.minute}")
837+ v2Minute, err := utils.Run(cmd)
838+ g.Expect(err).NotTo(HaveOccurred(), "Failed to get v2 CronJob schedule")
839+ g.Expect(strings.TrimSpace(v2Minute)).To(Equal("*/1"),
840+ "v2 schedule.minute should be converted from v1 schedule")
841+ }, time.Minute, time.Second).Should(Succeed())
842+
843+ By("creating a v2 CronJob with structured schedule fields")
844+ cmd = exec.Command("kubectl", "apply", "-f", "config/samples/batch_v2_cronjob.yaml", "-n", namespace)
845+ _, err = utils.Run(cmd)
846+ Expect(err).NotTo(HaveOccurred(), "Failed to create v2 CronJob")
847+
848+ By("verifying the v2 CronJob has the correct structured schedule")
849+ Eventually(func(g Gomega) {
850+ cmd := exec.Command("kubectl", "get", "cronjob.v2.batch.tutorial.kubebuilder.io", "cronjob-sample",
851+ "-n", namespace, "-o", "jsonpath={.spec.schedule.minute}")
852+ v2Minute, err := utils.Run(cmd)
853+ g.Expect(err).NotTo(HaveOccurred(), "Failed to get v2 CronJob schedule")
854+ g.Expect(strings.TrimSpace(v2Minute)).To(Equal("*/1"),
855+ "v2 CronJob should have minute field set")
856+ }, time.Minute, time.Second).Should(Succeed())
857+
858+ By("fetching the v2 CronJob as v1 and verifying schedule conversion")
859+ Eventually(func(g Gomega) {
860+ cmd := exec.Command("kubectl", "get", "cronjob.v1.batch.tutorial.kubebuilder.io", "cronjob-sample",
861+ "-n", namespace, "-o", "jsonpath={.spec.schedule}")
862+ v1Schedule, err := utils.Run(cmd)
863+ g.Expect(err).NotTo(HaveOccurred(), "Failed to get converted v1 schedule")
864+ // When v2 only has minute field set, it converts to "*/1 * * * *"
865+ g.Expect(strings.TrimSpace(v1Schedule)).To(Equal("*/1 * * * *"),
866+ "v1 schedule should be converted from v2 structured schedule")
867+ }, time.Minute, time.Second).Should(Succeed())
868+ })`
869+
870+ func (sp * Sample ) updateE2EWebhookConversion () {
871+ cronjobE2ETest := filepath .Join (sp .ctx .Dir , "test" , "e2e" , "e2e_test.go" )
872+
873+ // Add strings import if not already present
874+ err := pluginutil .InsertCodeIfNotExist (cronjobE2ETest ,
875+ ` "os/exec"
876+ "path/filepath"
877+ "time"` ,
878+ `
879+ "strings"` )
880+ hackutils .CheckError ("adding strings import for e2e test" , err )
881+
882+ // Add CronJob cleanup to the AfterEach block
883+ err = pluginutil .InsertCode (cronjobE2ETest ,
884+ ` // After each test, check for failures and collect logs, events,
885+ // and pod descriptions for debugging.
886+ AfterEach(func() {` ,
887+ `
888+ By("Cleaning up test CronJob resources")
889+ cmd := exec.Command("kubectl", "delete", "-f", "config/samples/batch_v1_cronjob.yaml", "-n", namespace, "--ignore-not-found=true")
890+ _, _ = utils.Run(cmd)
891+ cmd = exec.Command("kubectl", "delete", "-f", "config/samples/batch_v2_cronjob.yaml", "-n", namespace, "--ignore-not-found=true")
892+ _, _ = utils.Run(cmd)
893+ ` )
894+ hackutils .CheckError ("adding CronJob cleanup to AfterEach" , err )
895+
896+ // Add webhook conversion test after the existing TODO comment
897+ err = pluginutil .InsertCode (cronjobE2ETest ,
898+ ` // TODO: Customize the e2e test suite with scenarios specific to your project.
899+ // Consider applying sample/CR(s) and check their status and/or verifying
900+ // the reconciliation by using the metrics, i.e.:
901+ // metricsOutput, err := getMetricsOutput()
902+ // Expect(err).NotTo(HaveOccurred(), "Failed to retrieve logs from curl pod")
903+ // Expect(metricsOutput).To(ContainSubstring(
904+ // fmt.Sprintf(` + "`" + `controller_runtime_reconcile_total{controller="%s",result="success"} 1` + "`" + `,
905+ // strings.ToLower(<Kind>),
906+ // ))` ,
907+ webhookConversionE2ETest )
908+ hackutils .CheckError ("adding webhook conversion e2e test" , err )
909+ }
0 commit comments