in oracle/controllers/testhelpers/envtest.go [152:289]
func RunFunctionalTestSuiteWithWebhooks(
t *testing.T,
k8sClient *client.Client,
k8sManager *ctrl.Manager,
schemeBuilders []*runtime.SchemeBuilder,
description string,
controllers func() []Reconciler,
crdPaths []string,
webhooks func() []Webhook,
admissionWebhookHandlers func() map[string]AdmissionWebhook,
webhookPaths []string,
) {
// Define the test environment.
crdPaths = append(crdPaths, filepath.Join("config", "crd", "bases"), filepath.Join("config", "crd", "testing"))
var testEnvLock sync.Mutex
testEnv := envtest.Environment{
CRDDirectoryPaths: crdPaths,
ControlPlaneStartTimeout: 60 * time.Second, // Default 20s may not be enough for test pods.
}
// Set up webhooks
if len(webhookPaths) != 0 {
testEnv.WebhookInstallOptions = envtest.WebhookInstallOptions{
Paths: webhookPaths,
IgnoreErrorIfPathMissing: true,
}
}
if runfiles, err := bazel.RunfilesPath(); err == nil {
// Running with bazel test, find binary assets in runfiles.
testEnv.BinaryAssetsDirectory = filepath.Join(runfiles, "external/kubebuilder_tools/bin")
}
// k8s 1.21 introduced graceful shutdown so testEnv wont shutdown if we
// keep a connection open. By using a context with cancel we can
// shutdown our managers before we try to shutdown the testEnv and
// ensure no hanging connections keep the apiserver from stopping.
mgrCtx, mgrCancel := context.WithCancel(ctrl.SetupSignalHandler())
BeforeSuite(func(done Done) {
testEnvLock.Lock()
defer testEnvLock.Unlock()
klog.SetOutput(GinkgoWriter)
logf.SetLogger(klogr.NewWithOptions(klogr.WithFormat(klogr.FormatKlog)))
log := logf.FromContext(nil)
var err error
var cfg *rest.Config
var backoff = wait.Backoff{
Steps: 6,
Duration: 100 * time.Millisecond,
Factor: 5.0,
Jitter: 0.1,
}
Expect(retry.OnError(backoff, func(error) bool { return true }, func() error {
cfg, err = testEnv.Start()
if err != nil {
log.Error(err, "Envtest startup failed, retrying")
}
return err
})).Should(Succeed())
for _, sb := range schemeBuilders {
utilruntime.Must(sb.AddToScheme(scheme.Scheme))
}
if len(webhookPaths) != 0 {
// start webhook server using Manager
webhookInstallOptions := &testEnv.WebhookInstallOptions
*k8sManager, err = ctrl.NewManager(cfg, ctrl.Options{
Scheme: scheme.Scheme,
Host: webhookInstallOptions.LocalServingHost,
Port: webhookInstallOptions.LocalServingPort,
CertDir: webhookInstallOptions.LocalServingCertDir,
LeaderElection: false,
MetricsBindAddress: "0",
})
Expect(err).NotTo(HaveOccurred())
} else {
*k8sManager, err = ctrl.NewManager(cfg, ctrl.Options{
Scheme: scheme.Scheme,
MetricsBindAddress: "0",
})
Expect(err).ToNot(HaveOccurred())
}
*k8sClient = (*k8sManager).GetClient()
// Install controllers into the manager.
for _, c := range controllers() {
Expect(c.SetupWithManager(*k8sManager)).To(Succeed())
}
// Install webhooks into the manager.
for _, c := range webhooks() {
Expect(c.SetupWebhookWithManager(*k8sManager)).To(Succeed())
}
// Register admission webhook handlers into the webhook in the manager
for path, handler := range admissionWebhookHandlers() {
(*k8sManager).GetWebhookServer().Register(path, handler)
}
go func() {
defer GinkgoRecover()
err = (*k8sManager).Start(mgrCtx)
Expect(err).ToNot(HaveOccurred())
}()
if len(webhookPaths) != 0 {
// wait for the webhook server to get ready
webhookInstallOptions := &testEnv.WebhookInstallOptions
dialer := &net.Dialer{Timeout: 60 * 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
}
conn.Close()
return nil
}, 60*time.Second, 5*time.Second).Should(Succeed())
}
close(done)
}, 600)
AfterSuite(func() {
testEnvLock.Lock()
defer testEnvLock.Unlock()
By("Stopping control plane")
mgrCancel()
Expect(testEnv.Stop()).To(Succeed())
})
RegisterFailHandler(Fail)
RunSpecsWithDefaultAndCustomReporters(t,
description,
[]Reporter{printer.NewlineReporter{}})
}