Skip to content

Commit

Permalink
add secret mutator
Browse files Browse the repository at this point in the history
  • Loading branch information
airycanon committed Sep 6, 2023
1 parent 79ecb3e commit cd08f05
Show file tree
Hide file tree
Showing 2 changed files with 172 additions and 0 deletions.
62 changes: 62 additions & 0 deletions secret/mutate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package secret

import (
"context"

corev1 "k8s.io/api/core/v1"
)

// Mutator interface defines a method for modifying Secret objects.
type Mutator interface {
Mutate(context.Context, *corev1.Secret) error
}

// MutateFunc is a function type that implements the Mutator interface.
type MutateFunc func(context.Context, *corev1.Secret) error

func (m MutateFunc) Mutate(ctx context.Context, secret *corev1.Secret) error {
return m(ctx, secret)
}

// MutatorList is a slice of Mutators.
type MutatorList []Mutator

// Mutate iterates over the list of mutators and applies them to the provided Secret object.
func (m MutatorList) Mutate(ctx context.Context, secret *corev1.Secret) error {
for _, mutator := range m {
if err := mutator.Mutate(ctx, secret); err != nil {
return err
}
}
return nil
}

// DefaultMutator is a no-operation implementation of the Mutator interface.
// It is used as a default option when there is no Mutator associated with the context.
var DefaultMutator = &NoOpMutator{}

// NoOpMutator struct implements the Mutator interface but performs no actions.
type NoOpMutator struct {
}

// Mutate is the NoOpMutator's implementation that simply returns the passed-in Secret object without any modifications.
func (a *NoOpMutator) Mutate(_ context.Context, secret *corev1.Secret) error {
return nil
}

// mutatorKey is a key used for storing a Mutator in a context.
var mutatorKey = struct{}{}

// MutatorFromCtx retrieves a Mutator from the given context.
// If no Mutator is found, it returns the noOpMutator.
func MutatorFromCtx(ctx context.Context) Mutator {
if mutation, ok := ctx.Value(mutatorKey).(Mutator); ok {
return mutation
}
return DefaultMutator
}

// WithMutator attaches a Mutator to a context and returns the new context.
func WithMutator(ctx context.Context, mutator Mutator) context.Context {
return context.WithValue(ctx, mutatorKey, mutator)
}
110 changes: 110 additions & 0 deletions secret/mutate_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package secret

import (
"context"
"errors"
. "github.com/onsi/gomega"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"testing"
)

// MockMutator is a mock implementation of the Mutator interface for testing.
type MockMutator struct {
Modified bool
}

// Mutate modifies the Secret object by appending "-modified" to its Name field.
func (m *MockMutator) Mutate(_ context.Context, secret *corev1.Secret) error {
secret.Name += "-modified"
m.Modified = true
return nil
}

// TestMutatorList tests the Mutate function for a list of Mutators.
func TestMutatorList(t *testing.T) {
g := NewGomegaWithT(t)

mockMutator := &MockMutator{}
list := MutatorList{DefaultMutator, mockMutator}

secret := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
},
}
err := list.Mutate(context.Background(), secret)

g.Expect(err).To(BeNil())
g.Expect(secret.Name).To(Equal("test-modified"))
g.Expect(mockMutator.Modified).To(BeTrue())
}

// TestMutatorList tests the Mutate function for a list of Mutators.
func TestMutatorListError(t *testing.T) {
g := NewGomegaWithT(t)

m1 := MutateFunc(func(ctx context.Context, secret *corev1.Secret) error {
return errors.New("test")
})

m2 := MutateFunc(func(ctx context.Context, secret *corev1.Secret) error {
return nil
})
list := MutatorList{m1, m2}

secret := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
},
}
err := list.Mutate(context.Background(), secret)

g.Expect(err).NotTo(BeNil())
}

// TestNoOpMutator tests the no-operation Mutator.
func TestNoOpMutator(t *testing.T) {
g := NewGomegaWithT(t)

secret := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
},
}
err := DefaultMutator.Mutate(context.Background(), secret)

g.Expect(err).To(BeNil())
g.Expect(secret.Name).To(Equal("test"))
}

// TestNoOpMutator tests the no-operation Mutator.
func TestMutatorFunc(t *testing.T) {
g := NewGomegaWithT(t)

secret := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
},
}
mutator := MutateFunc(func(ctx context.Context, secret *corev1.Secret) error {
secret.Name += "-modified"
return nil
})
err := mutator.Mutate(context.Background(), secret)

g.Expect(err).To(BeNil())
g.Expect(secret.Name).To(Equal("test-modified"))
}

// TestMutatorFromCtx tests the retrieval of a Mutator from a context.
func TestMutatorFromCtx(t *testing.T) {
g := NewGomegaWithT(t)

ctx := context.Background()
g.Expect(MutatorFromCtx(ctx)).To(Equal(DefaultMutator))

mockMutator := &MockMutator{}
ctx = WithMutator(ctx, mockMutator)
g.Expect(MutatorFromCtx(ctx)).To(Equal(mockMutator))
}

0 comments on commit cd08f05

Please sign in to comment.