crossplane-runtime/pkg/resource/predicates_test.go

462 lines
11 KiB
Go

/*
Copyright 2019 The Crossplane 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 resource
import (
"testing"
"github.com/google/go-cmp/cmp"
"github.com/pkg/errors"
corev1 "k8s.io/api/core/v1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"sigs.k8s.io/controller-runtime/pkg/client"
"github.com/crossplaneio/crossplane-runtime/pkg/resource/fake"
"github.com/crossplaneio/crossplane-runtime/pkg/test"
)
func TestAnyOf(t *testing.T) {
cases := map[string]struct {
fns []PredicateFn
obj runtime.Object
want bool
}{
"PredicatePasses": {
fns: []PredicateFn{
func(obj runtime.Object) bool { return false },
func(obj runtime.Object) bool { return true },
},
want: true,
},
"NoPredicatesPass": {
fns: []PredicateFn{
func(obj runtime.Object) bool { return false },
},
want: false,
},
}
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
got := AnyOf(tc.fns...)(tc.obj)
if diff := cmp.Diff(tc.want, got); diff != "" {
t.Errorf("AnyOf(...): -want, +got:\n%s", diff)
}
})
}
}
func TestAllOf(t *testing.T) {
cases := map[string]struct {
fns []PredicateFn
obj runtime.Object
want bool
}{
"AllPredicatesPass": {
fns: []PredicateFn{
func(obj runtime.Object) bool { return true },
func(obj runtime.Object) bool { return true },
},
want: true,
},
"NoPredicatesPass": {
fns: []PredicateFn{
func(obj runtime.Object) bool { return false },
func(obj runtime.Object) bool { return false },
},
want: false,
},
"SomePredicatesPass": {
fns: []PredicateFn{
func(obj runtime.Object) bool { return false },
func(obj runtime.Object) bool { return true },
},
want: false,
},
}
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
got := AllOf(tc.fns...)(tc.obj)
if diff := cmp.Diff(tc.want, got); diff != "" {
t.Errorf("AllOf(...): -want, +got:\n%s", diff)
}
})
}
}
func TestHasManagedResourceReferenceKind(t *testing.T) {
cases := map[string]struct {
obj runtime.Object
c client.Client
kind ManagedKind
want bool
}{
"NotAClassReferencer": {
c: &test.MockClient{},
kind: ManagedKind(fake.GVK(&fake.Managed{})),
want: false,
},
"HasNoResourceReference": {
obj: &fake.Claim{},
kind: ManagedKind(fake.GVK(&fake.Managed{})),
want: false,
},
"HasCorrectResourceReference": {
obj: &fake.Claim{
ManagedResourceReferencer: fake.ManagedResourceReferencer{
Ref: &corev1.ObjectReference{
APIVersion: fake.GVK(&fake.Managed{}).GroupVersion().String(),
Kind: fake.GVK(&fake.Managed{}).Kind,
},
},
},
kind: ManagedKind(fake.GVK(&fake.Managed{})),
want: true,
},
}
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
got := HasManagedResourceReferenceKind(tc.kind)(tc.obj)
if diff := cmp.Diff(tc.want, got); diff != "" {
t.Errorf("HasManagedResourceReferenceKind(...): -want, +got:\n%s", diff)
}
})
}
}
func TestHasClassReferenceKind(t *testing.T) {
cases := map[string]struct {
obj runtime.Object
c client.Client
kind ClassKind
want bool
}{
"NotAClassReferencer": {
c: &test.MockClient{},
kind: ClassKind(fake.GVK(&fake.Class{})),
want: false,
},
"HasNoClassReference": {
obj: &fake.Claim{},
kind: ClassKind(fake.GVK(&fake.Class{})),
want: false,
},
"HasCorrectClassReference": {
obj: &fake.Claim{
ClassReferencer: fake.ClassReferencer{
Ref: &corev1.ObjectReference{
APIVersion: fake.GVK(&fake.Class{}).GroupVersion().String(),
Kind: fake.GVK(&fake.Class{}).Kind,
},
},
},
kind: ClassKind(fake.GVK(&fake.Class{})),
want: true,
},
}
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
got := HasClassReferenceKind(tc.kind)(tc.obj)
if diff := cmp.Diff(tc.want, got); diff != "" {
t.Errorf("HasClassReferenceKind(...): -want, +got:\n%s", diff)
}
})
}
}
func TestIsManagedKind(t *testing.T) {
cases := map[string]struct {
kind ManagedKind
ot runtime.ObjectTyper
obj runtime.Object
want bool
}{
"IsKind": {
kind: ManagedKind(fake.GVK(&fake.Managed{})),
ot: MockTyper{GVKs: []schema.GroupVersionKind{fake.GVK(&fake.Managed{})}},
want: true,
},
"IsNotKind": {
kind: ManagedKind(fake.GVK(&fake.Managed{})),
ot: MockTyper{GVKs: []schema.GroupVersionKind{fake.GVK(&fake.Claim{})}},
want: false,
},
"ErrorDeterminingKind": {
kind: ManagedKind(fake.GVK(&fake.Managed{})),
ot: MockTyper{Error: errors.New("boom")},
want: false,
},
}
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
got := IsManagedKind(tc.kind, tc.ot)(tc.obj)
if diff := cmp.Diff(tc.want, got); diff != "" {
t.Errorf("IsManagedKind(...): -want, +got:\n%s", diff)
}
})
}
}
func TestIsControlledByKind(t *testing.T) {
controller := true
cases := map[string]struct {
kind schema.GroupVersionKind
obj runtime.Object
want bool
}{
"NoObjectMeta": {
want: false,
},
"NoControllerRef": {
obj: &corev1.Secret{},
want: false,
},
"WrongAPIVersion": {
kind: fake.GVK(&fake.Managed{}),
obj: &corev1.Secret{ObjectMeta: v1.ObjectMeta{OwnerReferences: []v1.OwnerReference{
{
Kind: fake.GVK(&fake.Managed{}).Kind,
Controller: &controller,
},
}}},
want: false,
},
"WrongKind": {
kind: fake.GVK(&fake.Managed{}),
obj: &corev1.Secret{ObjectMeta: v1.ObjectMeta{OwnerReferences: []v1.OwnerReference{
{
APIVersion: fake.GVK(&fake.Managed{}).GroupVersion().String(),
Controller: &controller,
},
}}},
want: false,
},
"IsControlledByKind": {
kind: fake.GVK(&fake.Managed{}),
obj: &corev1.Secret{ObjectMeta: v1.ObjectMeta{OwnerReferences: []v1.OwnerReference{
{
APIVersion: fake.GVK(&fake.Managed{}).GroupVersion().String(),
Kind: fake.GVK(&fake.Managed{}).Kind,
Controller: &controller,
},
}}},
want: true,
},
}
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
got := IsControlledByKind(tc.kind)(tc.obj)
if diff := cmp.Diff(tc.want, got); diff != "" {
t.Errorf("IsControlledByKind(...): -want, +got:\n%s", diff)
}
})
}
}
func TestIsPropagator(t *testing.T) {
cases := map[string]struct {
obj runtime.Object
want bool
}{
"NotAnAnnotator": {
want: false,
},
"NotAPropagator": {
obj: &corev1.Secret{ObjectMeta: v1.ObjectMeta{Annotations: map[string]string{
"some.annotation": "someValue",
}}},
want: false,
},
"IsPropagator": {
obj: &corev1.Secret{ObjectMeta: v1.ObjectMeta{Annotations: map[string]string{
AnnotationKeyPropagateToPrefix + "cool-uid": "cool-namespace/cool-name",
}}},
want: true,
},
"IsMultiPropagator": {
obj: &corev1.Secret{ObjectMeta: v1.ObjectMeta{Annotations: map[string]string{
AnnotationKeyPropagateToPrefix + "cool-uid": "cool-namespace/cool-name",
AnnotationKeyPropagateToPrefix + "cool-uid-two": "cool-namespace/cool-name-2",
}}},
want: true,
},
}
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
got := IsPropagator()(tc.obj)
if diff := cmp.Diff(tc.want, got); diff != "" {
t.Errorf("IsPropagator(...): -want, +got:\n%s", diff)
}
})
}
}
func TestIsPropagated(t *testing.T) {
cases := map[string]struct {
obj runtime.Object
want bool
}{
"NotAnAnnotator": {
want: false,
},
"NotPropagated": {
obj: &corev1.Secret{ObjectMeta: v1.ObjectMeta{Annotations: map[string]string{
"some.annotation": "someValue",
}}},
want: false,
},
"IsPropagated": {
obj: &corev1.Secret{ObjectMeta: v1.ObjectMeta{Annotations: map[string]string{
AnnotationKeyPropagateFromNamespace: namespace,
AnnotationKeyPropagateFromName: name,
AnnotationKeyPropagateFromUID: string(uid),
}}},
want: true,
},
}
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
got := IsPropagated()(tc.obj)
if diff := cmp.Diff(tc.want, got); diff != "" {
t.Errorf("IsPropagated(...): -want, +got:\n%s", diff)
}
})
}
}
func TestHasClassSelector(t *testing.T) {
cases := map[string]struct {
obj runtime.Object
want bool
}{
"NotAClassSelector": {
want: false,
},
"NoClassSelector": {
obj: &fake.Claim{},
want: false,
},
"HasClassSelector": {
obj: &fake.Claim{ClassSelector: fake.ClassSelector{Sel: &v1.LabelSelector{}}},
want: true,
},
}
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
got := HasClassSelector()(tc.obj)
if diff := cmp.Diff(tc.want, got); diff != "" {
t.Errorf("HasClassSelector(...): -want, +got:\n%s", diff)
}
})
}
}
func TestHasNoClassSelector(t *testing.T) {
cases := map[string]struct {
obj runtime.Object
want bool
}{
"NotAClassSelector": {
want: false,
},
"NoClassSelector": {
obj: &fake.Claim{},
want: true,
},
"HasClassSelector": {
obj: &fake.Claim{ClassSelector: fake.ClassSelector{Sel: &v1.LabelSelector{}}},
want: false,
},
}
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
got := HasNoClassSelector()(tc.obj)
if diff := cmp.Diff(tc.want, got); diff != "" {
t.Errorf("HasNoClassSelector(...): -want, +got:\n%s", diff)
}
})
}
}
func TestHasNoClassReference(t *testing.T) {
cases := map[string]struct {
obj runtime.Object
want bool
}{
"NotAClassReferencer": {
want: false,
},
"NoClassReference": {
obj: &fake.Claim{},
want: true,
},
"HasClassReference": {
obj: &fake.Claim{ClassReferencer: fake.ClassReferencer{Ref: &corev1.ObjectReference{}}},
want: false,
},
}
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
got := HasNoClassReference()(tc.obj)
if diff := cmp.Diff(tc.want, got); diff != "" {
t.Errorf("HasNoClassReference(...): -want, +got:\n%s", diff)
}
})
}
}
func TestHasNoMangedResourceReference(t *testing.T) {
cases := map[string]struct {
obj runtime.Object
want bool
}{
"NotAManagedResourceReferencer": {
want: false,
},
"NoManagedResourceReference": {
obj: &fake.Claim{},
want: true,
},
"HasClassReference": {
obj: &fake.Claim{ManagedResourceReferencer: fake.ManagedResourceReferencer{Ref: &corev1.ObjectReference{}}},
want: false,
},
}
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
got := HasNoManagedResourceReference()(tc.obj)
if diff := cmp.Diff(tc.want, got); diff != "" {
t.Errorf("HasNoManagedResourecReference(...): -want, +got:\n%s", diff)
}
})
}
}