knative.dev/pkg@v0.0.0-20260602142205-ac97e43f6622/webhook/psbinding/index_test.go (about)

     1  /*
     2  Copyright 2019 The Knative Authors
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package psbinding
    18  
    19  import (
    20  	"testing"
    21  
    22  	"github.com/google/go-cmp/cmp"
    23  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    24  	"k8s.io/apimachinery/pkg/labels"
    25  
    26  	. "knative.dev/pkg/testing/duck"
    27  )
    28  
    29  func TestExact(t *testing.T) {
    30  	em := make(exactMatcher, 1)
    31  
    32  	want := &TestBindable{
    33  		ObjectMeta: metav1.ObjectMeta{
    34  			Namespace: "blah",
    35  			Name:      "asdf",
    36  		},
    37  	}
    38  
    39  	gvk := want.GetGroupVersionKind()
    40  	key := exactKey{
    41  		Group:     gvk.Group,
    42  		Kind:      gvk.Kind,
    43  		Namespace: want.GetNamespace(),
    44  		Name:      want.GetName(),
    45  	}
    46  
    47  	// Before we add something, we shouldn't be able to get anything.
    48  	if got := em.get(key); len(got) != 0 {
    49  		t.Errorf("Get(%+v) = %v; wanted empty list", key, got)
    50  	}
    51  
    52  	// Now add it.
    53  	em.add(key, want)
    54  
    55  	// After we add something, we should be able to get it.
    56  	wanted := []Bindable{want}
    57  	if got := em.get(key); !cmp.Equal(got, wanted) {
    58  		t.Error("Get (-want, +got):", cmp.Diff(wanted, got))
    59  	}
    60  
    61  	otherKey := exactKey{
    62  		Group:     "apps",
    63  		Kind:      "Deployment",
    64  		Namespace: "foo",
    65  		Name:      "bar",
    66  	}
    67  
    68  	// After we add something, we still shouldn't return things for other keys.
    69  	if got := em.get(otherKey); len(got) != 0 {
    70  		t.Errorf("Get(%+v) = %v; wanted empty list", key, got)
    71  	}
    72  
    73  	// Add another Binding with the same coordinates.
    74  	alsoWant := &TestBindable{
    75  		ObjectMeta: metav1.ObjectMeta{
    76  			Namespace: "blah",
    77  			Name:      "asdf",
    78  		},
    79  	}
    80  	em.add(key, want)
    81  
    82  	// We should now get both Bindings.
    83  	wanted = []Bindable{want, alsoWant}
    84  	if got := em.get(key); !cmp.Equal(got, wanted) {
    85  		t.Error("Get (-want, +got):", cmp.Diff(wanted, got))
    86  	}
    87  }
    88  
    89  func TestInexact(t *testing.T) {
    90  	want := &TestBindable{
    91  		ObjectMeta: metav1.ObjectMeta{
    92  			Namespace: "blah",
    93  			Name:      "asdf",
    94  			Labels: map[string]string{
    95  				"foo": "bar",
    96  				"baz": "blah",
    97  			},
    98  		},
    99  	}
   100  	ls := labels.Set(want.Labels)
   101  
   102  	gvk := want.GetGroupVersionKind()
   103  	key := inexactKey{
   104  		Group:     gvk.Group,
   105  		Kind:      gvk.Kind,
   106  		Namespace: want.GetNamespace(),
   107  	}
   108  
   109  	t.Run("empty matcher doesn't match", func(t *testing.T) {
   110  		im := make(inexactMatcher, 1)
   111  		if got := im.get(key, ls); len(got) != 0 {
   112  			t.Errorf("Get(%+v) = %v; wanted empty list", key, got)
   113  		}
   114  	})
   115  
   116  	t.Run("matcher with exact labels matches", func(t *testing.T) {
   117  		im := make(inexactMatcher, 1)
   118  
   119  		// Use exactly the labels from the resource.
   120  		selector := ls.AsSelector()
   121  
   122  		im.add(key, selector, want)
   123  
   124  		// With an appropriate selector, we match and get the binding.
   125  		wanted := []Bindable{want}
   126  		if got := im.get(key, ls); !cmp.Equal(got, wanted) {
   127  			t.Error("Get (-want, +got):", cmp.Diff(wanted, got))
   128  		}
   129  	})
   130  
   131  	t.Run("matcher for everything matches", func(t *testing.T) {
   132  		im := make(inexactMatcher, 1)
   133  
   134  		// Match everything.
   135  		selector := labels.Everything()
   136  
   137  		im.add(key, selector, want)
   138  
   139  		// With an appropriate selector, we match and get the binding.
   140  		wanted := []Bindable{want}
   141  		if got := im.get(key, ls); !cmp.Equal(got, wanted) {
   142  			t.Error("Get (-want, +got):", cmp.Diff(wanted, got))
   143  		}
   144  	})
   145  
   146  	t.Run("matcher for nothing does not match", func(t *testing.T) {
   147  		im := make(inexactMatcher, 1)
   148  
   149  		// Match nothing.
   150  		selector := labels.Nothing()
   151  
   152  		im.add(key, selector, want)
   153  
   154  		if got := im.get(key, ls); len(got) != 0 {
   155  			t.Errorf("Get(%+v) = %v; wanted empty list", key, got)
   156  		}
   157  	})
   158  
   159  	t.Run("matcher with a subset of labels matches", func(t *testing.T) {
   160  		im := make(inexactMatcher, 1)
   161  
   162  		// Use a subset of the resources labels.
   163  		selector := labels.Set(map[string]string{
   164  			"foo": "bar",
   165  		}).AsSelector()
   166  
   167  		im.add(key, selector, want)
   168  
   169  		// With an appropriate selector, we match and get the binding.
   170  		wanted := []Bindable{want}
   171  		if got := im.get(key, ls); !cmp.Equal(got, wanted) {
   172  			t.Error("Get (-want, +got):", cmp.Diff(wanted, got))
   173  		}
   174  	})
   175  
   176  	t.Run("matcher with overlapping labels does not match", func(t *testing.T) {
   177  		im := make(inexactMatcher, 1)
   178  
   179  		// Use a subset of the resources labels.
   180  		selector := labels.Set(map[string]string{
   181  			"foo": "bar",
   182  			"not": "found",
   183  		}).AsSelector()
   184  
   185  		im.add(key, selector, want)
   186  
   187  		// We shouldn't match because the second labels shouldn't match.
   188  		if got := im.get(key, ls); len(got) != 0 {
   189  			t.Errorf("Get(%+v) = %v; wanted empty list", key, got)
   190  		}
   191  	})
   192  
   193  	t.Run("matcher with exact labels doesn't match a different namespace", func(t *testing.T) {
   194  		im := make(inexactMatcher, 1)
   195  
   196  		// Use exactly the labels from the resource.
   197  		selector := ls.AsSelector()
   198  
   199  		im.add(key, selector, want)
   200  
   201  		otherKey := key
   202  		otherKey.Namespace = "another"
   203  
   204  		// We shouldn't match because the second labels shouldn't match.
   205  		if got := im.get(otherKey, ls); len(got) != 0 {
   206  			t.Errorf("Get(%+v) = %v; wanted empty list", key, got)
   207  		}
   208  	})
   209  
   210  	t.Run("multiple Bindings match", func(t *testing.T) {
   211  		alsoWant := &TestBindable{
   212  			ObjectMeta: metav1.ObjectMeta{
   213  				Namespace: "blah",
   214  				Name:      "asdf",
   215  				Labels: map[string]string{
   216  					"foo": "bar",
   217  					"baz": "blah",
   218  				},
   219  			},
   220  		}
   221  
   222  		im := make(inexactMatcher, 1)
   223  
   224  		// Use a subset of the resources labels.
   225  		selector := labels.Set(map[string]string{
   226  			"foo": "bar",
   227  		}).AsSelector()
   228  
   229  		im.add(key, selector, want)
   230  		im.add(key, selector, alsoWant)
   231  
   232  		// With an appropriate selector, we match and get both bindings.
   233  		wanted := []Bindable{want, alsoWant}
   234  		if got := im.get(key, ls); !cmp.Equal(got, wanted) {
   235  			t.Error("Get (-want, +got):", cmp.Diff(wanted, got))
   236  		}
   237  	})
   238  }
   239  
   240  func TestIndex(t *testing.T) {
   241  	wantExact1 := &TestBindable{
   242  		ObjectMeta: metav1.ObjectMeta{
   243  			Namespace: "a",
   244  			Name:      "b",
   245  			Labels: map[string]string{
   246  				"colour": "red",
   247  			},
   248  		},
   249  	}
   250  
   251  	wantExact2 := &TestBindable{
   252  		ObjectMeta: metav1.ObjectMeta{
   253  			Namespace: "a",
   254  			Name:      "b",
   255  			Labels: map[string]string{
   256  				"colour": "blue",
   257  			},
   258  		},
   259  	}
   260  
   261  	wantInexact1 := &TestBindable{
   262  		ObjectMeta: metav1.ObjectMeta{
   263  			Namespace: "a",
   264  			Name:      "b",
   265  			Labels: map[string]string{
   266  				"colour": "red",
   267  			},
   268  		},
   269  	}
   270  
   271  	wantInexact2 := &TestBindable{
   272  		ObjectMeta: metav1.ObjectMeta{
   273  			Namespace: "a",
   274  			Name:      "b",
   275  			Labels: map[string]string{
   276  				"colour": "blue",
   277  			},
   278  		},
   279  	}
   280  
   281  	gvk := wantExact1.GetGroupVersionKind()
   282  	eKey := exactKey{
   283  		Group:     gvk.Group,
   284  		Kind:      gvk.Kind,
   285  		Namespace: wantExact1.GetNamespace(),
   286  		Name:      wantExact1.GetName(),
   287  	}
   288  	iKey := inexactKey{
   289  		Group:     gvk.Group,
   290  		Kind:      gvk.Kind,
   291  		Namespace: wantExact1.GetNamespace(),
   292  	}
   293  	redLabels := labels.Set(wantInexact1.Labels)
   294  	redSelector := redLabels.AsSelector()
   295  	blueLabels := labels.Set(wantInexact2.Labels)
   296  	blueSelector := blueLabels.AsSelector()
   297  	none := make(labels.Set)
   298  	allSelector := none.AsSelector()
   299  
   300  	t.Run("single exact match is found", func(t *testing.T) {
   301  		var index index
   302  		newIndexBuilder().
   303  			associate(eKey, wantExact1).
   304  			build(&index)
   305  
   306  		wanted := []Bindable{wantExact1}
   307  		if got := index.lookUp(eKey, none); !cmp.Equal(got, wanted) {
   308  			t.Error("Get (-want, +got):", cmp.Diff(wanted, got))
   309  		}
   310  	})
   311  
   312  	t.Run("single inexact match is found", func(t *testing.T) {
   313  		var index index
   314  		newIndexBuilder().
   315  			associateSelection(iKey, redSelector, wantInexact1).
   316  			build(&index)
   317  
   318  		wanted := []Bindable{wantInexact1}
   319  		if got := index.lookUp(eKey, redLabels); !cmp.Equal(got, wanted) {
   320  			t.Error("Get (-want, +got):", cmp.Diff(wanted, got))
   321  		}
   322  	})
   323  
   324  	t.Run("multiple exact matches are found", func(t *testing.T) {
   325  		var index index
   326  		newIndexBuilder().
   327  			associate(eKey, wantExact1).
   328  			associate(eKey, wantExact2).
   329  			build(&index)
   330  
   331  		wanted := []Bindable{wantExact1, wantExact2}
   332  		if got := index.lookUp(eKey, none); !cmp.Equal(got, wanted) {
   333  			t.Error("Get (-want, +got):", cmp.Diff(wanted, got))
   334  		}
   335  	})
   336  
   337  	t.Run("multiple inexact matches are found", func(t *testing.T) {
   338  		var index index
   339  		newIndexBuilder().
   340  			associateSelection(iKey, allSelector, wantInexact1).
   341  			associateSelection(iKey, allSelector, wantInexact2).
   342  			build(&index)
   343  
   344  		wanted := []Bindable{wantInexact1, wantInexact2}
   345  		if got := index.lookUp(eKey, redLabels); !cmp.Equal(got, wanted) {
   346  			t.Error("Get (-want, +got):", cmp.Diff(wanted, got))
   347  		}
   348  	})
   349  
   350  	t.Run("multiple exact and inexact matches are found", func(t *testing.T) {
   351  		var index index
   352  		newIndexBuilder().
   353  			associate(eKey, wantExact1).
   354  			associate(eKey, wantExact2).
   355  			associateSelection(iKey, allSelector, wantInexact1).
   356  			associateSelection(iKey, allSelector, wantInexact2).
   357  			build(&index)
   358  
   359  		wanted := []Bindable{wantExact1, wantExact2, wantInexact1, wantInexact2}
   360  		if got := index.lookUp(eKey, none); !cmp.Equal(got, wanted) {
   361  			t.Error("Get (-want, +got):", cmp.Diff(wanted, got))
   362  		}
   363  	})
   364  
   365  	t.Run("the correct exact and inexact matches are found", func(t *testing.T) {
   366  		var index index
   367  		newIndexBuilder().
   368  			associate(eKey, wantExact1).
   369  			associate(eKey, wantExact2).
   370  			associateSelection(iKey, redSelector, wantInexact1).
   371  			associateSelection(iKey, blueSelector, wantInexact2).
   372  			build(&index)
   373  
   374  		wanted := []Bindable{wantExact1, wantExact2, wantInexact1}
   375  		if got := index.lookUp(eKey, redLabels); !cmp.Equal(got, wanted) {
   376  			t.Error("Get (-want, +got):", cmp.Diff(wanted, got))
   377  		}
   378  	})
   379  }