Skip to content

Commit 2891ee8

Browse files
committed
feat: add e2e test to validate webhook conversion between versions
1 parent 72d4edb commit 2891ee8

File tree

2 files changed

+165
-0
lines changed

2 files changed

+165
-0
lines changed

docs/book/src/multiversion-tutorial/testdata/project/test/e2e/e2e_test.go

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626
"os/exec"
2727
"path/filepath"
2828
"time"
29+
"strings"
2930

3031
. "github.com/onsi/ginkgo/v2"
3132
. "github.com/onsi/gomega"
@@ -97,6 +98,12 @@ var _ = Describe("Manager", Ordered, func() {
9798
// After each test, check for failures and collect logs, events,
9899
// and pod descriptions for debugging.
99100
AfterEach(func() {
101+
By("Cleaning up test CronJob resources")
102+
cmd := exec.Command("kubectl", "delete", "-f", "config/samples/batch_v1_cronjob.yaml", "-n", namespace, "--ignore-not-found=true")
103+
_, _ = utils.Run(cmd)
104+
cmd = exec.Command("kubectl", "delete", "-f", "config/samples/batch_v2_cronjob.yaml", "-n", namespace, "--ignore-not-found=true")
105+
_, _ = utils.Run(cmd)
106+
100107
specReport := CurrentSpecReport()
101108
if specReport.Failed() {
102109
By("Fetching controller manager pod logs")
@@ -331,6 +338,63 @@ var _ = Describe("Manager", Ordered, func() {
331338
// fmt.Sprintf(`controller_runtime_reconcile_total{controller="%s",result="success"} 1`,
332339
// strings.ToLower(<Kind>),
333340
// ))
341+
It("should successfully convert between v1 and v2 versions", func() {
342+
By("creating a v1 CronJob with a specific schedule")
343+
cmd := exec.Command("kubectl", "apply", "-f", "config/samples/batch_v1_cronjob.yaml", "-n", namespace)
344+
_, err := utils.Run(cmd)
345+
Expect(err).NotTo(HaveOccurred(), "Failed to create v1 CronJob")
346+
347+
By("waiting for the v1 CronJob to be created")
348+
Eventually(func(g Gomega) {
349+
cmd := exec.Command("kubectl", "get", "cronjob", "cronjob-sample", "-n", namespace)
350+
_, err := utils.Run(cmd)
351+
g.Expect(err).NotTo(HaveOccurred(), "v1 CronJob should exist")
352+
}, time.Minute, time.Second).Should(Succeed())
353+
354+
By("fetching the v1 CronJob and verifying the schedule format")
355+
cmd = exec.Command("kubectl", "get", "cronjob.v1.batch.tutorial.kubebuilder.io", "cronjob-sample",
356+
"-n", namespace, "-o", "jsonpath={.spec.schedule}")
357+
v1Schedule, err := utils.Run(cmd)
358+
Expect(err).NotTo(HaveOccurred(), "Failed to get v1 CronJob schedule")
359+
Expect(strings.TrimSpace(v1Schedule)).To(Equal("*/1 * * * *"),
360+
"v1 schedule should be in cron format")
361+
362+
By("fetching the same CronJob as v2 and verifying the converted schedule")
363+
Eventually(func(g Gomega) {
364+
cmd := exec.Command("kubectl", "get", "cronjob.v2.batch.tutorial.kubebuilder.io", "cronjob-sample",
365+
"-n", namespace, "-o", "jsonpath={.spec.schedule.minute}")
366+
v2Minute, err := utils.Run(cmd)
367+
g.Expect(err).NotTo(HaveOccurred(), "Failed to get v2 CronJob schedule")
368+
g.Expect(strings.TrimSpace(v2Minute)).To(Equal("*/1"),
369+
"v2 schedule.minute should be converted from v1 schedule")
370+
}, time.Minute, time.Second).Should(Succeed())
371+
372+
By("creating a v2 CronJob with structured schedule fields")
373+
cmd = exec.Command("kubectl", "apply", "-f", "config/samples/batch_v2_cronjob.yaml", "-n", namespace)
374+
_, err = utils.Run(cmd)
375+
Expect(err).NotTo(HaveOccurred(), "Failed to create v2 CronJob")
376+
377+
By("verifying the v2 CronJob has the correct structured schedule")
378+
Eventually(func(g Gomega) {
379+
cmd := exec.Command("kubectl", "get", "cronjob.v2.batch.tutorial.kubebuilder.io", "cronjob-sample",
380+
"-n", namespace, "-o", "jsonpath={.spec.schedule.minute}")
381+
v2Minute, err := utils.Run(cmd)
382+
g.Expect(err).NotTo(HaveOccurred(), "Failed to get v2 CronJob schedule")
383+
g.Expect(strings.TrimSpace(v2Minute)).To(Equal("*/1"),
384+
"v2 CronJob should have minute field set")
385+
}, time.Minute, time.Second).Should(Succeed())
386+
387+
By("fetching the v2 CronJob as v1 and verifying schedule conversion")
388+
Eventually(func(g Gomega) {
389+
cmd := exec.Command("kubectl", "get", "cronjob.v1.batch.tutorial.kubebuilder.io", "cronjob-sample",
390+
"-n", namespace, "-o", "jsonpath={.spec.schedule}")
391+
v1Schedule, err := utils.Run(cmd)
392+
g.Expect(err).NotTo(HaveOccurred(), "Failed to get converted v1 schedule")
393+
// When v2 only has minute field set, it converts to "*/1 * * * *"
394+
g.Expect(strings.TrimSpace(v1Schedule)).To(Equal("*/1 * * * *"),
395+
"v1 schedule should be converted from v2 structured schedule")
396+
}, time.Minute, time.Second).Should(Succeed())
397+
})
334398
})
335399
})
336400

hack/docs/internal/multiversion-tutorial/generate_multiversion.go

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ func (sp *Sample) UpdateTutorial() {
111111
sp.updateConversionFiles()
112112
sp.updateSampleV2()
113113
sp.updateMain()
114+
sp.updateE2EWebhookConversion()
114115
}
115116

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

0 commit comments

Comments
 (0)