@@ -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,113 @@ 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", "cronjob-sample", "-n", namespace)
815+ _, err := utils.Run(cmd)
816+ g.Expect(err).NotTo(HaveOccurred(), "v1 CronJob should exist")
817+ }, time.Minute, time.Second).Should(Succeed())
818+
819+ By("fetching the v1 CronJob and verifying the schedule format")
820+ cmd = exec.Command("kubectl", "get", "cronjob.v1.batch.tutorial.kubebuilder.io", "cronjob-sample",
821+ "-n", namespace, "-o", "jsonpath={.spec.schedule}")
822+ v1Schedule, err := utils.Run(cmd)
823+ Expect(err).NotTo(HaveOccurred(), "Failed to get v1 CronJob schedule")
824+ Expect(strings.TrimSpace(v1Schedule)).To(Equal("*/1 * * * *"),
825+ "v1 schedule should be in cron format")
826+
827+ By("fetching the same CronJob as v2 and verifying the converted schedule")
828+ Eventually(func(g Gomega) {
829+ cmd := exec.Command("kubectl", "get", "cronjob.v2.batch.tutorial.kubebuilder.io", "cronjob-sample",
830+ "-n", namespace, "-o", "jsonpath={.spec.schedule.minute}")
831+ v2Minute, err := utils.Run(cmd)
832+ g.Expect(err).NotTo(HaveOccurred(), "Failed to get v2 CronJob schedule")
833+ g.Expect(strings.TrimSpace(v2Minute)).To(Equal("*/1"),
834+ "v2 schedule.minute should be converted from v1 schedule")
835+ }, time.Minute, time.Second).Should(Succeed())
836+
837+ By("creating a v2 CronJob with structured schedule fields")
838+ cmd = exec.Command("kubectl", "apply", "-f", "config/samples/batch_v2_cronjob.yaml", "-n", namespace)
839+ _, err = utils.Run(cmd)
840+ Expect(err).NotTo(HaveOccurred(), "Failed to create v2 CronJob")
841+
842+ By("verifying the v2 CronJob has the correct structured schedule")
843+ Eventually(func(g Gomega) {
844+ cmd := exec.Command("kubectl", "get", "cronjob.v2.batch.tutorial.kubebuilder.io", "cronjob-sample",
845+ "-n", namespace, "-o", "jsonpath={.spec.schedule.minute}")
846+ v2Minute, err := utils.Run(cmd)
847+ g.Expect(err).NotTo(HaveOccurred(), "Failed to get v2 CronJob schedule")
848+ g.Expect(strings.TrimSpace(v2Minute)).To(Equal("*/1"),
849+ "v2 CronJob should have minute field set")
850+ }, time.Minute, time.Second).Should(Succeed())
851+
852+ By("fetching the v2 CronJob as v1 and verifying schedule conversion")
853+ Eventually(func(g Gomega) {
854+ cmd := exec.Command("kubectl", "get", "cronjob.v1.batch.tutorial.kubebuilder.io", "cronjob-sample",
855+ "-n", namespace, "-o", "jsonpath={.spec.schedule}")
856+ v1Schedule, err := utils.Run(cmd)
857+ g.Expect(err).NotTo(HaveOccurred(), "Failed to get converted v1 schedule")
858+ // When v2 only has minute field set, it converts to "*/1 * * * *"
859+ g.Expect(strings.TrimSpace(v1Schedule)).To(Equal("*/1 * * * *"),
860+ "v1 schedule should be converted from v2 structured schedule")
861+ }, time.Minute, time.Second).Should(Succeed())
862+ })`
863+
864+ func (sp * Sample ) updateE2EWebhookConversion () {
865+ cronjobE2ETest := filepath .Join (sp .ctx .Dir , "test" , "e2e" , "e2e_test.go" )
866+
867+ // Add strings import if not already present
868+ err := pluginutil .InsertCodeIfNotExist (cronjobE2ETest ,
869+ ` "os/exec"
870+ "path/filepath"
871+ "time"` ,
872+ `
873+ "strings"` )
874+ hackutils .CheckError ("adding strings import for e2e test" , err )
875+
876+ // Add CronJob cleanup to the AfterEach block
877+ err = pluginutil .InsertCode (cronjobE2ETest ,
878+ ` // After each test, check for failures and collect logs, events,
879+ // and pod descriptions for debugging.
880+ AfterEach(func() {` ,
881+ `
882+ By("Cleaning up test CronJob resources")
883+ cmd := exec.Command("kubectl", "delete", "-f", "config/samples/batch_v1_cronjob.yaml", "-n", namespace, "--ignore-not-found=true")
884+ _, _ = utils.Run(cmd)
885+ cmd = exec.Command("kubectl", "delete", "-f", "config/samples/batch_v2_cronjob.yaml", "-n", namespace, "--ignore-not-found=true")
886+ _, _ = utils.Run(cmd)
887+ ` )
888+ hackutils .CheckError ("adding CronJob cleanup to AfterEach" , err )
889+
890+ // Add webhook conversion test after the existing TODO comment
891+ err = pluginutil .InsertCode (cronjobE2ETest ,
892+ ` // TODO: Customize the e2e test suite with scenarios specific to your project.
893+ // Consider applying sample/CR(s) and check their status and/or verifying
894+ // the reconciliation by using the metrics, i.e.:
895+ // metricsOutput, err := getMetricsOutput()
896+ // Expect(err).NotTo(HaveOccurred(), "Failed to retrieve logs from curl pod")
897+ // Expect(metricsOutput).To(ContainSubstring(
898+ // fmt.Sprintf(` + "`" + `controller_runtime_reconcile_total{controller="%s",result="success"} 1` + "`" + `,
899+ // strings.ToLower(<Kind>),
900+ // ))` ,
901+ webhookConversionE2ETest )
902+ hackutils .CheckError ("adding webhook conversion e2e test" , err )
903+ }
0 commit comments