knative.dev/pkg@v0.0.0-20260602142205-ac97e43f6622/apis/duck/v1/knative_reference_test.go (about)

     1  /*
     2  Copyright 2020 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 v1
    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  	"knative.dev/pkg/apis"
    26  )
    27  
    28  const (
    29  	group = "group.my"
    30  )
    31  
    32  func TestValidate(t *testing.T) {
    33  	ctx := context.Background()
    34  
    35  	validRef := KReference{
    36  		Kind:       kind,
    37  		APIVersion: apiVersion,
    38  		Name:       name,
    39  		Namespace:  namespace,
    40  	}
    41  
    42  	tests := map[string]struct {
    43  		ref  *KReference
    44  		ctx  context.Context
    45  		want *apis.FieldError
    46  	}{
    47  		"nil valid": {
    48  			ref:  nil,
    49  			ctx:  ctx,
    50  			want: apis.ErrMissingField("name", "kind", "apiVersion"),
    51  		},
    52  		"valid ref": {
    53  			ref:  &validRef,
    54  			ctx:  ctx,
    55  			want: nil,
    56  		},
    57  		"invalid ref, empty": {
    58  			ref:  &KReference{},
    59  			ctx:  ctx,
    60  			want: apis.ErrMissingField("name", "kind", "apiVersion"),
    61  		},
    62  		"invalid ref, missing kind": {
    63  			ref: &KReference{
    64  				Namespace:  namespace,
    65  				Name:       name,
    66  				APIVersion: apiVersion,
    67  			},
    68  			ctx:  ctx,
    69  			want: apis.ErrMissingField("kind"),
    70  		},
    71  		"invalid ref, missing api version": {
    72  			ref: &KReference{
    73  				Namespace: namespace,
    74  				Name:      name,
    75  				Kind:      kind,
    76  			},
    77  			ctx:  ctx,
    78  			want: apis.ErrMissingField("apiVersion"),
    79  		},
    80  		"invalid ref, mismatched namespaces": {
    81  			ref: &KReference{
    82  				Namespace:  namespace,
    83  				Name:       name,
    84  				Kind:       kind,
    85  				APIVersion: apiVersion,
    86  			},
    87  			ctx: apis.WithinParent(ctx, metav1.ObjectMeta{Namespace: "diffns"}),
    88  			want: &apis.FieldError{
    89  				Message: "mismatched namespaces",
    90  				Paths:   []string{"namespace"},
    91  				Details: `parent namespace: "diffns" does not match ref: "b-namespace"`,
    92  			},
    93  		},
    94  		"invalid ref, disallowed group": {
    95  			ref: &KReference{
    96  				Namespace: namespace,
    97  				Name:      name,
    98  				Kind:      kind,
    99  				Group:     group,
   100  			},
   101  			ctx:  ctx,
   102  			want: apis.ErrMissingField("apiVersion").Also(apis.ErrDisallowedFields("group")),
   103  		},
   104  		"invalid ref, group allowed and both api version and group are specified, but they are conflicting": {
   105  			ref: &KReference{
   106  				Namespace:  namespace,
   107  				Name:       name,
   108  				Kind:       kind,
   109  				Group:      group,
   110  				APIVersion: apiVersion,
   111  			},
   112  			ctx: KReferenceGroupAllowed(ctx),
   113  			want: &apis.FieldError{
   114  				Message: "both apiVersion and group are specified and they refer to different API groups",
   115  				Paths:   []string{"apiVersion", "group"},
   116  				Details: "Only one of them must be specified",
   117  			},
   118  		},
   119  		"invalid ref, group allowed and both api version and group are specified": {
   120  			ref: &KReference{
   121  				Namespace:  namespace,
   122  				Name:       name,
   123  				Kind:       kind,
   124  				Group:      "eventing.knative.dev",
   125  				APIVersion: "eventing.knative.dev/v1",
   126  			},
   127  			ctx:  KReferenceGroupAllowed(ctx),
   128  			want: nil,
   129  		},
   130  		"valid ref, group enabled and both apiVersion and group missing": {
   131  			ref: &KReference{
   132  				Namespace: namespace,
   133  				Name:      name,
   134  				Kind:      kind,
   135  			},
   136  			ctx:  KReferenceGroupAllowed(ctx),
   137  			want: apis.ErrMissingField("apiVersion").Also(apis.ErrMissingField("group")),
   138  		},
   139  		"valid ref, group enabled and configured": {
   140  			ref: &KReference{
   141  				Namespace: namespace,
   142  				Name:      name,
   143  				Kind:      kind,
   144  				Group:     group,
   145  			},
   146  			ctx:  KReferenceGroupAllowed(ctx),
   147  			want: nil,
   148  		},
   149  		"valid ref, group enabled but apiVersion configured": {
   150  			ref: &KReference{
   151  				Namespace:  namespace,
   152  				Name:       name,
   153  				Kind:       kind,
   154  				APIVersion: apiVersion,
   155  			},
   156  			ctx:  KReferenceGroupAllowed(ctx),
   157  			want: nil,
   158  		},
   159  		"valid ref, mismatched namespaces, but overridden": {
   160  			ref: &KReference{
   161  				Namespace:  namespace,
   162  				Name:       name,
   163  				Kind:       kind,
   164  				APIVersion: apiVersion,
   165  			},
   166  			ctx: apis.AllowDifferentNamespace(apis.WithinParent(ctx, metav1.ObjectMeta{Namespace: "diffns"})),
   167  		},
   168  	}
   169  
   170  	for name, tc := range tests {
   171  		t.Run(name, func(t *testing.T) {
   172  			gotErr := tc.ref.Validate(tc.ctx)
   173  
   174  			if tc.want != nil {
   175  				if diff := cmp.Diff(tc.want.Error(), gotErr.Error()); diff != "" {
   176  					t.Errorf("Got: %v wanted %v", gotErr, tc.want)
   177  				}
   178  			} else if gotErr != nil {
   179  				t.Errorf("Validate() = %v, wanted nil", gotErr)
   180  			}
   181  		})
   182  	}
   183  }
   184  
   185  func TestKReferenceSetDefaults(t *testing.T) {
   186  	ctx := context.Background()
   187  
   188  	const parentNamespace = "parentNamespace"
   189  
   190  	tests := map[string]struct {
   191  		ref  *KReference
   192  		ctx  context.Context
   193  		want string
   194  	}{
   195  		"namespace set, nothing in context, not modified ": {
   196  			ref:  &KReference{Namespace: namespace},
   197  			ctx:  ctx,
   198  			want: namespace,
   199  		},
   200  		"namespace set, context set, not modified ": {
   201  			ref:  &KReference{Namespace: namespace},
   202  			ctx:  apis.WithinParent(ctx, metav1.ObjectMeta{Namespace: parentNamespace}),
   203  			want: namespace,
   204  		},
   205  		"namespace not set, context set, defaulted": {
   206  			ref:  &KReference{},
   207  			ctx:  apis.WithinParent(ctx, metav1.ObjectMeta{Namespace: parentNamespace}),
   208  			want: parentNamespace,
   209  		},
   210  	}
   211  	for name, tc := range tests {
   212  		t.Run(name, func(t *testing.T) {
   213  			tc.ref.SetDefaults(tc.ctx)
   214  			if tc.ref.Namespace != tc.want {
   215  				t.Errorf("Namespace = %s; want: %s", tc.ref.Namespace, tc.want)
   216  			}
   217  		})
   218  	}
   219  }