package v1alpha1 import ( "context" "crypto/tls" "fmt" "net" "os" "path/filepath" "testing" "time" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "go.uber.org/zap/zapcore" certmanagerv1 "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1" monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1" admissionv1 "k8s.io/api/admission/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/utils/ptr" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/envtest" log "sigs.k8s.io/controller-runtime/pkg/log" logf "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/log/zap" metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server" "sigs.k8s.io/controller-runtime/pkg/webhook" "github.com/mariadb-operator/mariadb-operator/api/v1alpha1" // +kubebuilder:scaffold:imports ) var ( ctx context.Context cancel context.CancelFunc k8sClient client.Client testEnv *envtest.Environment testCtx = context.Background() testNamespace = "default" ) func TestAPIs(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "Webhook Suite") } var _ = BeforeSuite(func() { log.SetLogger(zap.New( zap.WriteTo(GinkgoWriter), zap.UseDevMode(true), zap.Level(zapcore.InfoLevel), )) ctx, cancel = context.WithCancel(context.TODO()) var err error scheme := runtime.NewScheme() err = v1alpha1.AddToScheme(scheme) Expect(err).NotTo(HaveOccurred()) Expect(admissionv1.AddToScheme(scheme)).NotTo(HaveOccurred()) Expect(monitoringv1.AddToScheme(scheme)).NotTo(HaveOccurred()) Expect(certmanagerv1.AddToScheme(scheme)).NotTo(HaveOccurred()) // +kubebuilder:scaffold:scheme By("Bootstrapping test environment") testEnv = &envtest.Environment{ CRDDirectoryPaths: []string{filepath.Join("..", "..", "..", "config", "crd", "bases")}, ErrorIfCRDPathMissing: false, WebhookInstallOptions: envtest.WebhookInstallOptions{ Paths: []string{filepath.Join("..", "..", "..", "config", "webhook")}, }, UseExistingCluster: ptr.To(false), } // Retrieve the first found binary directory to allow running tests from IDEs if getFirstFoundEnvTestBinaryDir() != "" { testEnv.BinaryAssetsDirectory = getFirstFoundEnvTestBinaryDir() } cfg, err := testEnv.Start() Expect(err).NotTo(HaveOccurred()) Expect(cfg).NotTo(BeNil()) DeferCleanup(testEnv.Stop) k8sClient, err = client.New(cfg, client.Options{Scheme: scheme}) Expect(err).NotTo(HaveOccurred()) Expect(k8sClient).NotTo(BeNil()) webhookInstallOptions := &testEnv.WebhookInstallOptions mgr, err := ctrl.NewManager(cfg, ctrl.Options{ Scheme: scheme, LeaderElection: false, Metrics: metricsserver.Options{ BindAddress: "0", }, WebhookServer: webhook.NewServer(webhook.Options{ Host: webhookInstallOptions.LocalServingHost, Port: webhookInstallOptions.LocalServingPort, CertDir: webhookInstallOptions.LocalServingCertDir, }), }) Expect(err).NotTo(HaveOccurred()) err = SetupMariaDBWebhookWithManager(mgr) Expect(err).NotTo(HaveOccurred()) err = SetupMaxScaleWebhookWithManager(mgr) Expect(err).NotTo(HaveOccurred()) err = SetupBackupWebhookWithManager(mgr) Expect(err).NotTo(HaveOccurred()) err = SetupPhysicalBackupWebhookWithManager(mgr) Expect(err).NotTo(HaveOccurred()) err = SetupRestoreWebhookWithManager(mgr) Expect(err).NotTo(HaveOccurred()) err = SetupConnectionWebhookWithManager(mgr) Expect(err).NotTo(HaveOccurred()) err = SetupUserWebhookWithManager(mgr) Expect(err).NotTo(HaveOccurred()) err = SetupGrantWebhookWithManager(mgr) Expect(err).NotTo(HaveOccurred()) err = SetupDatabaseWebhookWithManager(mgr) Expect(err).NotTo(HaveOccurred()) err = SetupSqlJobWebhookWithManager(mgr) Expect(err).NotTo(HaveOccurred()) // +kubebuilder:scaffold:webhook go func() { defer GinkgoRecover() err = mgr.Start(ctx) Expect(err).NotTo(HaveOccurred()) }() // wait for the webhook server to get ready. dialer := &net.Dialer{Timeout: time.Second} addrPort := fmt.Sprintf("%s:%d", webhookInstallOptions.LocalServingHost, webhookInstallOptions.LocalServingPort) Eventually(func() error { conn, err := tls.DialWithDialer(dialer, "tcp", addrPort, &tls.Config{InsecureSkipVerify: true}) if err != nil { return err } return conn.Close() }).Should(Succeed()) }) var _ = AfterSuite(func() { By("tearing down the test environment") cancel() err := testEnv.Stop() Expect(err).NotTo(HaveOccurred()) }) // getFirstFoundEnvTestBinaryDir locates the first binary in the specified path. // ENVTEST-based tests depend on specific binaries, usually located in paths set by // controller-runtime. When running tests directly (e.g., via an IDE) without using // Makefile targets, the 'BinaryAssetsDirectory' must be explicitly configured. // // This function streamlines the process by finding the required binaries, similar to // setting the 'KUBEBUILDER_ASSETS' environment variable. To ensure the binaries are // properly set up, run 'make setup-envtest' beforehand. func getFirstFoundEnvTestBinaryDir() string { basePath := filepath.Join("..", "..", "..", "bin", "k8s") entries, err := os.ReadDir(basePath) if err != nil { logf.Log.Error(err, "Failed to read directory", "path", basePath) return "" } for _, entry := range entries { if entry.IsDir() { return filepath.Join(basePath, entry.Name()) } } return "" }