Skip to content

Commit

Permalink
test(webhook): add test for Cryostat defaulter webhook (#988)
Browse files Browse the repository at this point in the history
  • Loading branch information
ebaron authored Dec 18, 2024
1 parent a543918 commit 9ea119d
Show file tree
Hide file tree
Showing 4 changed files with 133 additions and 22 deletions.
6 changes: 3 additions & 3 deletions internal/webhooks/cryostat_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ var cryostatlog = logf.Log.WithName("cryostat-resource")
func SetupWebhookWithManager(mgr ctrl.Manager, apiType runtime.Object) error {
return ctrl.NewWebhookManagedBy(mgr).
For(apiType).
WithValidator(&CryostatValidator{
Client: mgr.GetClient(),
Log: &cryostatlog,
WithValidator(&cryostatValidator{
client: mgr.GetClient(),
log: &cryostatlog,
}).
WithDefaulter(&cryostatDefaulter{
log: &cryostatlog,
Expand Down
117 changes: 117 additions & 0 deletions internal/webhooks/defaulter_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
// Copyright The Cryostat Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package webhooks_test

import (
"context"
"strconv"

operatorv1beta2 "github.com/cryostatio/cryostat-operator/api/v1beta2"
"github.com/cryostatio/cryostat-operator/internal/controllers/model"
"github.com/cryostatio/cryostat-operator/internal/test"
webhooktests "github.com/cryostatio/cryostat-operator/internal/webhooks/test"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"

"k8s.io/apimachinery/pkg/types"
ctrlclient "sigs.k8s.io/controller-runtime/pkg/client"
logf "sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
)

type defaulterTestInput struct {
client ctrlclient.Client
objs []ctrlclient.Object
*webhooktests.WebhookTestResources
}

var _ = Describe("CryostatDefaulter", func() {
var t *defaulterTestInput
var otherNS string
count := 0

namespaceWithSuffix := func(name string) string {
return name + "-defaulter-" + strconv.Itoa(count)
}

BeforeEach(func() {
ns := namespaceWithSuffix("test")
otherNS = namespaceWithSuffix("other")
t = &defaulterTestInput{
WebhookTestResources: &webhooktests.WebhookTestResources{
TestResources: &test.TestResources{
Name: "cryostat",
Namespace: ns,
},
},
}
t.objs = []ctrlclient.Object{
t.NewNamespace(), t.NewOtherNamespace(otherNS),
}
})

JustBeforeEach(func() {
logger := zap.New()
logf.SetLogger(logger)

t.client = k8sClient
for _, obj := range t.objs {
err := t.client.Create(ctx, obj)
Expect(err).ToNot(HaveOccurred())
}
})

JustAfterEach(func() {
for _, obj := range t.objs {
err := ctrlclient.IgnoreNotFound(t.client.Delete(ctx, obj))
Expect(err).ToNot(HaveOccurred())
}
})

AfterEach(func() {
count++
})

Context("without target namespace", func() {
BeforeEach(func() {
t.objs = append(t.objs, t.NewCryostat().Object)
})

It("should set default target namespace", func() {
result := t.getCryostatInstance()
Expect(result.TargetNamespaces).To(ConsistOf(t.Namespace))
})
})

Context("with target namespace", func() {
BeforeEach(func() {
t.TargetNamespaces = []string{otherNS}
t.objs = append(t.objs, t.NewCryostat().Object)
})

It("should do nothing", func() {
result := t.getCryostatInstance()
Expect(result.TargetNamespaces).To(ConsistOf(otherNS))
})
})

})

func (t *defaulterTestInput) getCryostatInstance() *model.CryostatInstance {
cr := &operatorv1beta2.Cryostat{}
err := t.client.Get(context.Background(), types.NamespacedName{Name: t.Name, Namespace: t.Namespace}, cr)
Expect(err).ToNot(HaveOccurred())
return t.ConvertNamespacedToModel(cr)
}
20 changes: 10 additions & 10 deletions internal/webhooks/validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,25 +27,25 @@ import (
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
)

type CryostatValidator struct {
Client client.Client
Log *logr.Logger
type cryostatValidator struct {
client client.Client
log *logr.Logger
}

var _ admission.CustomValidator = &CryostatValidator{}
var _ admission.CustomValidator = &cryostatValidator{}

// ValidateCreate validates a Create operation on a Cryostat
func (r *CryostatValidator) ValidateCreate(ctx context.Context, obj runtime.Object) (admission.Warnings, error) {
func (r *cryostatValidator) ValidateCreate(ctx context.Context, obj runtime.Object) (admission.Warnings, error) {
return r.validate(ctx, obj, "create")
}

// ValidateCreate validates an Update operation on a Cryostat
func (r *CryostatValidator) ValidateUpdate(ctx context.Context, oldObj, newObj runtime.Object) (admission.Warnings, error) {
func (r *cryostatValidator) ValidateUpdate(ctx context.Context, oldObj, newObj runtime.Object) (admission.Warnings, error) {
return r.validate(ctx, newObj, "update")
}

// ValidateCreate validates a Delete operation on a Cryostat
func (r *CryostatValidator) ValidateDelete(ctx context.Context, obj runtime.Object) (admission.Warnings, error) {
func (r *cryostatValidator) ValidateDelete(ctx context.Context, obj runtime.Object) (admission.Warnings, error) {
// Nothing to validate on deletion
return nil, nil
}
Expand All @@ -68,12 +68,12 @@ func (e *ErrNotPermitted) Error() string {

var _ error = &ErrNotPermitted{}

func (r *CryostatValidator) validate(ctx context.Context, obj runtime.Object, op string) (admission.Warnings, error) {
func (r *cryostatValidator) validate(ctx context.Context, obj runtime.Object, op string) (admission.Warnings, error) {
cr, ok := obj.(*operatorv1beta2.Cryostat)
if !ok {
return nil, fmt.Errorf("expected a Cryostat, but received a %T", obj)
}
r.Log.Info(fmt.Sprintf("validate %s", op), "name", cr.Name, "namespace", cr.Namespace)
r.log.Info(fmt.Sprintf("validate %s", op), "name", cr.Name, "namespace", cr.Namespace)

// Look up the user who made this request
req, err := admission.RequestFromContext(ctx)
Expand Down Expand Up @@ -101,7 +101,7 @@ func (r *CryostatValidator) validate(ctx context.Context, obj runtime.Object, op
},
}

err := r.Client.Create(ctx, sar)
err := r.client.Create(ctx, sar)
if err != nil {
return nil, fmt.Errorf("failed to check permissions: %w", err)
}
Expand Down
12 changes: 3 additions & 9 deletions internal/webhooks/validator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,8 @@ import (
)

type validatorTestInput struct {
client ctrlclient.Client
validator *webhooks.CryostatValidator
objs []ctrlclient.Object
client ctrlclient.Client
objs []ctrlclient.Object
*webhooktests.WebhookTestResources
}

Expand All @@ -46,7 +45,7 @@ var _ = Describe("CryostatValidator", func() {
count := 0

namespaceWithSuffix := func(name string) string {
return name + "-" + strconv.Itoa(count)
return name + "-validator-" + strconv.Itoa(count)
}

BeforeEach(func() {
Expand All @@ -73,11 +72,6 @@ var _ = Describe("CryostatValidator", func() {
logf.SetLogger(logger)

t.client = k8sClient
t.validator = &webhooks.CryostatValidator{
Client: k8sClient,
Log: &logger,
}

for _, obj := range t.objs {
err := t.client.Create(ctx, obj)
Expect(err).ToNot(HaveOccurred())
Expand Down

0 comments on commit 9ea119d

Please sign in to comment.