mirror of https://github.com/knative/pkg.git
				
				
				
			
		
			
				
	
	
		
			2303 lines
		
	
	
		
			60 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			2303 lines
		
	
	
		
			60 KiB
		
	
	
	
		
			Go
		
	
	
	
| /*
 | |
| Copyright 2019 The Knative 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 psbinding
 | |
| 
 | |
| import (
 | |
| 	"context"
 | |
| 	"encoding/json"
 | |
| 	"errors"
 | |
| 	"fmt"
 | |
| 	"testing"
 | |
| 	"time"
 | |
| 
 | |
| 	"github.com/google/go-cmp/cmp"
 | |
| 	jsonpatch "gomodules.xyz/jsonpatch/v2"
 | |
| 	fakek8s "k8s.io/client-go/kubernetes/fake"
 | |
| 	"knative.dev/pkg/apis"
 | |
| 	"knative.dev/pkg/client/injection/ducks/duck/v1/podspecable"
 | |
| 	kubeclient "knative.dev/pkg/client/injection/kube/client/fake"
 | |
| 	mwhinformer "knative.dev/pkg/client/injection/kube/informers/admissionregistration/v1/mutatingwebhookconfiguration"
 | |
| 	_ "knative.dev/pkg/client/injection/kube/informers/admissionregistration/v1/mutatingwebhookconfiguration/fake"
 | |
| 	dynamicclient "knative.dev/pkg/injection/clients/dynamicclient/fake"
 | |
| 	secretinformer "knative.dev/pkg/injection/clients/namespacedkube/informers/core/v1/secret"
 | |
| 	_ "knative.dev/pkg/injection/clients/namespacedkube/informers/core/v1/secret/fake"
 | |
| 	pkgreconciler "knative.dev/pkg/reconciler"
 | |
| 	"knative.dev/pkg/tracker"
 | |
| 
 | |
| 	admissionv1 "k8s.io/api/admission/v1"
 | |
| 	admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
 | |
| 	appsv1 "k8s.io/api/apps/v1"
 | |
| 	corev1 "k8s.io/api/core/v1"
 | |
| 	apierrs "k8s.io/apimachinery/pkg/api/errors"
 | |
| 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | |
| 	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
 | |
| 	"k8s.io/apimachinery/pkg/runtime"
 | |
| 	"k8s.io/apimachinery/pkg/runtime/schema"
 | |
| 	"k8s.io/apimachinery/pkg/types"
 | |
| 	"k8s.io/apimachinery/pkg/util/wait"
 | |
| 	clientgotesting "k8s.io/client-go/testing"
 | |
| 	"k8s.io/client-go/tools/cache"
 | |
| 	"k8s.io/client-go/tools/record"
 | |
| 	"knative.dev/pkg/apis/duck"
 | |
| 	duckv1 "knative.dev/pkg/apis/duck/v1"
 | |
| 	duckv1alpha1 "knative.dev/pkg/apis/duck/v1alpha1"
 | |
| 	"knative.dev/pkg/configmap"
 | |
| 	"knative.dev/pkg/controller"
 | |
| 	"knative.dev/pkg/ptr"
 | |
| 	"knative.dev/pkg/system"
 | |
| 	"knative.dev/pkg/webhook"
 | |
| 	certresources "knative.dev/pkg/webhook/certificates/resources"
 | |
| 
 | |
| 	. "knative.dev/pkg/reconciler/testing"
 | |
| 	. "knative.dev/pkg/testing/duck"
 | |
| 	. "knative.dev/pkg/webhook/testing"
 | |
| )
 | |
| 
 | |
| func checkDeploymentIsPatched(t *testing.T, r *TableRow) {
 | |
| 	t.Helper()
 | |
| 	ac := r.Reconciler.(webhook.AdmissionController)
 | |
| 	d := &appsv1.Deployment{
 | |
| 		ObjectMeta: metav1.ObjectMeta{
 | |
| 			Namespace: "foo",
 | |
| 			Name:      "on-it",
 | |
| 			Labels: map[string]string{
 | |
| 				"foo": "bar",
 | |
| 			},
 | |
| 		},
 | |
| 		Spec: appsv1.DeploymentSpec{
 | |
| 			Template: corev1.PodTemplateSpec{
 | |
| 				Spec: corev1.PodSpec{
 | |
| 					Containers: []corev1.Container{{
 | |
| 						Name:  "foo",
 | |
| 						Image: "busybox",
 | |
| 					}},
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 	}
 | |
| 	b, err := json.Marshal(d)
 | |
| 	if err != nil {
 | |
| 		t.Fatal("Unable to serialize deployment:", err)
 | |
| 	}
 | |
| 
 | |
| 	req := &admissionv1.AdmissionRequest{
 | |
| 		Operation: admissionv1.Create,
 | |
| 		Kind: metav1.GroupVersionKind{
 | |
| 			Group:   "apps",
 | |
| 			Version: "v1",
 | |
| 			Kind:    "Deployment",
 | |
| 		},
 | |
| 		Namespace: d.Namespace,
 | |
| 		Object:    runtime.RawExtension{Raw: b},
 | |
| 	}
 | |
| 
 | |
| 	// It is allowed, and patched to include the environment variable.
 | |
| 	resp := ac.Admit(r.Ctx, req)
 | |
| 	ExpectAllowed(t, resp)
 | |
| 	ExpectPatches(t, resp.Patch, []jsonpatch.JsonPatchOperation{{
 | |
| 		Operation: "add",
 | |
| 		Path:      "/spec/template/spec/containers/0/env",
 | |
| 		Value: []interface{}{map[string]interface{}{
 | |
| 			"name":  "FOO",
 | |
| 			"value": "the-value",
 | |
| 		}},
 | |
| 	}})
 | |
| }
 | |
| 
 | |
| func checkDeploymentIsPatchedBack(t *testing.T, r *TableRow) {
 | |
| 	t.Helper()
 | |
| 	ac := r.Reconciler.(webhook.AdmissionController)
 | |
| 	d := &appsv1.Deployment{
 | |
| 		ObjectMeta: metav1.ObjectMeta{
 | |
| 			Namespace: "foo",
 | |
| 			Name:      "on-it",
 | |
| 			Labels: map[string]string{
 | |
| 				"foo": "bar",
 | |
| 			},
 | |
| 		},
 | |
| 		Spec: appsv1.DeploymentSpec{
 | |
| 			Template: corev1.PodTemplateSpec{
 | |
| 				Spec: corev1.PodSpec{
 | |
| 					Containers: []corev1.Container{{
 | |
| 						Name:  "foo",
 | |
| 						Image: "busybox",
 | |
| 						Env: []corev1.EnvVar{{
 | |
| 							Name:  "FOO",
 | |
| 							Value: "the-value",
 | |
| 						}},
 | |
| 					}},
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 	}
 | |
| 	b, err := json.Marshal(d)
 | |
| 	if err != nil {
 | |
| 		t.Fatal("Unable to serialize deployment:", err)
 | |
| 	}
 | |
| 
 | |
| 	req := &admissionv1.AdmissionRequest{
 | |
| 		Operation: admissionv1.Create,
 | |
| 		Kind: metav1.GroupVersionKind{
 | |
| 			Group:   "apps",
 | |
| 			Version: "v1",
 | |
| 			Kind:    "Deployment",
 | |
| 		},
 | |
| 		Namespace: d.Namespace,
 | |
| 		Object:    runtime.RawExtension{Raw: b},
 | |
| 	}
 | |
| 
 | |
| 	// It is allowed, and patched to REMOVE the environment variable.
 | |
| 	resp := ac.Admit(r.Ctx, req)
 | |
| 	ExpectAllowed(t, resp)
 | |
| 	ExpectPatches(t, resp.Patch, []jsonpatch.JsonPatchOperation{{
 | |
| 		Operation: "remove",
 | |
| 		Path:      "/spec/template/spec/containers/0/env",
 | |
| 	}})
 | |
| }
 | |
| 
 | |
| func checkDeploymentIsNotPatched(t *testing.T, r *TableRow) {
 | |
| 	t.Helper()
 | |
| 	ac := r.Reconciler.(webhook.AdmissionController)
 | |
| 	d := &appsv1.Deployment{
 | |
| 		ObjectMeta: metav1.ObjectMeta{
 | |
| 			Namespace: "foo",
 | |
| 			Name:      "off-it",
 | |
| 			Labels: map[string]string{
 | |
| 				"foo": "baz",
 | |
| 			},
 | |
| 		},
 | |
| 		Spec: appsv1.DeploymentSpec{
 | |
| 			Template: corev1.PodTemplateSpec{
 | |
| 				Spec: corev1.PodSpec{
 | |
| 					Containers: []corev1.Container{{
 | |
| 						Name:  "foo",
 | |
| 						Image: "busybox",
 | |
| 					}},
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 	}
 | |
| 	b, err := json.Marshal(d)
 | |
| 	if err != nil {
 | |
| 		t.Fatal("Unable to serialize deployment:", err)
 | |
| 	}
 | |
| 
 | |
| 	req := &admissionv1.AdmissionRequest{
 | |
| 		Operation: admissionv1.Create,
 | |
| 		Kind: metav1.GroupVersionKind{
 | |
| 			Group:   "apps",
 | |
| 			Version: "v1",
 | |
| 			Kind:    "Deployment",
 | |
| 		},
 | |
| 		Namespace: d.Namespace,
 | |
| 		Object:    runtime.RawExtension{Raw: b},
 | |
| 	}
 | |
| 
 | |
| 	// It is allowed, but not patched.
 | |
| 	resp := ac.Admit(r.Ctx, req)
 | |
| 	ExpectAllowed(t, resp)
 | |
| 	if want, got := "", string(resp.Patch); want != got {
 | |
| 		t.Errorf("Admit() = %s, got %s", got, want)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func checkDeleteIgnored(t *testing.T, r *TableRow) {
 | |
| 	t.Helper()
 | |
| 	ac := r.Reconciler.(webhook.AdmissionController)
 | |
| 	d := &appsv1.Deployment{
 | |
| 		ObjectMeta: metav1.ObjectMeta{
 | |
| 			Namespace: "foo",
 | |
| 			Name:      "on-it",
 | |
| 			Labels: map[string]string{
 | |
| 				"foo": "bar",
 | |
| 			},
 | |
| 		},
 | |
| 		Spec: appsv1.DeploymentSpec{
 | |
| 			Template: corev1.PodTemplateSpec{
 | |
| 				Spec: corev1.PodSpec{
 | |
| 					Containers: []corev1.Container{{
 | |
| 						Name:  "foo",
 | |
| 						Image: "busybox",
 | |
| 					}},
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 	}
 | |
| 	b, err := json.Marshal(d)
 | |
| 	if err != nil {
 | |
| 		t.Fatal("Unable to serialize deployment:", err)
 | |
| 	}
 | |
| 
 | |
| 	req := &admissionv1.AdmissionRequest{
 | |
| 		Operation: admissionv1.Delete,
 | |
| 		Kind: metav1.GroupVersionKind{
 | |
| 			Group:   "apps",
 | |
| 			Version: "v1",
 | |
| 			Kind:    "Deployment",
 | |
| 		},
 | |
| 		Namespace: d.Namespace,
 | |
| 		Object:    runtime.RawExtension{Raw: b},
 | |
| 	}
 | |
| 
 | |
| 	// It is allowed, and patched to include the environment variable.
 | |
| 	resp := ac.Admit(r.Ctx, req)
 | |
| 	ExpectAllowed(t, resp)
 | |
| 	if want, got := "", string(resp.Patch); want != got {
 | |
| 		t.Errorf("Admit() = %s, got %s", got, want)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestWebhookReconcile(t *testing.T) {
 | |
| 	name, path := "foo.bar.baz", "/blah"
 | |
| 	secretName := "webhook-secret"
 | |
| 
 | |
| 	secret := &corev1.Secret{
 | |
| 		ObjectMeta: metav1.ObjectMeta{
 | |
| 			Name:      secretName,
 | |
| 			Namespace: system.Namespace(),
 | |
| 		},
 | |
| 		Data: map[string][]byte{
 | |
| 			certresources.ServerKey:  []byte("present"),
 | |
| 			certresources.ServerCert: []byte("present"),
 | |
| 			certresources.CACert:     []byte("present"),
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	equivalent := admissionregistrationv1.Equivalent
 | |
| 
 | |
| 	// The key to use, which for this singleton reconciler doesn't matter (although the
 | |
| 	// namespace matters for namespace validation).
 | |
| 	key := system.Namespace() + "/does not matter"
 | |
| 
 | |
| 	table := TableTest{{
 | |
| 		Name:    "no secret",
 | |
| 		Key:     key,
 | |
| 		WantErr: true,
 | |
| 	}, {
 | |
| 		Name: "secret missing CA Cert",
 | |
| 		Key:  key,
 | |
| 		Objects: []runtime.Object{&corev1.Secret{
 | |
| 			ObjectMeta: metav1.ObjectMeta{
 | |
| 				Name:      secretName,
 | |
| 				Namespace: system.Namespace(),
 | |
| 			},
 | |
| 			Data: map[string][]byte{
 | |
| 				certresources.ServerKey:  []byte("present"),
 | |
| 				certresources.ServerCert: []byte("present"),
 | |
| 				// certresources.CACert:     []byte("missing"),
 | |
| 			},
 | |
| 		}},
 | |
| 		WantErr: true,
 | |
| 	}, {
 | |
| 		Name:    "secret exists, but MWH does not",
 | |
| 		Key:     key,
 | |
| 		Objects: []runtime.Object{secret},
 | |
| 		WantErr: true,
 | |
| 	}, {
 | |
| 		Name: "secret and MWH exist, missing service reference",
 | |
| 		Key:  key,
 | |
| 		Objects: []runtime.Object{secret,
 | |
| 			&admissionregistrationv1.MutatingWebhookConfiguration{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Name: name,
 | |
| 				},
 | |
| 				Webhooks: []admissionregistrationv1.MutatingWebhook{{
 | |
| 					Name: name,
 | |
| 				}},
 | |
| 			},
 | |
| 		},
 | |
| 		WantErr: true,
 | |
| 	}, {
 | |
| 		Name: "secret and MWH exist, missing other stuff",
 | |
| 		Key:  key,
 | |
| 		Objects: []runtime.Object{secret,
 | |
| 			&admissionregistrationv1.MutatingWebhookConfiguration{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Name: name,
 | |
| 				},
 | |
| 				Webhooks: []admissionregistrationv1.MutatingWebhook{{
 | |
| 					Name: name,
 | |
| 					ClientConfig: admissionregistrationv1.WebhookClientConfig{
 | |
| 						Service: &admissionregistrationv1.ServiceReference{
 | |
| 							Namespace: system.Namespace(),
 | |
| 							Name:      "webhook",
 | |
| 						},
 | |
| 					},
 | |
| 				}},
 | |
| 			},
 | |
| 		},
 | |
| 		WantUpdates: []clientgotesting.UpdateActionImpl{{
 | |
| 			Object: &admissionregistrationv1.MutatingWebhookConfiguration{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Name: name,
 | |
| 				},
 | |
| 				Webhooks: []admissionregistrationv1.MutatingWebhook{{
 | |
| 					Name: name,
 | |
| 					ClientConfig: admissionregistrationv1.WebhookClientConfig{
 | |
| 						Service: &admissionregistrationv1.ServiceReference{
 | |
| 							Namespace: system.Namespace(),
 | |
| 							Name:      "webhook",
 | |
| 							// Path is added.
 | |
| 							Path: ptr.String(path),
 | |
| 						},
 | |
| 						// CABundle is added.
 | |
| 						CABundle: []byte("present"),
 | |
| 					},
 | |
| 					// Rules are added.
 | |
| 					Rules: nil,
 | |
| 					// MatchPolicy is added.
 | |
| 					MatchPolicy: &equivalent,
 | |
| 					// Selectors are added.
 | |
| 					NamespaceSelector: &ExclusionSelector,
 | |
| 					ObjectSelector:    &ExclusionSelector,
 | |
| 				}},
 | |
| 			},
 | |
| 		}},
 | |
| 	}, {
 | |
| 		Name: "secret and MWH exist, added fields are incorrect",
 | |
| 		Key:  key,
 | |
| 		Objects: []runtime.Object{secret,
 | |
| 			&admissionregistrationv1.MutatingWebhookConfiguration{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Name: name,
 | |
| 				},
 | |
| 				Webhooks: []admissionregistrationv1.MutatingWebhook{{
 | |
| 					Name: name,
 | |
| 					ClientConfig: admissionregistrationv1.WebhookClientConfig{
 | |
| 						Service: &admissionregistrationv1.ServiceReference{
 | |
| 							Namespace: system.Namespace(),
 | |
| 							Name:      "webhook",
 | |
| 							// Incorrect
 | |
| 							Path: ptr.String("incorrect"),
 | |
| 						},
 | |
| 						// Incorrect
 | |
| 						CABundle: []byte("incorrect"),
 | |
| 					},
 | |
| 					// Incorrect (really just incomplete)
 | |
| 					Rules: []admissionregistrationv1.RuleWithOperations{{
 | |
| 						Operations: []admissionregistrationv1.OperationType{"CREATE", "UPDATE"},
 | |
| 						Rule: admissionregistrationv1.Rule{
 | |
| 							APIGroups:   []string{"pkg.knative.dev"},
 | |
| 							APIVersions: []string{"v1alpha1"},
 | |
| 							Resources:   []string{"innerdefaultresources/*"},
 | |
| 						},
 | |
| 					}},
 | |
| 				}},
 | |
| 			},
 | |
| 		},
 | |
| 		WantUpdates: []clientgotesting.UpdateActionImpl{{
 | |
| 			Object: &admissionregistrationv1.MutatingWebhookConfiguration{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Name: name,
 | |
| 				},
 | |
| 				Webhooks: []admissionregistrationv1.MutatingWebhook{{
 | |
| 					Name: name,
 | |
| 					ClientConfig: admissionregistrationv1.WebhookClientConfig{
 | |
| 						Service: &admissionregistrationv1.ServiceReference{
 | |
| 							Namespace: system.Namespace(),
 | |
| 							Name:      "webhook",
 | |
| 							// Path is fixed.
 | |
| 							Path: ptr.String(path),
 | |
| 						},
 | |
| 						// CABundle is fixed.
 | |
| 						CABundle: []byte("present"),
 | |
| 					},
 | |
| 					// Rules are fixed.
 | |
| 					Rules: nil,
 | |
| 					// MatchPolicy is added.
 | |
| 					MatchPolicy: &equivalent,
 | |
| 					// Selectors are added.
 | |
| 					NamespaceSelector: &ExclusionSelector,
 | |
| 					ObjectSelector:    &ExclusionSelector,
 | |
| 				}},
 | |
| 			},
 | |
| 		}},
 | |
| 	}, {
 | |
| 		Name:    "failure updating MWH",
 | |
| 		Key:     key,
 | |
| 		WantErr: true,
 | |
| 		WithReactors: []clientgotesting.ReactionFunc{
 | |
| 			InduceFailure("update", "mutatingwebhookconfigurations"),
 | |
| 		},
 | |
| 		Objects: []runtime.Object{secret,
 | |
| 			&admissionregistrationv1.MutatingWebhookConfiguration{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Name: name,
 | |
| 				},
 | |
| 				Webhooks: []admissionregistrationv1.MutatingWebhook{{
 | |
| 					Name: name,
 | |
| 					ClientConfig: admissionregistrationv1.WebhookClientConfig{
 | |
| 						Service: &admissionregistrationv1.ServiceReference{
 | |
| 							Namespace: system.Namespace(),
 | |
| 							Name:      "webhook",
 | |
| 							// Incorrect
 | |
| 							Path: ptr.String("incorrect"),
 | |
| 						},
 | |
| 						// Incorrect
 | |
| 						CABundle: []byte("incorrect"),
 | |
| 					},
 | |
| 					// Incorrect (really just incomplete)
 | |
| 					Rules: []admissionregistrationv1.RuleWithOperations{{
 | |
| 						Operations: []admissionregistrationv1.OperationType{"CREATE", "UPDATE"},
 | |
| 						Rule: admissionregistrationv1.Rule{
 | |
| 							APIGroups:   []string{"pkg.knative.dev"},
 | |
| 							APIVersions: []string{"v1alpha1"},
 | |
| 							Resources:   []string{"innerdefaultresources/*"},
 | |
| 						},
 | |
| 					}},
 | |
| 				}},
 | |
| 			},
 | |
| 		},
 | |
| 		WantUpdates: []clientgotesting.UpdateActionImpl{{
 | |
| 			Object: &admissionregistrationv1.MutatingWebhookConfiguration{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Name: name,
 | |
| 				},
 | |
| 				Webhooks: []admissionregistrationv1.MutatingWebhook{{
 | |
| 					Name: name,
 | |
| 					ClientConfig: admissionregistrationv1.WebhookClientConfig{
 | |
| 						Service: &admissionregistrationv1.ServiceReference{
 | |
| 							Namespace: system.Namespace(),
 | |
| 							Name:      "webhook",
 | |
| 							// Path is fixed.
 | |
| 							Path: ptr.String(path),
 | |
| 						},
 | |
| 						// CABundle is fixed.
 | |
| 						CABundle: []byte("present"),
 | |
| 					},
 | |
| 					// Rules are fixed.
 | |
| 					Rules: nil,
 | |
| 					// MatchPolicy is added.
 | |
| 					MatchPolicy: &equivalent,
 | |
| 					// Selectors are added.
 | |
| 					NamespaceSelector: &ExclusionSelector,
 | |
| 					ObjectSelector:    &ExclusionSelector,
 | |
| 				}},
 | |
| 			},
 | |
| 		}},
 | |
| 	}, {
 | |
| 		Name: ":fire: everything is fine :fire:",
 | |
| 		Key:  key,
 | |
| 		Objects: []runtime.Object{secret,
 | |
| 			&admissionregistrationv1.MutatingWebhookConfiguration{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Name: name,
 | |
| 				},
 | |
| 				Webhooks: []admissionregistrationv1.MutatingWebhook{{
 | |
| 					Name: name,
 | |
| 					ClientConfig: admissionregistrationv1.WebhookClientConfig{
 | |
| 						Service: &admissionregistrationv1.ServiceReference{
 | |
| 							Namespace: system.Namespace(),
 | |
| 							Name:      "webhook",
 | |
| 							// Path is fine.
 | |
| 							Path: ptr.String(path),
 | |
| 						},
 | |
| 						// CABundle is fine.
 | |
| 						CABundle: []byte("present"),
 | |
| 					},
 | |
| 					// Rules are fine.
 | |
| 					Rules: nil,
 | |
| 					// MatchPolicy is fine.
 | |
| 					MatchPolicy: &equivalent,
 | |
| 					// Selectors are fine.
 | |
| 					NamespaceSelector: &ExclusionSelector,
 | |
| 					ObjectSelector:    &ExclusionSelector,
 | |
| 				}},
 | |
| 			},
 | |
| 		},
 | |
| 	}, {
 | |
| 		Name: "a new binding has entered the match",
 | |
| 		Key:  key,
 | |
| 		Objects: []runtime.Object{secret,
 | |
| 			&TestBindable{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Namespace: "foo",
 | |
| 					Name:      "bar",
 | |
| 				},
 | |
| 				Spec: TestBindableSpec{
 | |
| 					BindingSpec: duckv1alpha1.BindingSpec{
 | |
| 						Subject: tracker.Reference{
 | |
| 							APIVersion: "random.knative.dev/v2beta3",
 | |
| 							Kind:       "Knoodle",
 | |
| 							Namespace:  "foo",
 | |
| 							Name:       "on-it",
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 			&admissionregistrationv1.MutatingWebhookConfiguration{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Name: name,
 | |
| 				},
 | |
| 				Webhooks: []admissionregistrationv1.MutatingWebhook{{
 | |
| 					Name: name,
 | |
| 					ClientConfig: admissionregistrationv1.WebhookClientConfig{
 | |
| 						Service: &admissionregistrationv1.ServiceReference{
 | |
| 							Namespace: system.Namespace(),
 | |
| 							Name:      "webhook",
 | |
| 							// Path is fine.
 | |
| 							Path: ptr.String(path),
 | |
| 						},
 | |
| 						// CABundle is fine.
 | |
| 						CABundle: []byte("present"),
 | |
| 					},
 | |
| 					// Rules are fine.
 | |
| 					Rules: nil,
 | |
| 					// MatchPolicy is fine.
 | |
| 					MatchPolicy: &equivalent,
 | |
| 					// Selectors are fine.
 | |
| 					NamespaceSelector: &ExclusionSelector,
 | |
| 					ObjectSelector:    &ExclusionSelector,
 | |
| 				}},
 | |
| 			},
 | |
| 		},
 | |
| 		WantUpdates: []clientgotesting.UpdateActionImpl{{
 | |
| 			Object: &admissionregistrationv1.MutatingWebhookConfiguration{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Name: name,
 | |
| 				},
 | |
| 				Webhooks: []admissionregistrationv1.MutatingWebhook{{
 | |
| 					Name: name,
 | |
| 					ClientConfig: admissionregistrationv1.WebhookClientConfig{
 | |
| 						Service: &admissionregistrationv1.ServiceReference{
 | |
| 							Namespace: system.Namespace(),
 | |
| 							Name:      "webhook",
 | |
| 							Path:      ptr.String(path),
 | |
| 						},
 | |
| 						CABundle: []byte("present"),
 | |
| 					},
 | |
| 					// A new rule is added to intercept the new type.
 | |
| 					Rules: []admissionregistrationv1.RuleWithOperations{{
 | |
| 						Operations: []admissionregistrationv1.OperationType{"CREATE", "UPDATE"},
 | |
| 						Rule: admissionregistrationv1.Rule{
 | |
| 							APIGroups:   []string{"random.knative.dev"},
 | |
| 							APIVersions: []string{"v2beta3"},
 | |
| 							Resources:   []string{"knoodles/*"},
 | |
| 						},
 | |
| 					}},
 | |
| 					MatchPolicy:       &equivalent,
 | |
| 					NamespaceSelector: &ExclusionSelector,
 | |
| 					ObjectSelector:    &ExclusionSelector,
 | |
| 				}},
 | |
| 			},
 | |
| 		}},
 | |
| 	}, {
 | |
| 		Name: "steady state direct bindings",
 | |
| 		Key:  key,
 | |
| 		Objects: []runtime.Object{secret,
 | |
| 			&TestBindable{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Namespace: "foo",
 | |
| 					Name:      "bar1",
 | |
| 				},
 | |
| 				Spec: TestBindableSpec{
 | |
| 					BindingSpec: duckv1alpha1.BindingSpec{
 | |
| 						Subject: tracker.Reference{
 | |
| 							APIVersion: "random.knative.dev/v2beta3",
 | |
| 							Kind:       "Knoodle",
 | |
| 							Namespace:  "foo",
 | |
| 							Name:       "on-it",
 | |
| 						},
 | |
| 					},
 | |
| 					Foo: "one-value",
 | |
| 				},
 | |
| 			},
 | |
| 			&TestBindable{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Namespace: "foo",
 | |
| 					Name:      "bar2",
 | |
| 				},
 | |
| 				Spec: TestBindableSpec{
 | |
| 					BindingSpec: duckv1alpha1.BindingSpec{
 | |
| 						Subject: tracker.Reference{
 | |
| 							APIVersion: "apps/v1",
 | |
| 							Kind:       "Deployment",
 | |
| 							Namespace:  "foo",
 | |
| 							Name:       "on-it",
 | |
| 						},
 | |
| 					},
 | |
| 					Foo: "the-value",
 | |
| 				},
 | |
| 			},
 | |
| 			&admissionregistrationv1.MutatingWebhookConfiguration{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Name: name,
 | |
| 				},
 | |
| 				Webhooks: []admissionregistrationv1.MutatingWebhook{{
 | |
| 					Name: name,
 | |
| 					ClientConfig: admissionregistrationv1.WebhookClientConfig{
 | |
| 						Service: &admissionregistrationv1.ServiceReference{
 | |
| 							Namespace: system.Namespace(),
 | |
| 							Name:      "webhook",
 | |
| 							Path:      ptr.String(path),
 | |
| 						},
 | |
| 						CABundle: []byte("present"),
 | |
| 					},
 | |
| 					// A new rule is added to intercept the new type.
 | |
| 					Rules: []admissionregistrationv1.RuleWithOperations{{
 | |
| 						Operations: []admissionregistrationv1.OperationType{"CREATE", "UPDATE"},
 | |
| 						Rule: admissionregistrationv1.Rule{
 | |
| 							APIGroups:   []string{"apps"},
 | |
| 							APIVersions: []string{"v1"},
 | |
| 							Resources:   []string{"deployments/*"},
 | |
| 						},
 | |
| 					}, {
 | |
| 						Operations: []admissionregistrationv1.OperationType{"CREATE", "UPDATE"},
 | |
| 						Rule: admissionregistrationv1.Rule{
 | |
| 							APIGroups:   []string{"random.knative.dev"},
 | |
| 							APIVersions: []string{"v2beta3"},
 | |
| 							Resources:   []string{"knoodles/*"},
 | |
| 						},
 | |
| 					}},
 | |
| 					MatchPolicy:       &equivalent,
 | |
| 					NamespaceSelector: &ExclusionSelector,
 | |
| 					ObjectSelector:    &ExclusionSelector,
 | |
| 				}},
 | |
| 			},
 | |
| 		},
 | |
| 		// Verify that Admit properly patches deployments after being programmed
 | |
| 		// with the binding.
 | |
| 		PostConditions: []func(*testing.T, *TableRow){
 | |
| 			checkDeploymentIsPatched,
 | |
| 			checkDeploymentIsNotPatched,
 | |
| 			checkDeleteIgnored,
 | |
| 		},
 | |
| 	}, {
 | |
| 		Name: "steady state selector",
 | |
| 		Key:  key,
 | |
| 		Objects: []runtime.Object{secret,
 | |
| 			&TestBindable{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Namespace: "foo",
 | |
| 					Name:      "bar1",
 | |
| 				},
 | |
| 				Spec: TestBindableSpec{
 | |
| 					BindingSpec: duckv1alpha1.BindingSpec{
 | |
| 						Subject: tracker.Reference{
 | |
| 							APIVersion: "random.knative.dev/v2beta3",
 | |
| 							Kind:       "Knoodle",
 | |
| 							Namespace:  "foo",
 | |
| 							Selector: &metav1.LabelSelector{
 | |
| 								// Match everything.
 | |
| 								MatchLabels: map[string]string{},
 | |
| 							},
 | |
| 						},
 | |
| 					},
 | |
| 					Foo: "one-value",
 | |
| 				},
 | |
| 			},
 | |
| 			&TestBindable{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Namespace: "foo",
 | |
| 					Name:      "bar2",
 | |
| 				},
 | |
| 				Spec: TestBindableSpec{
 | |
| 					BindingSpec: duckv1alpha1.BindingSpec{
 | |
| 						Subject: tracker.Reference{
 | |
| 							APIVersion: "apps/v1",
 | |
| 							Kind:       "Deployment",
 | |
| 							Namespace:  "foo",
 | |
| 							Selector: &metav1.LabelSelector{
 | |
| 								MatchLabels: map[string]string{
 | |
| 									"foo": "bar",
 | |
| 								},
 | |
| 							},
 | |
| 						},
 | |
| 					},
 | |
| 					Foo: "the-value",
 | |
| 				},
 | |
| 			},
 | |
| 			&admissionregistrationv1.MutatingWebhookConfiguration{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Name: name,
 | |
| 				},
 | |
| 				Webhooks: []admissionregistrationv1.MutatingWebhook{{
 | |
| 					Name: name,
 | |
| 					ClientConfig: admissionregistrationv1.WebhookClientConfig{
 | |
| 						Service: &admissionregistrationv1.ServiceReference{
 | |
| 							Namespace: system.Namespace(),
 | |
| 							Name:      "webhook",
 | |
| 							Path:      ptr.String(path),
 | |
| 						},
 | |
| 						CABundle: []byte("present"),
 | |
| 					},
 | |
| 					// A new rule is added to intercept the new type.
 | |
| 					Rules: []admissionregistrationv1.RuleWithOperations{{
 | |
| 						Operations: []admissionregistrationv1.OperationType{"CREATE", "UPDATE"},
 | |
| 						Rule: admissionregistrationv1.Rule{
 | |
| 							APIGroups:   []string{"apps"},
 | |
| 							APIVersions: []string{"v1"},
 | |
| 							Resources:   []string{"deployments/*"},
 | |
| 						},
 | |
| 					}, {
 | |
| 						Operations: []admissionregistrationv1.OperationType{"CREATE", "UPDATE"},
 | |
| 						Rule: admissionregistrationv1.Rule{
 | |
| 							APIGroups:   []string{"random.knative.dev"},
 | |
| 							APIVersions: []string{"v2beta3"},
 | |
| 							Resources:   []string{"knoodles/*"},
 | |
| 						},
 | |
| 					}},
 | |
| 					MatchPolicy:       &equivalent,
 | |
| 					NamespaceSelector: &ExclusionSelector,
 | |
| 					ObjectSelector:    &ExclusionSelector,
 | |
| 				}},
 | |
| 			},
 | |
| 		},
 | |
| 		// Verify that Admit properly patches deployments after being programmed
 | |
| 		// with the binding.
 | |
| 		PostConditions: []func(*testing.T, *TableRow){
 | |
| 			checkDeploymentIsPatched,
 | |
| 			checkDeploymentIsNotPatched,
 | |
| 			checkDeleteIgnored,
 | |
| 		},
 | |
| 	}, {
 | |
| 		Name: "tombstoned binding undoes patch",
 | |
| 		Key:  key,
 | |
| 		Objects: []runtime.Object{secret,
 | |
| 			&TestBindable{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Namespace:         "foo",
 | |
| 					Name:              "bar2",
 | |
| 					DeletionTimestamp: &metav1.Time{Time: time.Now()},
 | |
| 				},
 | |
| 				Spec: TestBindableSpec{
 | |
| 					BindingSpec: duckv1alpha1.BindingSpec{
 | |
| 						Subject: tracker.Reference{
 | |
| 							APIVersion: "apps/v1",
 | |
| 							Kind:       "Deployment",
 | |
| 							Namespace:  "foo",
 | |
| 							Selector: &metav1.LabelSelector{
 | |
| 								MatchLabels: map[string]string{
 | |
| 									"foo": "bar",
 | |
| 								},
 | |
| 							},
 | |
| 						},
 | |
| 					},
 | |
| 					Foo: "the-value",
 | |
| 				},
 | |
| 			},
 | |
| 			&admissionregistrationv1.MutatingWebhookConfiguration{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Name: name,
 | |
| 				},
 | |
| 				Webhooks: []admissionregistrationv1.MutatingWebhook{{
 | |
| 					Name: name,
 | |
| 					ClientConfig: admissionregistrationv1.WebhookClientConfig{
 | |
| 						Service: &admissionregistrationv1.ServiceReference{
 | |
| 							Namespace: system.Namespace(),
 | |
| 							Name:      "webhook",
 | |
| 							Path:      ptr.String(path),
 | |
| 						},
 | |
| 						CABundle: []byte("present"),
 | |
| 					},
 | |
| 					Rules: []admissionregistrationv1.RuleWithOperations{{
 | |
| 						Operations: []admissionregistrationv1.OperationType{"CREATE", "UPDATE"},
 | |
| 						Rule: admissionregistrationv1.Rule{
 | |
| 							APIGroups:   []string{"apps"},
 | |
| 							APIVersions: []string{"v1"},
 | |
| 							Resources:   []string{"deployments/*"},
 | |
| 						},
 | |
| 					}},
 | |
| 					MatchPolicy:       &equivalent,
 | |
| 					NamespaceSelector: &ExclusionSelector,
 | |
| 					ObjectSelector:    &ExclusionSelector,
 | |
| 				}},
 | |
| 			},
 | |
| 		},
 | |
| 		// Verify that Admit properly patches deployments after being programmed
 | |
| 		// with the binding.
 | |
| 		PostConditions: []func(*testing.T, *TableRow){
 | |
| 			checkDeploymentIsPatchedBack,
 | |
| 			checkDeploymentIsNotPatched,
 | |
| 			checkDeleteIgnored,
 | |
| 		},
 | |
| 	}, {
 | |
| 		Name: "multiple new bindings have entered the match",
 | |
| 		Key:  key,
 | |
| 		Objects: []runtime.Object{secret,
 | |
| 			&TestBindable{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Namespace: "foo",
 | |
| 					Name:      "bar",
 | |
| 				},
 | |
| 				Spec: TestBindableSpec{
 | |
| 					BindingSpec: duckv1alpha1.BindingSpec{
 | |
| 						Subject: tracker.Reference{
 | |
| 							APIVersion: "random.knative.dev/v2beta3",
 | |
| 							Kind:       "Knoodle",
 | |
| 							Namespace:  "foo",
 | |
| 							Name:       "on-it",
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 			&TestBindable{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Namespace: "blah",
 | |
| 					Name:      "bazinga",
 | |
| 				},
 | |
| 				Spec: TestBindableSpec{
 | |
| 					BindingSpec: duckv1alpha1.BindingSpec{
 | |
| 						Subject: tracker.Reference{
 | |
| 							APIVersion: "pseudorandom.knative.dev/v3beta1",
 | |
| 							Kind:       "Knoogle",
 | |
| 							Namespace:  "blah",
 | |
| 							Name:       "oh-yeah",
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 			&admissionregistrationv1.MutatingWebhookConfiguration{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Name: name,
 | |
| 				},
 | |
| 				Webhooks: []admissionregistrationv1.MutatingWebhook{{
 | |
| 					Name: name,
 | |
| 					ClientConfig: admissionregistrationv1.WebhookClientConfig{
 | |
| 						Service: &admissionregistrationv1.ServiceReference{
 | |
| 							Namespace: system.Namespace(),
 | |
| 							Name:      "webhook",
 | |
| 							// Path is fine.
 | |
| 							Path: ptr.String(path),
 | |
| 						},
 | |
| 						// CABundle is fine.
 | |
| 						CABundle: []byte("present"),
 | |
| 					},
 | |
| 					// Rules are fine.
 | |
| 					Rules: nil,
 | |
| 					// MatchPolicy is fine.
 | |
| 					MatchPolicy: &equivalent,
 | |
| 					// Selectors are fine.
 | |
| 					NamespaceSelector: &ExclusionSelector,
 | |
| 					ObjectSelector:    &ExclusionSelector,
 | |
| 				}},
 | |
| 			},
 | |
| 		},
 | |
| 		WantUpdates: []clientgotesting.UpdateActionImpl{{
 | |
| 			Object: &admissionregistrationv1.MutatingWebhookConfiguration{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Name: name,
 | |
| 				},
 | |
| 				Webhooks: []admissionregistrationv1.MutatingWebhook{{
 | |
| 					Name: name,
 | |
| 					ClientConfig: admissionregistrationv1.WebhookClientConfig{
 | |
| 						Service: &admissionregistrationv1.ServiceReference{
 | |
| 							Namespace: system.Namespace(),
 | |
| 							Name:      "webhook",
 | |
| 							Path:      ptr.String(path),
 | |
| 						},
 | |
| 						CABundle: []byte("present"),
 | |
| 					},
 | |
| 					// New rules are added to intercept the new types.
 | |
| 					Rules: []admissionregistrationv1.RuleWithOperations{{
 | |
| 						Operations: []admissionregistrationv1.OperationType{"CREATE", "UPDATE"},
 | |
| 						Rule: admissionregistrationv1.Rule{
 | |
| 							APIGroups:   []string{"pseudorandom.knative.dev"},
 | |
| 							APIVersions: []string{"v3beta1"},
 | |
| 							Resources:   []string{"knoogles/*"},
 | |
| 						},
 | |
| 					}, {
 | |
| 						Operations: []admissionregistrationv1.OperationType{"CREATE", "UPDATE"},
 | |
| 						Rule: admissionregistrationv1.Rule{
 | |
| 							APIGroups:   []string{"random.knative.dev"},
 | |
| 							APIVersions: []string{"v2beta3"},
 | |
| 							Resources:   []string{"knoodles/*"},
 | |
| 						},
 | |
| 					}},
 | |
| 					MatchPolicy:       &equivalent,
 | |
| 					NamespaceSelector: &ExclusionSelector,
 | |
| 					ObjectSelector:    &ExclusionSelector,
 | |
| 				}},
 | |
| 			},
 | |
| 		}},
 | |
| 	}, {
 | |
| 		Name: "a new selector-based binding has entered the match",
 | |
| 		Key:  key,
 | |
| 		Objects: []runtime.Object{secret,
 | |
| 			&TestBindable{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Namespace: "foo",
 | |
| 					Name:      "bar",
 | |
| 				},
 | |
| 				Spec: TestBindableSpec{
 | |
| 					BindingSpec: duckv1alpha1.BindingSpec{
 | |
| 						Subject: tracker.Reference{
 | |
| 							APIVersion: "random.knative.dev/v2beta3",
 | |
| 							Kind:       "Knoodle",
 | |
| 							Namespace:  "foo",
 | |
| 							Selector: &metav1.LabelSelector{
 | |
| 								MatchLabels: map[string]string{
 | |
| 									"foo": "bar",
 | |
| 								},
 | |
| 							},
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 			&admissionregistrationv1.MutatingWebhookConfiguration{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Name: name,
 | |
| 				},
 | |
| 				Webhooks: []admissionregistrationv1.MutatingWebhook{{
 | |
| 					Name: name,
 | |
| 					ClientConfig: admissionregistrationv1.WebhookClientConfig{
 | |
| 						Service: &admissionregistrationv1.ServiceReference{
 | |
| 							Namespace: system.Namespace(),
 | |
| 							Name:      "webhook",
 | |
| 							// Path is fine.
 | |
| 							Path: ptr.String(path),
 | |
| 						},
 | |
| 						// CABundle is fine.
 | |
| 						CABundle: []byte("present"),
 | |
| 					},
 | |
| 					// Rules are fine.
 | |
| 					Rules: nil,
 | |
| 					// MatchPolicy is fine.
 | |
| 					MatchPolicy: &equivalent,
 | |
| 					// Selectors are fine.
 | |
| 					NamespaceSelector: &ExclusionSelector,
 | |
| 					ObjectSelector:    &ExclusionSelector,
 | |
| 				}},
 | |
| 			},
 | |
| 		},
 | |
| 		WantUpdates: []clientgotesting.UpdateActionImpl{{
 | |
| 			Object: &admissionregistrationv1.MutatingWebhookConfiguration{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Name: name,
 | |
| 				},
 | |
| 				Webhooks: []admissionregistrationv1.MutatingWebhook{{
 | |
| 					Name: name,
 | |
| 					ClientConfig: admissionregistrationv1.WebhookClientConfig{
 | |
| 						Service: &admissionregistrationv1.ServiceReference{
 | |
| 							Namespace: system.Namespace(),
 | |
| 							Name:      "webhook",
 | |
| 							Path:      ptr.String(path),
 | |
| 						},
 | |
| 						CABundle: []byte("present"),
 | |
| 					},
 | |
| 					// A new rule is added to intercept the new type.
 | |
| 					Rules: []admissionregistrationv1.RuleWithOperations{{
 | |
| 						Operations: []admissionregistrationv1.OperationType{"CREATE", "UPDATE"},
 | |
| 						Rule: admissionregistrationv1.Rule{
 | |
| 							APIGroups:   []string{"random.knative.dev"},
 | |
| 							APIVersions: []string{"v2beta3"},
 | |
| 							Resources:   []string{"knoodles/*"},
 | |
| 						},
 | |
| 					}},
 | |
| 					MatchPolicy:       &equivalent,
 | |
| 					NamespaceSelector: &ExclusionSelector,
 | |
| 					ObjectSelector:    &ExclusionSelector,
 | |
| 				}},
 | |
| 			},
 | |
| 		}},
 | |
| 	}}
 | |
| 
 | |
| 	table.Test(t, MakeFactory(func(ctx context.Context, listers *Listers, cmw configmap.Watcher) controller.Reconciler {
 | |
| 		r := NewReconciler(name, path, secretName, kubeclient.Get(ctx), listers.GetMutatingWebhookConfigurationLister(), listers.GetSecretLister(), nil)
 | |
| 		r.ListAll = func() ([]Bindable, error) {
 | |
| 			bl := make([]Bindable, 0)
 | |
| 			for _, elt := range listers.GetDuckObjects() {
 | |
| 				b, ok := elt.(Bindable)
 | |
| 				if !ok {
 | |
| 					continue
 | |
| 				}
 | |
| 				bl = append(bl, b)
 | |
| 			}
 | |
| 			return bl, nil
 | |
| 		}
 | |
| 		return r
 | |
| 	}))
 | |
| }
 | |
| 
 | |
| func TestNew(t *testing.T) {
 | |
| 	ctx, _ := SetupFakeContext(t)
 | |
| 	ctx = webhook.WithOptions(ctx, webhook.Options{})
 | |
| 
 | |
| 	c := NewAdmissionController(ctx, "foo", "/bar",
 | |
| 		func(context.Context, cache.ResourceEventHandler) ListAll {
 | |
| 			return func() ([]Bindable, error) {
 | |
| 				return nil, nil
 | |
| 			}
 | |
| 		},
 | |
| 		func(ctx context.Context, b Bindable) (context.Context, error) {
 | |
| 			return ctx, nil
 | |
| 		})
 | |
| 	if c == nil {
 | |
| 		t.Fatal("Expected NewController to return a non-nil value")
 | |
| 	}
 | |
| 
 | |
| 	if want, got := 0, c.WorkQueue().Len(); want != got {
 | |
| 		t.Errorf("WorkQueue.Len() = %d, wanted %d", got, want)
 | |
| 	}
 | |
| 
 | |
| 	la, ok := c.Reconciler.(pkgreconciler.LeaderAware)
 | |
| 	if !ok {
 | |
| 		t.Fatalf("%T is not leader aware", c.Reconciler)
 | |
| 	}
 | |
| 
 | |
| 	if err := la.Promote(pkgreconciler.UniversalBucket(), c.MaybeEnqueueBucketKey); err != nil {
 | |
| 		t.Error("Promote() =", err)
 | |
| 	}
 | |
| 
 | |
| 	// Queue has async moving parts so if we check at the wrong moment, this might still be 0.
 | |
| 	if wait.PollImmediate(10*time.Millisecond, 250*time.Millisecond, func() (bool, error) {
 | |
| 		return c.WorkQueue().Len() == 1, nil
 | |
| 	}) != nil {
 | |
| 		t.Error("Queue length was never 1")
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestNewReconciler(t *testing.T) {
 | |
| 	ctx, _ := SetupFakeContext(t)
 | |
| 	ctx = webhook.WithOptions(ctx, webhook.Options{})
 | |
| 	tests := []struct {
 | |
| 		name           string
 | |
| 		selectorOption ReconcilerOption
 | |
| 		wantSelector   metav1.LabelSelector
 | |
| 	}{
 | |
| 		{
 | |
| 			name:         "no selector, use default",
 | |
| 			wantSelector: ExclusionSelector,
 | |
| 		},
 | |
| 		{
 | |
| 			name:           "ExclusionSelector option",
 | |
| 			selectorOption: WithSelector(ExclusionSelector),
 | |
| 			wantSelector:   ExclusionSelector,
 | |
| 		},
 | |
| 		{
 | |
| 			name:           "InclusionSelector option",
 | |
| 			selectorOption: WithSelector(InclusionSelector),
 | |
| 			wantSelector:   InclusionSelector,
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	for _, tt := range tests {
 | |
| 		t.Run(tt.name, func(t *testing.T) {
 | |
| 			client := kubeclient.Get(ctx)
 | |
| 			mwhInformer := mwhinformer.Get(ctx)
 | |
| 			secretInformer := secretinformer.Get(ctx)
 | |
| 			withContext := func(ctx context.Context, b Bindable) (context.Context, error) {
 | |
| 				return ctx, nil
 | |
| 			}
 | |
| 			var r *Reconciler
 | |
| 			if tt.selectorOption == nil {
 | |
| 				r = NewReconciler("foo", "/bar", "foosec", client, mwhInformer.Lister(), secretInformer.Lister(), withContext)
 | |
| 			} else {
 | |
| 				r = NewReconciler("foo", "/bar", "foosec", client, mwhInformer.Lister(), secretInformer.Lister(), withContext, tt.selectorOption)
 | |
| 			}
 | |
| 			if diff := cmp.Diff(r.selector, tt.wantSelector); diff != "" {
 | |
| 				t.Errorf("Wrong selector configured. Got: %+v, want: %+v, diff: %v", r.selector, tt.wantSelector, diff)
 | |
| 			}
 | |
| 		})
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestBaseReconcile(t *testing.T) {
 | |
| 	table := TableTest{{
 | |
| 		Name: "bad key",
 | |
| 		Key:  "this/is/a/bad/key",
 | |
| 	}, {
 | |
| 		Name: "not found",
 | |
| 		Key:  "its/missing",
 | |
| 	}, {
 | |
| 		Name: "add finalizer, add env var",
 | |
| 		Key:  "foo/bar",
 | |
| 		Objects: []runtime.Object{
 | |
| 			&TestBindable{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Namespace: "foo",
 | |
| 					Name:      "bar",
 | |
| 				},
 | |
| 				Spec: TestBindableSpec{
 | |
| 					BindingSpec: duckv1alpha1.BindingSpec{
 | |
| 						Subject: tracker.Reference{
 | |
| 							APIVersion: "apps/v1",
 | |
| 							Kind:       "Deployment",
 | |
| 							Namespace:  "foo",
 | |
| 							Name:       "on-it",
 | |
| 						},
 | |
| 					},
 | |
| 					Foo: "asdfasdfasdfasdf",
 | |
| 				},
 | |
| 			},
 | |
| 			&appsv1.Deployment{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Namespace: "foo",
 | |
| 					Name:      "on-it",
 | |
| 				},
 | |
| 				Spec: appsv1.DeploymentSpec{
 | |
| 					Template: corev1.PodTemplateSpec{
 | |
| 						Spec: corev1.PodSpec{
 | |
| 							Containers: []corev1.Container{{
 | |
| 								Name:  "foo",
 | |
| 								Image: "busybox",
 | |
| 							}},
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 			&corev1.Namespace{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Name: "foo",
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 		WantStatusUpdates: []clientgotesting.UpdateActionImpl{{
 | |
| 			Object: mustTU(t, &TestBindable{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Namespace: "foo",
 | |
| 					Name:      "bar",
 | |
| 				},
 | |
| 				Spec: TestBindableSpec{
 | |
| 					BindingSpec: duckv1alpha1.BindingSpec{
 | |
| 						Subject: tracker.Reference{
 | |
| 							APIVersion: "apps/v1",
 | |
| 							Kind:       "Deployment",
 | |
| 							Namespace:  "foo",
 | |
| 							Name:       "on-it",
 | |
| 						},
 | |
| 					},
 | |
| 					Foo: "asdfasdfasdfasdf",
 | |
| 				},
 | |
| 				Status: TestBindableStatus{
 | |
| 					Status: duckv1.Status{
 | |
| 						Conditions: []apis.Condition{{
 | |
| 							Type:   "Ready",
 | |
| 							Status: "True",
 | |
| 						}},
 | |
| 					},
 | |
| 				},
 | |
| 			}),
 | |
| 		}},
 | |
| 		WantPatches: []clientgotesting.PatchActionImpl{
 | |
| 			patchAddFinalizer("foo", "bar", "" /* resource version */),
 | |
