knative.dev/pkg@v0.0.0-20260602142205-ac97e43f6622/tracker/interface_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 tracker
    18  
    19  import (
    20  	"context"
    21  	"testing"
    22  
    23  	"github.com/google/go-cmp/cmp"
    24  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    25  	"k8s.io/apimachinery/pkg/runtime/schema"
    26  	"knative.dev/pkg/apis"
    27  )
    28  
    29  func TestGroupVersionKind(t *testing.T) {
    30  	ref := Reference{
    31  		APIVersion: "apps/v1",
    32  		Kind:       "Deployment",
    33  		Namespace:  "default",
    34  		Name:       "nginx",
    35  	}
    36  
    37  	want := schema.GroupVersionKind{
    38  		Group:   "apps",
    39  		Version: "v1",
    40  		Kind:    "Deployment",
    41  	}
    42  	got := ref.GroupVersionKind()
    43  	if want != got {
    44  		t.Errorf("GroupVersionKind() = %v, wanted = %v", got, want)
    45  	}
    46  }
    47  
    48  func TestValidateObjectReference(t *testing.T) {
    49  	tests := []struct {
    50  		name string
    51  		ref  Reference
    52  		want *apis.FieldError
    53  	}{{
    54  		name: "empty reference",
    55  		want: apis.ErrMissingField("apiVersion", "kind", "name", "namespace"),
    56  	}, {
    57  		name: "good reference",
    58  		ref: Reference{
    59  			APIVersion: "apps/v1",
    60  			Kind:       "Deployment",
    61  			Namespace:  "default",
    62  			Name:       "nginx",
    63  		},
    64  	}, {
    65  		name: "another good reference",
    66  		ref: Reference{
    67  			APIVersion: "v1",
    68  			Kind:       "Service",
    69  			Namespace:  "default",
    70  			Name:       "nginx",
    71  		},
    72  	}, {
    73  		name: "bad apiVersion",
    74  		ref: Reference{
    75  			APIVersion: "a b c d", // Bad!
    76  			Kind:       "Service",
    77  			Namespace:  "default",
    78  			Name:       "nginx",
    79  		},
    80  		want: apis.ErrInvalidValue("name part must consist of alphanumeric characters, '-', '_' or '.', and must start and end with an alphanumeric character (e.g. 'MyName',  or 'my.name',  or '123-abc', regex used for validation is '([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]')", "apiVersion"),
    81  	}, {
    82  		name: "bad kind",
    83  		ref: Reference{
    84  			APIVersion: "apps/v1",
    85  			Kind:       "a b c d", // Bad!
    86  			Namespace:  "default",
    87  			Name:       "nginx",
    88  		},
    89  		want: apis.ErrInvalidValue("a valid C identifier must start with alphabetic character or '_', followed by a string of alphanumeric characters or '_' (e.g. 'my_name',  or 'MY_NAME',  or 'MyName', regex used for validation is '[A-Za-z_][A-Za-z0-9_]*')", "kind"),
    90  	}, {
    91  		name: "bad namespace and name",
    92  		ref: Reference{
    93  			APIVersion: "apps/v1",
    94  			Kind:       "Deployment",
    95  			Namespace:  "a.b",
    96  			Name:       "c.d",
    97  		},
    98  		want: &apis.FieldError{
    99  			Message: "invalid value: must not contain dots",
   100  			Paths:   []string{"namespace", "name"},
   101  		},
   102  	}, {
   103  		name: "with selector too",
   104  		ref: Reference{
   105  			APIVersion: "apps/v1",
   106  			Kind:       "Deployment",
   107  			Namespace:  "default",
   108  			Name:       "nginx",
   109  			Selector:   &metav1.LabelSelector{},
   110  		},
   111  		want: apis.ErrDisallowedFields("selector"),
   112  	}}
   113  
   114  	for _, test := range tests {
   115  		t.Run(test.name, func(t *testing.T) {
   116  			got := test.ref.ValidateObjectReference(context.Background())
   117  			if (test.want != nil) != (got != nil) {
   118  				t.Errorf("ValidateObjectReference() = %v, wanted %v", got, test.want)
   119  			} else if test.want != nil {
   120  				want, got := test.want.Error(), got.Error()
   121  				if diff := cmp.Diff(want, got); diff != "" {
   122  					t.Errorf("ValidateObjectReference() diff: %s", diff)
   123  				}
   124  			}
   125  		})
   126  	}
   127  }
   128  
   129  func TestValidate(t *testing.T) {
   130  	tests := []struct {
   131  		name string
   132  		ref  Reference
   133  		want *apis.FieldError
   134  	}{{
   135  		name: "empty reference",
   136  		want: apis.ErrMissingField("apiVersion", "kind", "namespace").Also(
   137  			apis.ErrMissingOneOf("name", "selector")),
   138  	}, {
   139  		name: "good reference",
   140  		ref: Reference{
   141  			APIVersion: "apps/v1",
   142  			Kind:       "Deployment",
   143  			Namespace:  "default",
   144  			Name:       "nginx",
   145  		},
   146  	}, {
   147  		name: "another good reference",
   148  		ref: Reference{
   149  			APIVersion: "v1",
   150  			Kind:       "Service",
   151  			Namespace:  "default",
   152  			Name:       "nginx",
   153  		},
   154  	}, {
   155  		name: "bad apiVersion",
   156  		ref: Reference{
   157  			APIVersion: "a b c d", // Bad!
   158  			Kind:       "Service",
   159  			Namespace:  "default",
   160  			Name:       "nginx",
   161  		},
   162  		want: apis.ErrInvalidValue("name part must consist of alphanumeric characters, '-', '_' or '.', and must start and end with an alphanumeric character (e.g. 'MyName',  or 'my.name',  or '123-abc', regex used for validation is '([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]')", "apiVersion"),
   163  	}, {
   164  		name: "bad kind",
   165  		ref: Reference{
   166  			APIVersion: "apps/v1",
   167  			Kind:       "a b c d", // Bad!
   168  			Namespace:  "default",
   169  			Name:       "nginx",
   170  		},
   171  		want: apis.ErrInvalidValue("a valid C identifier must start with alphabetic character or '_', followed by a string of alphanumeric characters or '_' (e.g. 'my_name',  or 'MY_NAME',  or 'MyName', regex used for validation is '[A-Za-z_][A-Za-z0-9_]*')", "kind"),
   172  	}, {
   173  		name: "bad namespace and name",
   174  		ref: Reference{
   175  			APIVersion: "apps/v1",
   176  			Kind:       "Deployment",
   177  			Namespace:  "a.b",
   178  			Name:       "c.d",
   179  		},
   180  		want: &apis.FieldError{
   181  			Message: "invalid value: must not contain dots",
   182  			Paths:   []string{"namespace", "name"},
   183  		},
   184  	}, {
   185  		name: "with selector too",
   186  		ref: Reference{
   187  			APIVersion: "apps/v1",
   188  			Kind:       "Deployment",
   189  			Namespace:  "default",
   190  			Name:       "nginx",
   191  			Selector:   &metav1.LabelSelector{},
   192  		},
   193  		want: apis.ErrMultipleOneOf("name", "selector"),
   194  	}, {
   195  		name: "with just selector",
   196  		ref: Reference{
   197  			APIVersion: "apps/v1",
   198  			Kind:       "Deployment",
   199  			Namespace:  "default",
   200  			Selector: &metav1.LabelSelector{
   201  				MatchLabels: map[string]string{
   202  					"foo": "bar",
   203  				},
   204  			},
   205  		},
   206  	}, {
   207  		name: "with invalid selector",
   208  		ref: Reference{
   209  			APIVersion: "apps/v1",
   210  			Kind:       "Deployment",
   211  			Namespace:  "default",
   212  			Selector: &metav1.LabelSelector{
   213  				MatchLabels: map[string]string{
   214  					"a b c": "bar",
   215  				},
   216  			},
   217  		},
   218  		want: apis.ErrInvalidValue(`key: Invalid value: "a b c": name part must consist of alphanumeric characters, '-', '_' or '.', and must start and end with an alphanumeric character (e.g. 'MyName',  or 'my.name',  or '123-abc', regex used for validation is '([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]')`, "selector"),
   219  	}}
   220  
   221  	for _, test := range tests {
   222  		t.Run(test.name, func(t *testing.T) {
   223  			got := test.ref.Validate(context.Background())
   224  			if (test.want != nil) != (got != nil) {
   225  				t.Errorf("ValidateObjectReference() = %v, wanted %v", got, test.want)
   226  			} else if test.want != nil {
   227  				want, got := test.want.Error(), got.Error()
   228  				if diff := cmp.Diff(want, got); diff != "" {
   229  					t.Errorf("ValidateObjectReference() diff %s", diff)
   230  				}
   231  			}
   232  		})
   233  	}
   234  }