This repository is currently being migrated. It's locked while the migration is in progress.
-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
added validation webhook test (#201)
So far focusing just on StorageOSCluster.Spec.Metrics
- Loading branch information
Michal Minář
authored
Jun 30, 2022
1 parent
208295e
commit af2e6fe
Showing
2 changed files
with
239 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
package webhook_test | ||
|
||
import ( | ||
"context" | ||
|
||
. "github.com/onsi/ginkgo" | ||
. "github.com/onsi/gomega" | ||
|
||
apierrors "k8s.io/apimachinery/pkg/api/errors" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
"k8s.io/apimachinery/pkg/runtime/schema" | ||
"k8s.io/apimachinery/pkg/util/validation/field" | ||
|
||
metricsv1 "github.com/ondat/metrics-exporter/api/config.storageos.com/v1" | ||
storageoscomv1 "github.com/storageos/operator/api/v1" | ||
) | ||
|
||
const clusterName = "storageoscluster" | ||
|
||
var _ = Describe("StorageOSCluster Validating Webhook", func() { | ||
var cluster storageoscomv1.StorageOSCluster | ||
BeforeEach(func() { | ||
cluster = storageoscomv1.StorageOSCluster{ | ||
ObjectMeta: metav1.ObjectMeta{ | ||
Namespace: namespace, | ||
Name: clusterName, | ||
}, | ||
Spec: storageoscomv1.StorageOSClusterSpec{ | ||
Metrics: storageoscomv1.Metrics{ | ||
Enabled: true, | ||
}, | ||
}, | ||
} | ||
}) | ||
|
||
AfterEach(func() { | ||
cluster = storageoscomv1.StorageOSCluster{ | ||
ObjectMeta: metav1.ObjectMeta{ | ||
Namespace: namespace, | ||
Name: clusterName, | ||
}, | ||
} | ||
err := k8sClient.Delete(context.TODO(), &cluster) | ||
// to satisfy our linter | ||
Expect(err).To(Or(HaveOccurred(), Not(HaveOccurred()))) | ||
}) | ||
|
||
Context("When the .spec.metrics is invalid", func() { | ||
It("refuses invalid .logLevel", func() { | ||
cluster.Spec.Metrics.LogLevel = "foo" | ||
Expect(k8sClient.Create(context.TODO(), &cluster)). | ||
To(MatchError( | ||
newInvalidError(field.NotSupported(field.NewPath("spec.metrics.logLevel"), | ||
"foo", []string{"debug", "info", "warn", "error", "dpanic", "panic", "fatal"})))) | ||
}) | ||
|
||
It("refuses invalid .timeout", func() { | ||
cluster.Spec.Metrics.Timeout = -1 | ||
err := k8sClient.Create(context.TODO(), &cluster) | ||
Expect(err).To(HaveOccurred()) | ||
Expect(err.Error()).To(MatchRegexp("spec.metrics.timeout.*should be greater than.*1")) | ||
}) | ||
|
||
It("refuses invalid .disabledCollectors", func() { | ||
cluster.Spec.Metrics.DisabledCollectors = []metricsv1.MetricsExporterCollector{ | ||
metricsv1.MetricsExporterCollector("bad"), | ||
} | ||
Expect(k8sClient.Create(context.TODO(), &cluster)). | ||
To(MatchError(newInvalidError(field.NotSupported( | ||
field.NewPath("spec.metrics.disabledCollectors"), "bad", []string{ | ||
"diskstats", | ||
"filesystem", | ||
})))) | ||
}) | ||
}) | ||
|
||
Context("When the .spec.metrics is valid", func() { | ||
It("should accept it", func() { | ||
cluster.Spec.Metrics.LogLevel = "debug" | ||
cluster.Spec.Metrics.Timeout = 1 | ||
cluster.Spec.Metrics.DisabledCollectors = []metricsv1.MetricsExporterCollector{ | ||
metricsv1.MetricsExporterCollectorDiskStats, | ||
} | ||
Expect(k8sClient.Create(context.TODO(), &cluster)).NotTo(HaveOccurred()) | ||
}) | ||
}) | ||
|
||
Context("When the .spec.metrics are empty", func() { | ||
It("should accept it", func() { | ||
Expect(k8sClient.Create(context.TODO(), &cluster)).NotTo(HaveOccurred()) | ||
}) | ||
}) | ||
}) | ||
|
||
func newInvalidError(errs ...*field.Error) *apierrors.StatusError { | ||
return apierrors.NewInvalid( | ||
schema.GroupKind{Group: "storageos.com", Kind: "StorageOSCluster"}, | ||
"storageoscluster", | ||
errs) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
package webhook_test | ||
|
||
// heavily inspired by | ||
// https://github.com/kubernetes-sigs/kubebuilder/blob/master/docs/book/src/cronjob-tutorial/testdata/project/api/v1/webhook_suite_test.go | ||
|
||
import ( | ||
"context" | ||
"crypto/tls" | ||
"fmt" | ||
"net" | ||
"path/filepath" | ||
"testing" | ||
"time" | ||
|
||
. "github.com/onsi/ginkgo" | ||
. "github.com/onsi/gomega" | ||
|
||
admissionv1beta1 "k8s.io/api/admission/v1beta1" | ||
//+kubebuilder:scaffold:imports | ||
corev1 "k8s.io/api/core/v1" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
"k8s.io/apimachinery/pkg/runtime" | ||
utilruntime "k8s.io/apimachinery/pkg/util/runtime" | ||
clientgoscheme "k8s.io/client-go/kubernetes/scheme" | ||
"k8s.io/client-go/rest" | ||
ctrl "sigs.k8s.io/controller-runtime" | ||
"sigs.k8s.io/controller-runtime/pkg/client" | ||
"sigs.k8s.io/controller-runtime/pkg/envtest" | ||
"sigs.k8s.io/controller-runtime/pkg/envtest/printer" | ||
logf "sigs.k8s.io/controller-runtime/pkg/log" | ||
"sigs.k8s.io/controller-runtime/pkg/log/zap" | ||
|
||
storageoscomv1 "github.com/storageos/operator/api/v1" | ||
"github.com/storageos/operator/controllers/webhook" | ||
) | ||
|
||
// These tests use Ginkgo (BDD-style Go testing framework). Refer to | ||
// http://onsi.github.io/ginkgo/ to learn more about Ginkgo. | ||
|
||
var cfg *rest.Config | ||
var k8sClient client.Client | ||
var testEnv *envtest.Environment | ||
var ctx context.Context | ||
var cancel context.CancelFunc | ||
|
||
const namespace = "storageos" | ||
|
||
func TestAPIs(t *testing.T) { | ||
RegisterFailHandler(Fail) | ||
|
||
RunSpecsWithDefaultAndCustomReporters(t, | ||
"Webhook Suite", | ||
[]Reporter{printer.NewlineReporter{}}) | ||
} | ||
|
||
var _ = BeforeSuite(func() { | ||
logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true))) | ||
|
||
ctx, cancel = context.WithCancel(context.TODO()) | ||
|
||
By("bootstrapping test environment") | ||
testEnv = &envtest.Environment{ | ||
CRDDirectoryPaths: []string{filepath.Join("..", "..", "config", "crd", "bases")}, | ||
ErrorIfCRDPathMissing: true, | ||
WebhookInstallOptions: envtest.WebhookInstallOptions{ | ||
Paths: []string{filepath.Join("..", "..", "config", "webhook")}, | ||
}, | ||
} | ||
|
||
var err error | ||
// cfg is defined in this file globally. | ||
cfg, err = testEnv.Start() | ||
Expect(err).NotTo(HaveOccurred()) | ||
Expect(cfg).NotTo(BeNil()) | ||
|
||
scheme := runtime.NewScheme() | ||
utilruntime.Must(clientgoscheme.AddToScheme(scheme)) | ||
err = storageoscomv1.AddToScheme(scheme) | ||
Expect(err).NotTo(HaveOccurred()) | ||
|
||
err = admissionv1beta1.AddToScheme(scheme) | ||
Expect(err).NotTo(HaveOccurred()) | ||
|
||
//+kubebuilder:scaffold:scheme | ||
|
||
k8sClient, err = client.New(cfg, client.Options{Scheme: scheme}) | ||
Expect(err).NotTo(HaveOccurred()) | ||
Expect(k8sClient).NotTo(BeNil()) | ||
|
||
// start webhook server using Manager | ||
webhookInstallOptions := &testEnv.WebhookInstallOptions | ||
mgr, err := ctrl.NewManager(cfg, ctrl.Options{ | ||
Scheme: scheme, | ||
Host: webhookInstallOptions.LocalServingHost, | ||
Port: webhookInstallOptions.LocalServingPort, | ||
CertDir: webhookInstallOptions.LocalServingCertDir, | ||
LeaderElection: false, | ||
MetricsBindAddress: "0", | ||
}) | ||
Expect(err).NotTo(HaveOccurred()) | ||
|
||
webhook, err := webhook.NewStorageOSClusterWebhook(mgr.GetClient(), mgr.GetScheme()) | ||
Expect(err).NotTo(HaveOccurred()) | ||
Expect(webhook.SetupWithManager(mgr)).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 | ||
} | ||
conn.Close() | ||
return nil | ||
}).Should(Succeed()) | ||
|
||
nm := corev1.Namespace{ | ||
ObjectMeta: metav1.ObjectMeta{ | ||
Name: namespace, | ||
}, | ||
} | ||
Expect(k8sClient.Create(context.TODO(), &nm)).NotTo(HaveOccurred()) | ||
}, 60) | ||
|
||
var _ = AfterSuite(func() { | ||
cancel() | ||
By("tearing down the test environment") | ||
err := testEnv.Stop() | ||
Expect(err).NotTo(HaveOccurred()) | ||
}) |