@@ -25,6 +25,7 @@ import (
2525 "os"
2626 "os/exec"
2727 "path/filepath"
28+ "strings"
2829 "time"
2930
3031 . "github.com/onsi/ginkgo/v2"
@@ -178,9 +179,14 @@ var _ = Describe("Manager", Ordered, func() {
178179 cmd := exec .Command ("kubectl" , "create" , "clusterrolebinding" , metricsRoleBindingName ,
179180 "--clusterrole=project-metrics-reader" ,
180181 fmt .Sprintf ("--serviceaccount=%s:%s" , namespace , serviceAccountName ),
181- )
182- _ , err := utils .Run (cmd )
183- Expect (err ).NotTo (HaveOccurred (), "Failed to create ClusterRoleBinding" )
182+ "--dry-run=client" , "-o" , "yaml" )
183+ output , err := utils .Run (cmd )
184+ Expect (err ).NotTo (HaveOccurred (), "Failed to generate ClusterRoleBinding YAML" )
185+
186+ cmd = exec .Command ("kubectl" , "apply" , "-f" , "-" )
187+ cmd .Stdin = strings .NewReader (output )
188+ _ , err = utils .Run (cmd )
189+ Expect (err ).NotTo (HaveOccurred (), "Failed to apply ClusterRoleBinding" )
184190
185191 By ("validating that the metrics service is available" )
186192 cmd = exec .Command ("kubectl" , "get" , "service" , metricsServiceName , "-n" , namespace )
@@ -319,7 +325,74 @@ var _ = Describe("Manager", Ordered, func() {
319325
320326 // +kubebuilder:scaffold:e2e-webhooks-checks
321327
322- // TODO: Customize the e2e test suite with scenarios specific to your project.
328+ It ("should validate webhook conversion between v1 and v2 CronJob versions" , func () {
329+ By ("applying the v1 CronJob sample" )
330+ cmd := exec .Command ("kubectl" , "apply" , "-f" , "config/samples/batch_v1_cronjob.yaml" , "-n" , namespace )
331+ _ , err := utils .Run (cmd )
332+ Expect (err ).NotTo (HaveOccurred (), "Failed to apply v1 CronJob sample" )
333+
334+ By ("verifying the v1 CronJob is stored properly" )
335+ Eventually (func (g Gomega ) {
336+ cmd := exec .Command ("kubectl" , "get" , "cronjob.batch.tutorial.kubebuilder.io" , "cronjob-sample" , "-n" , namespace , "-o" , "json" )
337+ output , err := utils .Run (cmd )
338+ g .Expect (err ).NotTo (HaveOccurred ())
339+
340+ var v1CronJob map [string ]interface {}
341+ err = json .Unmarshal ([]byte (output ), & v1CronJob )
342+ g .Expect (err ).NotTo (HaveOccurred ())
343+
344+ // Get spec and verify the schedule field exists
345+ v1Spec , ok := v1CronJob ["spec" ].(map [string ]interface {})
346+ g .Expect (ok ).To (BeTrue (), "Failed to get spec from v1 CronJob" )
347+ g .Expect (v1Spec ["schedule" ]).NotTo (BeNil (), "Schedule field should exist in v1 CronJob" )
348+ }).Should (Succeed ())
349+
350+ By ("deleting the v1 CronJob sample" )
351+ cmd = exec .Command ("kubectl" , "delete" , "-f" , "config/samples/batch_v1_cronjob.yaml" , "-n" , namespace , "--ignore-not-found" )
352+ _ , _ = utils .Run (cmd )
353+
354+ By ("applying the v2 CronJob sample" )
355+ cmd = exec .Command ("kubectl" , "apply" , "-f" , "config/samples/batch_v2_cronjob.yaml" , "-n" , namespace )
356+ _ , err = utils .Run (cmd )
357+ Expect (err ).NotTo (HaveOccurred (), "Failed to apply v2 CronJob sample" )
358+
359+ By ("verifying the v2 CronJob is stored properly" )
360+ Eventually (func (g Gomega ) {
361+ cmd := exec .Command ("kubectl" , "get" , "cronjob.batch.tutorial.kubebuilder.io" , "cronjob-sample" , "-n" , namespace , "-o" , "json" )
362+ output , err := utils .Run (cmd )
363+ g .Expect (err ).NotTo (HaveOccurred ())
364+
365+ var v2CronJob map [string ]interface {}
366+ err = json .Unmarshal ([]byte (output ), & v2CronJob )
367+ g .Expect (err ).NotTo (HaveOccurred ())
368+
369+ // Get spec and verify the schedule field exists
370+ v2Spec , ok := v2CronJob ["spec" ].(map [string ]interface {})
371+ g .Expect (ok ).To (BeTrue (), "Failed to get spec from v2 CronJob" )
372+ g .Expect (v2Spec ["schedule" ]).NotTo (BeNil (), "Schedule field should exist in v2 CronJob" )
373+ }).Should (Succeed ())
374+
375+ By ("verifying conversion webhook was called by checking controller logs" )
376+ Eventually (func (g Gomega ) {
377+ cmd := exec .Command ("kubectl" , "logs" , controllerPodName , "-n" , namespace )
378+ logs , err := utils .Run (cmd )
379+ g .Expect (err ).NotTo (HaveOccurred ())
380+
381+ // Verify that conversion webhook was actually called
382+ g .Expect (logs ).To (ContainSubstring ("ConvertTo:" ), "Expected to find ConvertTo log indicating conversion webhook was called" )
383+ g .Expect (logs ).To (ContainSubstring ("ConvertFrom:" ), "Expected to find ConvertFrom log indicating conversion webhook was called" )
384+
385+ // Verify that conversion is happening between the versions
386+ g .Expect (logs ).To (ContainSubstring ("Converting CronJob from Hub version v1 to Spoke version v2" ),
387+ "Expected v1 to v2 conversion" )
388+ g .Expect (logs ).To (ContainSubstring ("Converting CronJob from Spoke version v2 to Hub version v1" ),
389+ "Expected v2 to v1 conversion" )
390+ }).Should (Succeed ())
391+
392+ By ("cleaning up the v2 CronJob sample" )
393+ cmd = exec .Command ("kubectl" , "delete" , "-f" , "config/samples/batch_v2_cronjob.yaml" , "-n" , namespace , "--ignore-not-found" )
394+ _ , _ = utils .Run (cmd )
395+ })
323396 // Consider applying sample/CR(s) and check their status and/or verifying
324397 // the reconciliation by using the metrics, i.e.:
325398 // metricsOutput := getMetricsOutput()
0 commit comments