| 			patchAddLabel("foo"),
 | |
| 			patchAddEnv("foo", "on-it", "asdfasdfasdfasdf"),
 | |
| 		},
 | |
| 	}, {
 | |
| 		Name:    "failure adding finalizer",
 | |
| 		Key:     "foo/bar",
 | |
| 		WantErr: true,
 | |
| 		WithReactors: []clientgotesting.ReactionFunc{
 | |
| 			InduceFailure("patch", "testbindables"),
 | |
| 		},
 | |
| 		Objects: []runtime.Object{
 | |
| 			&TestBindable{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Namespace: "foo",
 | |
| 					Name:      "bar",
 | |
| 				},
 | |
| 				Spec: TestBindableSpec{
 | |
| 					BindingSpec: duckv1alpha1.BindingSpec{
 | |
| 						Subject: tracker.Reference{
 | |
| 							APIVersion: "apps/v1",
 | |
| 							Kind:       "Deployment",
 | |
| 							Namespace:  "foo",
 | |
| 							Name:       "on-it",
 | |
| 						},
 | |
| 					},
 | |
| 					Foo: "asdfasdfasdfasdf",
 | |
| 				},
 | |
| 				Status: TestBindableStatus{
 | |
| 					Status: duckv1.Status{
 | |
| 						Conditions: []apis.Condition{{
 | |
| 							Type:   "Ready",
 | |
| 							Status: "True",
 | |
| 						}},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 		WantPatches: []clientgotesting.PatchActionImpl{
 | |
| 			patchAddFinalizer("foo", "bar", "" /* resource version */),
 | |
| 		},
 | |
| 	}, {
 | |
| 		Name:    "failure patching deployment",
 | |
| 		Key:     "foo/bar",
 | |
| 		WantErr: true,
 | |
| 		WithReactors: []clientgotesting.ReactionFunc{
 | |
| 			InduceFailure("patch", "deployments"),
 | |
| 		},
 | |
| 		Objects: []runtime.Object{
 | |
| 			&TestBindable{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Namespace:  "foo",
 | |
| 					Name:       "bar",
 | |
| 					Finalizers: []string{"testbindables.duck.knative.dev"},
 | |
| 				},
 | |
| 				Spec: TestBindableSpec{
 | |
| 					BindingSpec: duckv1alpha1.BindingSpec{
 | |
| 						Subject: tracker.Reference{
 | |
| 							APIVersion: "apps/v1",
 | |
| 							Kind:       "Deployment",
 | |
| 							Namespace:  "foo",
 | |
| 							Name:       "on-it",
 | |
| 						},
 | |
| 					},
 | |
| 					Foo: "asdfasdfasdfasdf",
 | |
| 				},
 | |
| 				Status: TestBindableStatus{
 | |
| 					Status: duckv1.Status{
 | |
| 						Conditions: []apis.Condition{{
 | |
| 							Type:   "Ready",
 | |
| 							Status: "True",
 | |
| 						}},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 			&corev1.Namespace{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Name:   "foo",
 | |
| 					Labels: map[string]string{duck.BindingIncludeLabel: "true"},
 | |
| 				},
 | |
| 			},
 | |
| 			&appsv1.Deployment{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Namespace: "foo",
 | |
| 					Name:      "on-it",
 | |
| 				},
 | |
| 				Spec: appsv1.DeploymentSpec{
 | |
| 					Template: corev1.PodTemplateSpec{
 | |
| 						Spec: corev1.PodSpec{
 | |
| 							Containers: []corev1.Container{{
 | |
| 								Name:  "foo",
 | |
| 								Image: "busybox",
 | |
| 							}},
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 		WantPatches: []clientgotesting.PatchActionImpl{
 | |
| 			patchAddEnv("foo", "on-it", "asdfasdfasdfasdf"),
 | |
| 		},
 | |
| 		WantStatusUpdates: []clientgotesting.UpdateActionImpl{{
 | |
| 			Object: mustTU(t, &TestBindable{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Namespace:  "foo",
 | |
| 					Name:       "bar",
 | |
| 					Finalizers: []string{"testbindables.duck.knative.dev"},
 | |
| 				},
 | |
| 				Spec: TestBindableSpec{
 | |
| 					BindingSpec: duckv1alpha1.BindingSpec{
 | |
| 						Subject: tracker.Reference{
 | |
| 							APIVersion: "apps/v1",
 | |
| 							Kind:       "Deployment",
 | |
| 							Namespace:  "foo",
 | |
| 							Name:       "on-it",
 | |
| 						},
 | |
| 					},
 | |
| 					Foo: "asdfasdfasdfasdf",
 | |
| 				},
 | |
| 				Status: TestBindableStatus{
 | |
| 					Status: duckv1.Status{
 | |
| 						Conditions: []apis.Condition{{
 | |
| 							Type:    "Ready",
 | |
| 							Status:  "False",
 | |
| 							Reason:  "BindingFailed",
 | |
| 							Message: "failed binding subject on-it: inducing failure for patch deployments",
 | |
| 						}},
 | |
| 					},
 | |
| 				},
 | |
| 			}),
 | |
| 		}},
 | |
| 	}, {
 | |
| 		Name: "steady state",
 | |
| 		Key:  "foo/bar",
 | |
| 		Objects: []runtime.Object{
 | |
| 			&TestBindable{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Namespace:  "foo",
 | |
| 					Name:       "bar",
 | |
| 					Finalizers: []string{"testbindables.duck.knative.dev"},
 | |
| 				},
 | |
| 				Spec: TestBindableSpec{
 | |
| 					BindingSpec: duckv1alpha1.BindingSpec{
 | |
| 						Subject: tracker.Reference{
 | |
| 							APIVersion: "apps/v1",
 | |
| 							Kind:       "Deployment",
 | |
| 							Namespace:  "foo",
 | |
| 							Name:       "on-it",
 | |
| 						},
 | |
| 					},
 | |
| 					Foo: "asdfasdfasdfasdf",
 | |
| 				},
 | |
| 				Status: TestBindableStatus{
 | |
| 					Status: duckv1.Status{
 | |
| 						Conditions: []apis.Condition{{
 | |
| 							Type:   "Ready",
 | |
| 							Status: "True",
 | |
| 						}},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 			&appsv1.Deployment{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Namespace: "foo",
 | |
| 					Name:      "on-it",
 | |
| 				},
 | |
| 				Spec: appsv1.DeploymentSpec{
 | |
| 					Template: corev1.PodTemplateSpec{
 | |
| 						Spec: corev1.PodSpec{
 | |
| 							Containers: []corev1.Container{{
 | |
| 								Name:  "foo",
 | |
| 								Image: "busybox",
 | |
| 								Env: []corev1.EnvVar{{
 | |
| 									Name:  "FOO",
 | |
| 									Value: "asdfasdfasdfasdf",
 | |
| 								}},
 | |
| 							}},
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 			&corev1.Namespace{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Name: "foo",
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 		WantPatches: []clientgotesting.PatchActionImpl{
 | |
| 			patchAddLabel("foo"),
 | |
| 		},
 | |
| 	}, {
 | |
| 		Name: "finalizing, but not our turn.",
 | |
| 		Key:  "foo/bar",
 | |
| 		Objects: []runtime.Object{
 | |
| 			&TestBindable{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Namespace:         "foo",
 | |
| 					Name:              "bar",
 | |
| 					DeletionTimestamp: &metav1.Time{Time: time.Now()},
 | |
| 					Finalizers: []string{
 | |
| 						"slow.your.role",
 | |
| 						"testbindables.duck.knative.dev",
 | |
| 					},
 | |
| 				},
 | |
| 				Spec: TestBindableSpec{
 | |
| 					BindingSpec: duckv1alpha1.BindingSpec{
 | |
| 						Subject: tracker.Reference{
 | |
| 							APIVersion: "apps/v1",
 | |
| 							Kind:       "Deployment",
 | |
| 							Namespace:  "foo",
 | |
| 							Name:       "on-it",
 | |
| 						},
 | |
| 					},
 | |
| 					Foo: "new value",
 | |
| 				},
 | |
| 				Status: TestBindableStatus{
 | |
| 					Status: duckv1.Status{
 | |
| 						Conditions: []apis.Condition{{
 | |
| 							Type:   "Ready",
 | |
| 							Status: "True",
 | |
| 						}},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 	}, {
 | |
| 		Name: "finalizing, missing subject (remove the finalizer).",
 | |
| 		Key:  "foo/bar",
 | |
| 		Objects: []runtime.Object{
 | |
| 			&TestBindable{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Namespace:         "foo",
 | |
| 					Name:              "bar",
 | |
| 					DeletionTimestamp: &metav1.Time{Time: time.Now()},
 | |
| 					Finalizers: []string{
 | |
| 						"testbindables.duck.knative.dev",
 | |
| 					},
 | |
| 				},
 | |
| 				Spec: TestBindableSpec{
 | |
| 					BindingSpec: duckv1alpha1.BindingSpec{
 | |
| 						Subject: tracker.Reference{
 | |
| 							APIVersion: "apps/v1",
 | |
| 							Kind:       "Deployment",
 | |
| 							Namespace:  "foo",
 | |
| 							Name:       "on-it",
 | |
| 						},
 | |
| 					},
 | |
| 					Foo: "new value",
 | |
| 				},
 | |
| 				Status: TestBindableStatus{
 | |
| 					Status: duckv1.Status{
 | |
| 						Conditions: []apis.Condition{{
 | |
| 							Type:    "Ready",
 | |
| 							Status:  "False",
 | |
| 							Reason:  "SubjectMissing",
 | |
| 							Message: `deployments.apps "on-it" not found`,
 | |
| 						}},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 		WantPatches: []clientgotesting.PatchActionImpl{
 | |
| 			patchRemoveFinalizer("foo", "bar", "" /* resource version */),
 | |
| 		},
 | |
| 	}, {
 | |
| 		Name: "finalizing forbidden subject",
 | |
| 		Key:  "foo/bar",
 | |
| 		WithReactors: []clientgotesting.ReactionFunc{
 | |
| 			// This will cause the duck informer factory to return a Forbidden error on Get(gvr)
 | |
| 			// The informer calls list to ensure the type exists - this will
 | |
| 			func(a clientgotesting.Action) (handled bool, ret runtime.Object, err error) {
 | |
| 				if a.Matches("list", "deployments") {
 | |
| 					return true, nil, apierrs.NewForbidden(schema.GroupResource{}, "", errors.New("some-error"))
 | |
| 				}
 | |
| 				return false, nil, nil
 | |
| 			},
 | |
| 		},
 | |
| 		Objects: []runtime.Object{
 | |
| 			&TestBindable{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Namespace:         "foo",
 | |
| 					Name:              "bar",
 | |
| 					DeletionTimestamp: &metav1.Time{Time: time.Now()},
 | |
| 					Finalizers:        []string{"testbindables.duck.knative.dev"},
 | |
| 				},
 | |
| 				Spec: TestBindableSpec{
 | |
| 					BindingSpec: duckv1alpha1.BindingSpec{
 | |
| 						Subject: tracker.Reference{
 | |
| 							APIVersion: "apps/v1",
 | |
| 							Kind:       "Deployment",
 | |
| 							Namespace:  "foo",
 | |
| 							Name:       "on-it",
 | |
| 						},
 | |
| 					},
 | |
| 					Foo: "new value",
 | |
| 				},
 | |
| 				Status: TestBindableStatus{
 | |
| 					Status: duckv1.Status{
 | |
| 						Conditions: []apis.Condition{{
 | |
| 							Type:   "Ready",
 | |
| 							Status: "True",
 | |
| 						}},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 		WantPatches: []clientgotesting.PatchActionImpl{
 | |
| 			patchRemoveFinalizer("foo", "bar", "" /* resource version */),
 | |
| 		},
 | |
| 		WantStatusUpdates: []clientgotesting.UpdateActionImpl{{
 | |
| 			Object: mustTU(t, &TestBindable{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Namespace:         "foo",
 | |
| 					Name:              "bar",
 | |
| 					DeletionTimestamp: &metav1.Time{Time: time.Now()},
 | |
| 					Finalizers:        []string{"testbindables.duck.knative.dev"},
 | |
| 				},
 | |
| 				Spec: TestBindableSpec{
 | |
| 					BindingSpec: duckv1alpha1.BindingSpec{
 | |
| 						Subject: tracker.Reference{
 | |
| 							APIVersion: "apps/v1",
 | |
| 							Kind:       "Deployment",
 | |
| 							Namespace:  "foo",
 | |
| 							Name:       "on-it",
 | |
| 						},
 | |
| 					},
 | |
| 					Foo: "new value",
 | |
| 				},
 | |
| 				Status: TestBindableStatus{
 | |
| 					Status: duckv1.Status{
 | |
| 						Conditions: []apis.Condition{{
 | |
| 							Type:   "Ready",
 | |
| 							Status: "False",
 | |
| 							Reason: "SubjectUnavailable",
 | |
| 							// prefix comes from apierrs.NewForbidden
 | |
| 							Message: "forbidden: some-error",
 | |
| 						}},
 | |
| 					},
 | |
| 				},
 | |
| 			}),
 | |
| 		}},
 | |
| 	}, {
 | |
| 		Name: "finalizing (unbind, and remove the finalizer)",
 | |
| 		Key:  "foo/bar",
 | |
| 		Objects: []runtime.Object{
 | |
| 			&TestBindable{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Namespace:         "foo",
 | |
| 					Name:              "bar",
 | |
| 					DeletionTimestamp: &metav1.Time{Time: time.Now()},
 | |
| 					Finalizers: []string{
 | |
| 						"testbindables.duck.knative.dev",
 | |
| 					},
 | |
| 				},
 | |
| 				Spec: TestBindableSpec{
 | |
| 					BindingSpec: duckv1alpha1.BindingSpec{
 | |
| 						Subject: tracker.Reference{
 | |
| 							APIVersion: "apps/v1",
 | |
| 							Kind:       "Deployment",
 | |
| 							Namespace:  "foo",
 | |
| 							Name:       "on-it",
 | |
| 						},
 | |
| 					},
 | |
| 					Foo: "value",
 | |
| 				},
 | |
| 				Status: TestBindableStatus{
 | |
| 					Status: duckv1.Status{
 | |
| 						Conditions: []apis.Condition{{
 | |
| 							Type:   "Ready",
 | |
| 							Status: "True",
 | |
| 						}},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 			&appsv1.Deployment{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Namespace: "foo",
 | |
| 					Name:      "on-it",
 | |
| 				},
 | |
| 				Spec: appsv1.DeploymentSpec{
 | |
| 					Template: corev1.PodTemplateSpec{
 | |
| 						Spec: corev1.PodSpec{
 | |
| 							Containers: []corev1.Container{{
 | |
| 								Name:  "foo",
 | |
| 								Image: "busybox",
 | |
| 								Env: []corev1.EnvVar{{
 | |
| 									Name:  "FOO",
 | |
| 									Value: "value",
 | |
| 								}},
 | |
| 							}},
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 			&corev1.Namespace{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Name: "foo",
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 		WantPatches: []clientgotesting.PatchActionImpl{
 | |
| 			patchAddLabel("foo"),
 | |
| 			patchRemoveEnv("foo", "on-it"),
 | |
| 			patchRemoveFinalizer("foo", "bar", "" /* resource version */),
 | |
| 		},
 | |
| 	}, {
 | |
| 		Name: "add finalizer, add env var (via selector)",
 | |
| 		Key:  "foo/bar",
 | |
| 		Objects: []runtime.Object{
 | |
| 			&TestBindable{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Namespace: "foo",
 | |
| 					Name:      "bar",
 | |
| 				},
 | |
| 				Spec: TestBindableSpec{
 | |
| 					BindingSpec: duckv1alpha1.BindingSpec{
 | |
| 						Subject: tracker.Reference{
 | |
| 							APIVersion: "apps/v1",
 | |
| 							Kind:       "Deployment",
 | |
| 							Namespace:  "foo",
 | |
| 							Selector: &metav1.LabelSelector{
 | |
| 								MatchLabels: map[string]string{},
 | |
| 							},
 | |
| 						},
 | |
| 					},
 | |
| 					Foo: "asdfasdfasdfasdf",
 | |
| 				},
 | |
| 				Status: TestBindableStatus{
 | |
| 					Status: duckv1.Status{
 | |
| 						Conditions: []apis.Condition{{
 | |
| 							Type:   "Ready",
 | |
| 							Status: "True",
 | |
| 						}},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 			&appsv1.Deployment{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Namespace: "foo",
 | |
| 					Name:      "on-it",
 | |
| 				},
 | |
| 				Spec: appsv1.DeploymentSpec{
 | |
| 					Template: corev1.PodTemplateSpec{
 | |
| 						Spec: corev1.PodSpec{
 | |
| 							Containers: []corev1.Container{{
 | |
| 								Name:  "foo",
 | |
| 								Image: "busybox",
 | |
| 							}},
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 			&corev1.Namespace{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Name: "foo",
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 		WantPatches: []clientgotesting.PatchActionImpl{
 | |
| 			patchAddFinalizer("foo", "bar", "" /* resource version */),
 | |
| 			patchAddLabel("foo"),
 | |
| 			patchAddEnv("foo", "on-it", "asdfasdfasdfasdf"),
 | |
| 		},
 | |
| 	}, {
 | |
| 		Name: "steady state (via selector)",
 | |
| 		Key:  "foo/bar",
 | |
| 		Objects: []runtime.Object{
 | |
| 			&TestBindable{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Namespace:  "foo",
 | |
| 					Name:       "bar",
 | |
| 					Finalizers: []string{"testbindables.duck.knative.dev"},
 | |
| 				},
 | |
| 				Spec: TestBindableSpec{
 | |
| 					BindingSpec: duckv1alpha1.BindingSpec{
 | |
| 						Subject: tracker.Reference{
 | |
| 							APIVersion: "apps/v1",
 | |
| 							Kind:       "Deployment",
 | |
| 							Namespace:  "foo",
 | |
| 							Selector: &metav1.LabelSelector{
 | |
| 								MatchLabels: map[string]string{},
 | |
| 							},
 | |
| 						},
 | |
| 					},
 | |
| 					Foo: "asdfasdfasdfasdf",
 | |
| 				},
 | |
| 				Status: TestBindableStatus{
 | |
| 					Status: duckv1.Status{
 | |
| 						Conditions: []apis.Condition{{
 | |
| 							Type:   "Ready",
 | |
| 							Status: "True",
 | |
| 						}},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 			&appsv1.Deployment{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Namespace: "foo",
 | |
| 					Name:      "on-it",
 | |
| 				},
 | |
| 				Spec: appsv1.DeploymentSpec{
 | |
| 					Template: corev1.PodTemplateSpec{
 | |
| 						Spec: corev1.PodSpec{
 | |
| 							Containers: []corev1.Container{{
 | |
| 								Name:  "foo",
 | |
| 								Image: "busybox",
 | |
| 								Env: []corev1.EnvVar{{
 | |
| 									Name:  "FOO",
 | |
| 									Value: "asdfasdfasdfasdf",
 | |
| 								}},
 | |
| 							}},
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 			&corev1.Namespace{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Name: "foo",
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 		WantPatches: []clientgotesting.PatchActionImpl{
 | |
| 			patchAddLabel("foo"),
 | |
| 		},
 | |
| 	}, {
 | |
| 		Name: "finalizing, missing subject (remove the finalizer, via selector)",
 | |
| 		Key:  "foo/bar",
 | |
| 		Objects: []runtime.Object{
 | |
| 			&TestBindable{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Namespace:         "foo",
 | |
| 					Name:              "bar",
 | |
| 					DeletionTimestamp: &metav1.Time{Time: time.Now()},
 | |
| 					Finalizers: []string{
 | |
| 						"testbindables.duck.knative.dev",
 | |
| 					},
 | |
| 				},
 | |
| 				Spec: TestBindableSpec{
 | |
| 					BindingSpec: duckv1alpha1.BindingSpec{
 | |
| 						Subject: tracker.Reference{
 | |
| 							APIVersion: "apps/v1",
 | |
| 							Kind:       "Deployment",
 | |
| 							Namespace:  "foo",
 | |
| 							Selector: &metav1.LabelSelector{
 | |
| 								MatchLabels: map[string]string{},
 | |
| 							},
 | |
| 						},
 | |
| 					},
 | |
| 					Foo: "new value",
 | |
| 				},
 | |
| 				Status: TestBindableStatus{
 | |
| 					Status: duckv1.Status{
 | |
| 						Conditions: []apis.Condition{{
 | |
| 							Type:   "Ready",
 | |
| 							Status: "True",
 | |
| 						}},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 			&corev1.Namespace{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Name: "foo",
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 		WantPatches: []clientgotesting.PatchActionImpl{
 | |
| 			patchAddLabel("foo"),
 | |
| 			patchRemoveFinalizer("foo", "bar", "" /* resource version */),
 | |
| 		},
 | |
| 	}, {
 | |
| 		Name: "finalizing (unbind, and remove the finalizer, via selector)",
 | |
| 		Key:  "foo/bar",
 | |
| 		Objects: []runtime.Object{
 | |
| 			&TestBindable{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Namespace:         "foo",
 | |
| 					Name:              "bar",
 | |
| 					DeletionTimestamp: &metav1.Time{Time: time.Now()},
 | |
| 					Finalizers: []string{
 | |
| 						"testbindables.duck.knative.dev",
 | |
| 					},
 | |
| 				},
 | |
| 				Spec: TestBindableSpec{
 | |
| 					BindingSpec: duckv1alpha1.BindingSpec{
 | |
| 						Subject: tracker.Reference{
 | |
| 							APIVersion: "apps/v1",
 | |
| 							Kind:       "Deployment",
 | |
| 							Namespace:  "foo",
 | |
| 							Selector: &metav1.LabelSelector{
 | |
| 								MatchLabels: map[string]string{},
 | |
| 							},
 | |
| 						},
 | |
| 					},
 | |
| 					Foo: "value",
 | |
| 				},
 | |
| 				Status: TestBindableStatus{
 | |
| 					Status: duckv1.Status{
 | |
| 						Conditions: []apis.Condition{{
 | |
| 							Type:   "Ready",
 | |
| 							Status: "True",
 | |
| 						}},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 			&appsv1.Deployment{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Namespace: "foo",
 | |
| 					Name:      "on-it",
 | |
| 				},
 | |
| 				Spec: appsv1.DeploymentSpec{
 | |
| 					Template: corev1.PodTemplateSpec{
 | |
| 						Spec: corev1.PodSpec{
 | |
| 							Containers: []corev1.Container{{
 | |
| 								Name:  "foo",
 | |
| 								Image: "busybox",
 | |
| 								Env: []corev1.EnvVar{{
 | |
| 									Name:  "FOO",
 | |
| 									Value: "value",
 | |
| 								}},
 | |
| 							}},
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 			&corev1.Namespace{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Name: "foo",
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 		WantPatches: []clientgotesting.PatchActionImpl{
 | |
| 			patchAddLabel("foo"),
 | |
| 			patchRemoveEnv("foo", "on-it"),
 | |
| 			patchRemoveFinalizer("foo", "bar", "" /* resource version */),
 | |
| 		},
 | |
| 	}, {
 | |
| 		Name:    "failure updating status",
 | |
| 		Key:     "foo/bar",
 | |
| 		WantErr: true,
 | |
| 		WithReactors: []clientgotesting.ReactionFunc{
 | |
| 			InduceFailure("update", "testbindables"),
 | |
| 		},
 | |
| 		Objects: []runtime.Object{
 | |
| 			&TestBindable{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Namespace:  "foo",
 | |
| 					Name:       "bar",
 | |
| 					Finalizers: []string{"testbindables.duck.knative.dev"},
 | |
| 				},
 | |
| 				Spec: TestBindableSpec{
 | |
| 					BindingSpec: duckv1alpha1.BindingSpec{
 | |
| 						Subject: tracker.Reference{
 | |
| 							APIVersion: "apps/v1",
 | |
| 							Kind:       "Deployment",
 | |
| 							Namespace:  "foo",
 | |
| 							Name:       "on-it",
 | |
| 						},
 | |
| 					},
 | |
| 					Foo: "asdfasdfasdfasdf",
 | |
| 				},
 | |
| 			},
 | |
| 			&appsv1.Deployment{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Namespace: "foo",
 | |
| 					Name:      "on-it",
 | |
| 				},
 | |
| 				Spec: appsv1.DeploymentSpec{
 | |
| 					Template: corev1.PodTemplateSpec{
 | |
| 						Spec: corev1.PodSpec{
 | |
| 							Containers: []corev1.Container{{
 | |
| 								Name:  "foo",
 | |
| 								Image: "busybox",
 | |
| 								Env: []corev1.EnvVar{{
 | |
| 									Name:  "FOO",
 | |
| 									Value: "asdfasdfasdfasdf",
 | |
| 								}},
 | |
| 							}},
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 			&corev1.Namespace{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Name: "foo",
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 		WantPatches: []clientgotesting.PatchActionImpl{
 | |
| 			patchAddLabel("foo"),
 | |
| 		},
 | |
| 		WantStatusUpdates: []clientgotesting.UpdateActionImpl{{
 | |
| 			Object: mustTU(t, &TestBindable{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Namespace:  "foo",
 | |
| 					Name:       "bar",
 | |
| 					Finalizers: []string{"testbindables.duck.knative.dev"},
 | |
| 				},
 | |
| 				Spec: TestBindableSpec{
 | |
| 					BindingSpec: duckv1alpha1.BindingSpec{
 | |
| 						Subject: tracker.Reference{
 | |
| 							APIVersion: "apps/v1",
 | |
| 							Kind:       "Deployment",
 | |
| 							Namespace:  "foo",
 | |
| 							Name:       "on-it",
 | |
| 						},
 | |
| 					},
 | |
| 					Foo: "asdfasdfasdfasdf",
 | |
| 				},
 | |
| 				Status: TestBindableStatus{
 | |
| 					Status: duckv1.Status{
 | |
| 						Conditions: []apis.Condition{{
 | |
| 							Type:   "Ready",
 | |
| 							Status: "True",
 | |
| 						}},
 | |
| 					},
 | |
| 				},
 | |
| 			}),
 | |
| 		}},
 | |
| 	}, {
 | |
| 		Name:    "finalizing (error during unbind)",
 | |
| 		Key:     "foo/bar",
 | |
| 		WantErr: true,
 | |
| 		WithReactors: []clientgotesting.ReactionFunc{
 | |
| 			InduceFailure("patch", "deployments"),
 | |
| 		},
 | |
| 		Objects: []runtime.Object{
 | |
| 			&TestBindable{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Namespace:         "foo",
 | |
| 					Name:              "bar",
 | |
| 					DeletionTimestamp: &metav1.Time{Time: time.Now()},
 | |
| 					Finalizers: []string{
 | |
| 						"testbindables.duck.knative.dev",
 | |
| 					},
 | |
| 				},
 | |
| 				Spec: TestBindableSpec{
 | |
| 					BindingSpec: duckv1alpha1.BindingSpec{
 | |
| 						Subject: tracker.Reference{
 | |
| 							APIVersion: "apps/v1",
 | |
| 							Kind:       "Deployment",
 | |
| 							Namespace:  "foo",
 | |
| 							Selector: &metav1.LabelSelector{
 | |
| 								MatchLabels: map[string]string{},
 | |
| 							},
 | |
| 						},
 | |
| 					},
 | |
| 					Foo: "value",
 | |
| 				},
 | |
| 				Status: TestBindableStatus{
 | |
| 					Status: duckv1.Status{
 | |
| 						Conditions: []apis.Condition{{
 | |
| 							Type:    "Ready",
 | |
| 							Status:  "False",
 | |
| 							Reason:  "BindingFailed",
 | |
| 							Message: "failed binding subject on-it: inducing failure for patch deployments",
 | |
| 						}},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 			&appsv1.Deployment{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Namespace: "foo",
 | |
| 					Name:      "on-it",
 | |
| 				},
 | |
| 				Spec: appsv1.DeploymentSpec{
 | |
| 					Template: corev1.PodTemplateSpec{
 | |
| 						Spec: corev1.PodSpec{
 | |
| 							Containers: []corev1.Container{{
 | |
| 								Name:  "foo",
 | |
| 								Image: "busybox",
 | |
| 								Env: []corev1.EnvVar{{
 | |
| 									Name:  "FOO",
 | |
| 									Value: "value",
 | |
| 								}},
 | |
| 							}},
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 			&corev1.Namespace{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Name: "foo",
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 		WantPatches: []clientgotesting.PatchActionImpl{
 | |
| 			patchAddLabel("foo"),
 | |
| 			patchRemoveEnv("foo", "on-it"),
 | |
| 		},
 | |
| 	}}
 | |
| 
 | |
| 	table.Test(t, MakeFactory(func(ctx context.Context, listers *Listers, cmw configmap.Watcher) controller.Reconciler {
 | |
| 		gvr := SchemeGroupVersion.WithResource("testbindables")
 | |
| 		ctx = podspecable.WithDuck(ctx)
 | |
| 
 | |
| 		dc := dynamicclient.Get(ctx)
 | |
| 
 | |
| 		return &BaseReconciler{
 | |
| 			GVR: gvr,
 | |
| 
 | |
| 			DynamicClient: dc,
 | |
| 			Factory:       podspecable.Get(ctx),
 | |
| 
 | |
| 			Tracker: &FakeTracker{},
 | |
| 
 | |
| 			Recorder: record.NewFakeRecorder(20),
 | |
| 
 | |
| 			Get: func(namespace, name string) (Bindable, error) {
 | |
| 				for _, elt := range listers.GetDuckObjects() {
 | |
| 					b, ok := elt.(*TestBindable)
 | |
| 					if !ok {
 | |
| 						continue
 | |
| 					}
 | |
| 					if b.Namespace != namespace || b.Name != name {
 | |
| 						continue
 | |
| 					}
 | |
| 					return b, nil
 | |
| 				}
 | |
| 				return nil, apierrs.NewNotFound(gvr.GroupResource(), name)
 | |
| 			},
 | |
| 			NamespaceLister: listers.GetNamespaceLister(),
 | |
| 		}
 | |
| 	}))
 | |
| }
 | |
| 
 | |
| func TestBaseReconcileWithSubResourcesReconciler(t *testing.T) {
 | |
| 	table := TableTest{{
 | |
| 		Name: "create new subresource",
 | |
| 		Key:  "foo/bar",
 | |
| 		Objects: []runtime.Object{
 | |
| 			&TestBindable{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Namespace:  "foo",
 | |
| 					Name:       "bar",
 | |
| 					Finalizers: []string{"testbindables.duck.knative.dev"},
 | |
| 				},
 | |
| 				Spec: TestBindableSpec{
 | |
| 					BindingSpec: duckv1alpha1.BindingSpec{
 | |
| 						Subject: tracker.Reference{
 | |
| 							APIVersion: "apps/v1",
 | |
| 							Kind:       "Deployment",
 | |
| 							Namespace:  "foo",
 | |
| 							Name:       "on-it",
 | |
| 						},
 | |
| 					},
 | |
| 					Foo: "asdfasdfasdfasdf",
 | |
| 				},
 | |
| 				Status: TestBindableStatus{
 | |
| 					Status: duckv1.Status{
 | |
| 						Conditions: []apis.Condition{{
 | |
| 							Type:   "Ready",
 | |
| 							Status: "True",
 | |
| 						}},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 			&appsv1.Deployment{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Namespace: "foo",
 | |
| 					Name:      "on-it",
 | |
| 				},
 | |
| 				Spec: appsv1.DeploymentSpec{
 | |
| 					Template: corev1.PodTemplateSpec{
 | |
| 						Spec: corev1.PodSpec{
 | |
| 							Containers: []corev1.Container{{
 | |
| 								Name:  "foo",
 | |
| 								Image: "busybox",
 | |
| 								Env: []corev1.EnvVar{{
 | |
| 									Name:  "FOO",
 | |
| 									Value: "asdfasdfasdfasdf",
 | |
| 								}},
 | |
| 							}},
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 			&corev1.Namespace{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Name: "foo",
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 		WantPatches: []clientgotesting.PatchActionImpl{
 | |
| 			patchAddLabel("foo"),
 | |
| 		},
 | |
| 		WantCreates: []runtime.Object{
 | |
| 			&corev1.ConfigMap{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Name: "bar",
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 	},
 | |
| 		{
 | |
| 			Name: "delete resource and subresource",
 | |
| 			Key:  "foo/bar",
 | |
| 			Objects: []runtime.Object{
 | |
| 				&TestBindable{
 | |
| 					ObjectMeta: metav1.ObjectMeta{
 | |
| 						Namespace:         "foo",
 | |
| 						DeletionTimestamp: &metav1.Time{Time: time.Now()},
 | |
| 						Name:              "bar",
 | |
| 						Finalizers:        []string{"testbindables.duck.knative.dev"},
 | |
| 					},
 | |
| 					Spec: TestBindableSpec{
 | |
| 						BindingSpec: duckv1alpha1.BindingSpec{
 | |
| 							Subject: tracker.Reference{
 | |
| 								APIVersion: "apps/v1",
 | |
| 								Kind:       "Deployment",
 | |
| 								Namespace:  "foo",
 | |
| 								Name:       "on-it",
 | |
| 							},
 | |
| 						},
 | |
| 						Foo: "asdfasdfasdfasdf",
 | |
| 					},
 | |
| 					Status: TestBindableStatus{
 | |
| 						Status: duckv1.Status{
 | |
| 							Conditions: []apis.Condition{{
 | |
| 								Type:   "Ready",
 | |
| 								Status: "True",
 | |
| 							}},
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 				&appsv1.Deployment{
 | |
| 					ObjectMeta: metav1.ObjectMeta{
 | |
| 						Namespace: "foo",
 | |
| 						Name:      "on-it",
 | |
| 					},
 | |
| 					Spec: appsv1.DeploymentSpec{
 | |
| 						Template: corev1.PodTemplateSpec{
 | |
| 							Spec: corev1.PodSpec{
 | |
| 								Containers: []corev1.Container{{
 | |
| 									Name:  "foo",
 | |
| 									Image: "busybox",
 | |
| 									Env: []corev1.EnvVar{{
 | |
| 										Name:  "FOO",
 | |
| 										Value: "asdfasdfasdfasdf",
 | |
| 									}},
 | |
| 								}},
 | |
| 							},
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 				&corev1.Namespace{
 | |
| 					ObjectMeta: metav1.ObjectMeta{
 | |
| 						Name: "foo",
 | |
| 					},
 | |
| 				},
 | |
| 				&corev1.ConfigMap{
 | |
| 					ObjectMeta: metav1.ObjectMeta{
 | |
| 						Name:      "bar",
 | |
| 						Namespace: "foo",
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 			WantPatches: []clientgotesting.PatchActionImpl{
 | |
| 				patchAddLabel("foo"),
 | |
| 				patchRemoveEnv("foo", "on-it"),
 | |
| 				patchRemoveFinalizer("foo", "bar", "" /* resource version */),
 | |
| 			},
 | |
| 			WantDeletes: []clientgotesting.DeleteActionImpl{
 | |
| 				deletedConfigmap("foo", "bar"),
 | |
| 			},
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	table.Test(t, MakeFactory(func(ctx context.Context, listers *Listers, cmw configmap.Watcher) controller.Reconciler {
 | |
| 		gvr := SchemeGroupVersion.WithResource("testbindables")
 | |
| 		ctx = podspecable.WithDuck(ctx)
 | |
| 
 | |
| 		dc := dynamicclient.Get(ctx)
 | |
| 
 | |
| 		kc := kubeclient.Get(ctx)
 | |
| 		srr := &fakeSubResourcesReconciler{
 | |
| 			client: kc,
 | |
| 		}
 | |
| 		return &BaseReconciler{
 | |
| 			GVR: gvr,
 | |
| 
 | |
| 			DynamicClient: dc,
 | |
| 			Factory:       podspecable.Get(ctx),
 | |
| 
 | |
| 			Tracker: &FakeTracker{},
 | |
| 
 | |
| 			Recorder: record.NewFakeRecorder(20),
 | |
| 
 | |
| 			Get: func(namespace, name string) (Bindable, error) {
 | |
| 				for _, elt := range listers.GetDuckObjects() {
 | |
| 					b, ok := elt.(*TestBindable)
 | |
| 					if !ok {
 | |
| 						continue
 | |
| 					}
 | |
| 					if b.Namespace != namespace || b.Name != name {
 | |
| 						continue
 | |
| 					}
 | |
| 					return b, nil
 | |
| 				}
 | |
| 				return nil, apierrs.NewNotFound(gvr.GroupResource(), name)
 | |
| 			},
 | |
| 			NamespaceLister: listers.GetNamespaceLister(),
 | |
| 
 | |
| 			SubResourcesReconciler: srr,
 | |
| 		}
 | |
| 	}))
 | |
| }
 | |
| 
 | |
| func mustTU(t *testing.T, ro duck.OneOfOurs) *unstructured.Unstructured {
 | |
| 	u, err := duck.ToUnstructured(ro)
 | |
| 	if err != nil {
 | |
| 		t.Fatalf("ToUnstructured(%+v) = %v", ro, err)
 | |
| 	}
 | |
| 	return u
 | |
| }
 | |
| 
 | |
| func patchAddLabel(namespace string) clientgotesting.PatchActionImpl {
 | |
| 	action := clientgotesting.PatchActionImpl{}
 | |
| 	resource := schema.GroupVersionResource{
 | |
| 		Group:    "",
 | |
| 		Version:  "v1",
 | |
| 		Resource: "namespaces",
 | |
| 	}
 | |
| 	actionImpl := clientgotesting.ActionImpl{
 | |
| 		Namespace:   namespace,
 | |
| 		Verb:        "patch",
 | |
| 		Resource:    resource,
 | |
| 		Subresource: "",
 | |
| 	}
 | |
| 	action.ActionImpl = actionImpl
 | |
| 	action.Name = namespace
 | |
| 	action.PatchType = types.MergePatchType
 | |
| 
 | |
| 	patch, _ := json.Marshal(jsonLabelPatch)
 | |
| 	action.Patch = patch
 | |
| 	return action
 | |
| }
 | |
| func patchAddFinalizer(namespace, name, resourceVersion string) clientgotesting.PatchActionImpl {
 | |
| 	action := clientgotesting.PatchActionImpl{}
 | |
| 	action.Name = name
 | |
| 	action.Namespace = namespace
 | |
| 
 | |
| 	patch := fmt.Sprintf(`{"metadata":{"finalizers":["testbindables.duck.knative.dev"],"resourceVersion":%q}}`, resourceVersion)
 | |
| 
 | |
| 	action.Patch = []byte(patch)
 | |
| 	return action
 | |
| }
 | |
| 
 | |
| func patchRemoveFinalizer(namespace, name, resourceVersion string) clientgotesting.PatchActionImpl {
 | |
| 	action := clientgotesting.PatchActionImpl{}
 | |
| 	action.Name = name
 | |
| 	action.Namespace = namespace
 | |
| 
 | |
| 	patch := fmt.Sprintf(`{"metadata":{"finalizers":[],"resourceVersion":%q}}`, resourceVersion)
 | |
| 
 | |
| 	action.Patch = []byte(patch)
 | |
| 	return action
 | |
| }
 | |
| 
 | |
| func patchAddEnv(namespace, name, value string) clientgotesting.PatchActionImpl {
 | |
| 	action := clientgotesting.PatchActionImpl{}
 | |
| 	action.Name = name
 | |
| 	action.Namespace = namespace
 | |
| 
 | |
| 	patch := fmt.Sprintf(`[{"op":"add","path":"/spec/template/spec/containers/0/env","value":[{"name":"FOO","value":%q}]}]`, value)
 | |
| 
 | |
| 	action.Patch = []byte(patch)
 | |
| 	return action
 | |
| }
 | |
| 
 | |
| func patchRemoveEnv(namespace, name string) clientgotesting.PatchActionImpl {
 | |
| 	action := clientgotesting.PatchActionImpl{}
 | |
| 	action.Name = name
 | |
| 	action.Namespace = namespace
 | |
| 
 | |
| 	patch := `[{"op":"remove","path":"/spec/template/spec/containers/0/env"}]`
 | |
| 
 | |
| 	action.Patch = []byte(patch)
 | |
| 	return action
 | |
| }
 | |
| 
 | |
| func deletedConfigmap(namespace string, name string) clientgotesting.DeleteActionImpl {
 | |
| 	action := clientgotesting.DeleteActionImpl{}
 | |
| 	resource := schema.GroupVersionResource{
 | |
| 		Group:    "core",
 | |
| 		Version:  "v1",
 | |
| 		Resource: "configmaps",
 | |
| 	}
 | |
| 	actionImpl := clientgotesting.ActionImpl{
 | |
| 		Namespace:   namespace,
 | |
| 		Verb:        "delete",
 | |
| 		Resource:    resource,
 | |
| 		Subresource: "",
 | |
| 	}
 | |
| 	action.ActionImpl = actionImpl
 | |
| 	action.Name = name
 | |
| 	return action
 | |
| }
 | |
| 
 | |
| type fakeSubResourcesReconciler struct {
 | |
| 	client *fakek8s.Clientset
 | |
| }
 | |
| 
 | |
| func (d *fakeSubResourcesReconciler) Reconcile(ctx context.Context, fb Bindable) error {
 | |
| 	cfg := corev1.ConfigMap{
 | |
| 		ObjectMeta: metav1.ObjectMeta{
 | |
| 			Name: fb.GetName(),
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	_, err := d.client.CoreV1().ConfigMaps(fb.GetNamespace()).Create(ctx, &cfg, metav1.CreateOptions{})
 | |
| 	return err
 | |
| }
 | |
| 
 | |
| func (d *fakeSubResourcesReconciler) ReconcileDeletion(ctx context.Context, fb Bindable) error {
 | |
| 	return d.client.CoreV1().ConfigMaps(fb.GetNamespace()).Delete(ctx, fb.GetName(), metav1.DeleteOptions{})
 | |
| }
 |