Skip to content
This repository is currently being migrated. It's locked while the migration is in progress.

Commit

Permalink
added validation webhook test (#201)
Browse files Browse the repository at this point in the history
So far focusing just on StorageOSCluster.Spec.Metrics
  • Loading branch information
Michal Minář authored Jun 30, 2022
1 parent 208295e commit af2e6fe
Show file tree
Hide file tree
Showing 2 changed files with 239 additions and 0 deletions.
100 changes: 100 additions & 0 deletions controllers/webhook/metricsadmission_test.go
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)
}
139 changes: 139 additions & 0 deletions controllers/webhook/suite_test.go
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())
})

0 comments on commit af2e6fe

Please sign in to comment.