...

Source file src/edge-infra.dev/pkg/k8s/object/match/match_test.go

Documentation: edge-infra.dev/pkg/k8s/object/match

     1  package match
     2  
     3  import (
     4  	"testing"
     5  
     6  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
     7  	"k8s.io/apimachinery/pkg/runtime/schema"
     8  	"sigs.k8s.io/controller-runtime/pkg/client"
     9  )
    10  
    11  func TestObject(t *testing.T) {
    12  	tcs := map[string]struct {
    13  		obj     client.Object
    14  		matcher Matcher
    15  		exp     bool
    16  	}{
    17  		"nil object is false": {
    18  			nil,
    19  			AnyInMetadata{"key": "value"},
    20  			false,
    21  		},
    22  		"nil matcher is false": {
    23  			&unstructured.Unstructured{},
    24  			nil,
    25  			false,
    26  		},
    27  		"actually matches": {
    28  			func() client.Object {
    29  				o := &unstructured.Unstructured{}
    30  				o.SetGroupVersionKind(schema.GroupVersionKind{
    31  					Group:   "apps",
    32  					Version: "v1",
    33  					Kind:    "Deployment",
    34  				})
    35  				return o
    36  			}(),
    37  			Kind{"Deployment"},
    38  			true,
    39  		},
    40  	}
    41  
    42  	for name, tc := range tcs {
    43  		t.Run(name, func(t *testing.T) {
    44  			ok := Object(tc.obj, tc.matcher)
    45  			if ok != tc.exp {
    46  				t.Errorf("unexpected Match() result: wanted %t, got %t", tc.exp, ok)
    47  			}
    48  		})
    49  	}
    50  }
    51  
    52  func TestMatchers(t *testing.T) {
    53  	empty := &unstructured.Unstructured{}
    54  
    55  	type testCase struct {
    56  		obj     client.Object
    57  		matcher Matcher
    58  		exp     bool
    59  	}
    60  
    61  	tcs := map[string]map[string]testCase{
    62  		"Namespace": {
    63  			"Matches": {
    64  				&unstructured.Unstructured{Object: map[string]any{
    65  					"metadata": map[string]any{
    66  						"namespace": "kube-system",
    67  					},
    68  				}},
    69  				Namespace{"kube-system"},
    70  				true,
    71  			},
    72  			"Doesn't Match": {
    73  				&unstructured.Unstructured{Object: map[string]any{
    74  					"metadata": map[string]any{
    75  						"namespace": "kube-system",
    76  					},
    77  				}},
    78  				Namespace{"test"},
    79  				false,
    80  			},
    81  			"Empty Doesn't Match": {
    82  				empty,
    83  				Namespace{"test"},
    84  				false,
    85  			},
    86  		},
    87  		"Name": {
    88  			"Matches": {
    89  				&unstructured.Unstructured{Object: map[string]any{
    90  					"metadata": map[string]any{
    91  						"name": "bundle-of-joy",
    92  					},
    93  				}},
    94  				Name{"bundle-of-joy"},
    95  				true,
    96  			},
    97  			"Doesn't Match": {
    98  				&unstructured.Unstructured{Object: map[string]any{
    99  					"metadata": map[string]any{
   100  						"name": "unexpected-encounter",
   101  					},
   102  				}},
   103  				Name{"bundle-of-joy"},
   104  				false,
   105  			},
   106  			"Empty Doesn't Match": {
   107  				empty,
   108  				Name{"bundle-of-joy"},
   109  				false,
   110  			},
   111  		},
   112  		"Kind": {
   113  			"Matches": {
   114  				&unstructured.Unstructured{Object: map[string]any{
   115  					"kind": "Deployment",
   116  				}},
   117  				Kind{"Deployment"},
   118  				true,
   119  			},
   120  			"Doesn't Match": {
   121  				&unstructured.Unstructured{Object: map[string]any{
   122  					"kind": "Deployment",
   123  				}},
   124  				Kind{"Pod"},
   125  				false,
   126  			},
   127  			"Empty Doesn't Match": {
   128  				empty,
   129  				Kind{"Pod"},
   130  				false,
   131  			},
   132  		},
   133  		"GroupVersion": {
   134  			"Matches": {
   135  				&unstructured.Unstructured{Object: map[string]any{
   136  					"apiVersion": "apps/v1",
   137  				}},
   138  				GroupVersion{Group: "apps", Version: "v1"},
   139  				true,
   140  			},
   141  			"Doesn't Match": {
   142  				&unstructured.Unstructured{Object: map[string]any{
   143  					"apiVersion": "apps/v1",
   144  				}},
   145  				GroupVersion{Group: "", Version: "v1beta1"},
   146  				false,
   147  			},
   148  			"Doesn't Match Version": {
   149  				&unstructured.Unstructured{Object: map[string]any{
   150  					"apiVersion": "apps/v1",
   151  				}},
   152  				GroupVersion{Group: "apps", Version: "v1beta1"},
   153  				false,
   154  			},
   155  			"Empty Doesn't Match": {
   156  				empty,
   157  				GroupVersion{Group: "apps", Version: "v1"},
   158  				false,
   159  			},
   160  		},
   161  		"AnyInMetadata": {
   162  			"Matches": {
   163  				objWithMeta(map[string]any{
   164  					"labels": map[string]any{
   165  						"key": "value",
   166  					},
   167  				}),
   168  				AnyInMetadata{"key": "value"},
   169  				true,
   170  			},
   171  			"Partial Match Annotations": {
   172  				objWithMeta(map[string]any{
   173  					"annotations": map[string]any{
   174  						"key": "value",
   175  					},
   176  				}),
   177  				AnyInMetadata{"key": "value", "key2": "value2"},
   178  				true,
   179  			},
   180  			"Partial Match Labels": {
   181  				objWithMeta(map[string]any{
   182  					"labels": map[string]any{
   183  						"key": "value",
   184  					},
   185  				}),
   186  				AnyInMetadata{"key": "value", "key2": "value2"},
   187  				true,
   188  			},
   189  			"Matches Case Insensitive": {
   190  				objWithMeta(map[string]any{
   191  					"labels": map[string]any{
   192  						"key": "valUe",
   193  					},
   194  				}),
   195  				AnyInMetadata{"key": "value"},
   196  				true,
   197  			},
   198  			"Doesn't Match": {
   199  				objWithMeta(map[string]any{
   200  					"labels": map[string]any{
   201  						"key2": "value",
   202  					},
   203  					"annotations": map[string]any{
   204  						"key": "value2",
   205  					},
   206  				}),
   207  				AnyInMetadata{"key": "value", "key2": "value2"},
   208  				false,
   209  			},
   210  			"Empty Doesn't Match": {
   211  				empty,
   212  				AnyInMetadata{"key": "value"},
   213  				false,
   214  			},
   215  		},
   216  		"Labels": {
   217  			"Matches": {
   218  				objWithMeta(map[string]any{
   219  					"labels": map[string]any{
   220  						"label": "labelValue",
   221  					},
   222  				}),
   223  				Labels{"label": "labelValue"},
   224  				true,
   225  			},
   226  			"Matches Multiple": {
   227  				objWithMeta(map[string]any{
   228  					"labels": map[string]any{
   229  						"key":  "value",
   230  						"key2": "value2",
   231  					},
   232  				}),
   233  				Labels{
   234  					"key":  "value",
   235  					"key2": "value2",
   236  				},
   237  				true,
   238  			},
   239  			"Matches Case Insensitive": {
   240  				objWithMeta(map[string]any{
   241  					"labels": map[string]any{
   242  						"key": "valUe",
   243  					},
   244  				}),
   245  				Labels{"key": "valUe"},
   246  				true,
   247  			},
   248  			"Doesn't Match Partially": {
   249  				objWithMeta(map[string]any{
   250  					"labels": map[string]any{
   251  						"key":  "value",
   252  						"key2": "value3",
   253  					},
   254  				}),
   255  				Labels{"key": "value", "key2": "value2"},
   256  				false,
   257  			},
   258  			"Empty Doesn't Match": {
   259  				empty,
   260  				Labels{"key": "value"},
   261  				false,
   262  			},
   263  		},
   264  		"Annotations": {
   265  			"Matches": {
   266  				objWithMeta(map[string]any{
   267  					"annotations": map[string]any{
   268  						"key": "value",
   269  					},
   270  				}),
   271  				Annotations{"key": "value"},
   272  				true,
   273  			},
   274  			"Matches Multiple": {
   275  				objWithMeta(map[string]any{
   276  					"annotations": map[string]any{
   277  						"key":  "value",
   278  						"key2": "value2",
   279  					},
   280  				}),
   281  				Annotations{"key": "value", "key2": "value2"},
   282  				true,
   283  			},
   284  			"Matches Case Insensitive": {
   285  				objWithMeta(map[string]any{
   286  					"annotations": map[string]any{
   287  						"key": "valUe",
   288  					},
   289  				}),
   290  				Annotations{"key": "valUe"},
   291  				true,
   292  			},
   293  			"Doesn't Match Partially": {
   294  				objWithMeta(map[string]any{
   295  					"annotations": map[string]any{
   296  						"key":  "value",
   297  						"key2": "value3",
   298  					},
   299  				}),
   300  				Annotations{"key": "value", "key2": "value2"},
   301  				false,
   302  			},
   303  			"Empty Doesn't Match": {
   304  				empty,
   305  				Annotations{"key": "value"},
   306  				false,
   307  			},
   308  		},
   309  		"Any": {
   310  			"Matches": {
   311  				&unstructured.Unstructured{Object: map[string]any{
   312  					"kind": "Deployment",
   313  				}},
   314  				Any{Kind{"Deployment"}},
   315  				true,
   316  			},
   317  			"Partial Matches": {
   318  				&unstructured.Unstructured{Object: map[string]any{
   319  					"kind": "Deployment",
   320  				}},
   321  				Any{Kind{"Deployment"}, Name{"bundle-of-joy"}},
   322  				true,
   323  			},
   324  			"Ignores nil Matchers": {
   325  				&unstructured.Unstructured{Object: map[string]any{
   326  					"kind": "Deployment",
   327  					"metadata": map[string]any{
   328  						"name": "bundle-of-joy",
   329  					},
   330  				}},
   331  				Any{Kind{"Deployment"}, nil, Name{"bundle-of-joy"}},
   332  				true,
   333  			},
   334  			"Doesn't Match": {
   335  				empty,
   336  				Any{Kind{"Deployment"}, Name{"bundle-of-joy"}},
   337  				false,
   338  			},
   339  			"Empty Doesn't Match": {
   340  				&unstructured.Unstructured{Object: map[string]any{
   341  					"kind": "Deployment",
   342  					"metadata": map[string]any{
   343  						"name": "bundle-of-joy",
   344  					},
   345  				}},
   346  				Any{},
   347  				false,
   348  			},
   349  		},
   350  		"All": {
   351  			"Matches": {
   352  				&unstructured.Unstructured{Object: map[string]any{
   353  					"kind": "Deployment",
   354  				}},
   355  				All{Kind{"Deployment"}},
   356  				true,
   357  			},
   358  			"Partial Doesn't Match": {
   359  				&unstructured.Unstructured{Object: map[string]any{
   360  					"kind": "Deployment",
   361  				}},
   362  				All{Kind{"Deployment"}, Name{"bundle-of-joy"}},
   363  				false,
   364  			},
   365  			"Ignores nil Matchers": {
   366  				&unstructured.Unstructured{Object: map[string]any{
   367  					"kind": "Deployment",
   368  					"metadata": map[string]any{
   369  						"name": "bundle-of-joy",
   370  					},
   371  				}},
   372  				All{Kind{"Deployment"}, nil, Name{"bundle-of-joy"}},
   373  				true,
   374  			},
   375  			"Doesn't Match": {
   376  				empty,
   377  				All{Kind{"Deployment"}, Name{"bundle-of-joy"}},
   378  				false,
   379  			},
   380  			"Empty Doesn't Match": {
   381  				&unstructured.Unstructured{Object: map[string]any{
   382  					"kind": "Deployment",
   383  					"metadata": map[string]any{
   384  						"name": "bundle-of-joy",
   385  					},
   386  				}},
   387  				All{},
   388  				false,
   389  			},
   390  		},
   391  	}
   392  
   393  	for fn, fnTestCases := range tcs {
   394  		t.Run(fn, func(t *testing.T) {
   395  			for name, tc := range fnTestCases {
   396  				t.Run(name, func(t *testing.T) {
   397  					ok := tc.matcher.Match(tc.obj)
   398  					if ok != tc.exp {
   399  						t.Errorf("unexpected Match() result: wanted %t, got %t", tc.exp, ok)
   400  					}
   401  				})
   402  			}
   403  		})
   404  	}
   405  }
   406  
   407  func objWithMeta(meta map[string]any) *unstructured.Unstructured {
   408  	return &unstructured.Unstructured{Object: map[string]any{
   409  		"metadata": meta,
   410  	}}
   411  }
   412  

View as plain text