knative.dev/pkg@v0.0.0-20260602142205-ac97e43f6622/apis/duck/v1/destination_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 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  	kind       = "SomeKind"
    30  	apiVersion = "v1mega1"
    31  	name       = "a-name"
    32  	namespace  = "b-namespace"
    33  )
    34  
    35  var (
    36  	testCert = `-----BEGIN CERTIFICATE-----
    37  MIIDmjCCAoKgAwIBAgIUYzA4bTMXevuk3pl2Mn8hpCYL2C0wDQYJKoZIhvcNAQEL
    38  BQAwLzELMAkGA1UEBhMCVVMxIDAeBgNVBAMMF0tuYXRpdmUtRXhhbXBsZS1Sb290
    39  LUNBMB4XDTIzMDQwNTEzMTUyNFoXDTI2MDEyMzEzMTUyNFowbTELMAkGA1UEBhMC
    40  VVMxEjAQBgNVBAgMCVlvdXJTdGF0ZTERMA8GA1UEBwwIWW91ckNpdHkxHTAbBgNV
    41  BAoMFEV4YW1wbGUtQ2VydGlmaWNhdGVzMRgwFgYDVQQDDA9sb2NhbGhvc3QubG9j
    42  YWwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC5teo+En6U5nhqn7Sc
    43  uanqswUmPlgs9j/8l21Rhb4T+ezlYKGQGhbJyFFMuiCE1Rjn8bpCwi7Nnv12Y2nz
    44  FhEv2Jx0yL3Tqx0Q593myqKDq7326EtbO7wmDT0XD03twH5i9XZ0L0ihPWn1mjUy
    45  WxhnHhoFpXrsnQECJorZY6aTrFbGVYelIaj5AriwiqyL0fET8pueI2GwLjgWHFSH
    46  X8XsGAlcLUhkQG0Z+VO9usy4M1Wpt+cL6cnTiQ+sRmZ6uvaj8fKOT1Slk/oUeAi4
    47  WqFkChGzGzLik0QrhKGTdw3uUvI1F2sdQj0GYzXaWqRz+tP9qnXdzk1GrszKKSlm
    48  WBTLAgMBAAGjcDBuMB8GA1UdIwQYMBaAFJJcCftus4vj98N0zQQautsjEu82MAkG
    49  A1UdEwQCMAAwCwYDVR0PBAQDAgTwMBQGA1UdEQQNMAuCCWxvY2FsaG9zdDAdBgNV
    50  HQ4EFgQUnu/3vqA3VEzm128x/hLyZzR9JlgwDQYJKoZIhvcNAQELBQADggEBAFc+
    51  1cKt/CNjHXUsirgEhry2Mm96R6Yxuq//mP2+SEjdab+FaXPZkjHx118u3PPX5uTh
    52  gTT7rMfka6J5xzzQNqJbRMgNpdEFH1bbc11aYuhi0khOAe0cpQDtktyuDJQMMv3/
    53  3wu6rLr6fmENo0gdcyUY9EiYrglWGtdXhlo4ySRY8UZkUScG2upvyOhHTxVCAjhP
    54  efbMkNjmDuZOMK+wqanqr5YV6zMPzkQK7DspfRgasMAQmugQu7r2MZpXg8Ilhro1
    55  s/wImGnMVk5RzpBVrq2VB9SkX/ThTVYEC/Sd9BQM364MCR+TA1l8/ptaLFLuwyw8
    56  O2dgzikq8iSy1BlRsVw=
    57  -----END CERTIFICATE-----`
    58  
    59  	csr = `-----BEGIN CERTIFICATE REQUEST-----
    60  MIICvDCCAaQCAQAwdzELMAkGA1UEBhMCVVMxDTALBgNVBAgMBFV0YWgxDzANBgNV
    61  BAcMBkxpbmRvbjEWMBQGA1UECgwNRGlnaUNlcnQgSW5jLjERMA8GA1UECwwIRGln
    62  aUNlcnQxHTAbBgNVBAMMFGV4YW1wbGUuZGlnaWNlcnQuY29tMIIBIjANBgkqhkiG
    63  9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8+To7d+2kPWeBv/orU3LVbJwDrSQbeKamCmo
    64  wp5bqDxIwV20zqRb7APUOKYoVEFFOEQs6T6gImnIolhbiH6m4zgZ/CPvWBOkZc+c
    65  1Po2EmvBz+AD5sBdT5kzGQA6NbWyZGldxRthNLOs1efOhdnWFuhI162qmcflgpiI
    66  WDuwq4C9f+YkeJhNn9dF5+owm8cOQmDrV8NNdiTqin8q3qYAHHJRW28glJUCZkTZ
    67  wIaSR6crBQ8TbYNE0dc+Caa3DOIkz1EOsHWzTx+n0zKfqcbgXi4DJx+C1bjptYPR
    68  BPZL8DAeWuA8ebudVT44yEp82G96/Ggcf7F33xMxe0yc+Xa6owIDAQABoAAwDQYJ
    69  KoZIhvcNAQEFBQADggEBAB0kcrFccSmFDmxox0Ne01UIqSsDqHgL+XmHTXJwre6D
    70  hJSZwbvEtOK0G3+dr4Fs11WuUNt5qcLsx5a8uk4G6AKHMzuhLsJ7XZjgmQXGECpY
    71  Q4mC3yT3ZoCGpIXbw+iP3lmEEXgaQL0Tx5LFl/okKbKYwIqNiyKWOMj7ZR/wxWg/
    72  ZDGRs55xuoeLDJ/ZRFf9bI+IaCUd1YrfYcHIl3G87Av+r49YVwqRDT0VDV7uLgqn
    73  29XI1PpVUNCPQGn9p/eX6Qo7vpDaPybRtA2R7XLKjQaF9oXWeCUqy1hvJac9QFO2
    74  97Ob1alpHPoZ7mWiEuJwjBPii6a9M9G30nUo39lBi1w=
    75  -----END CERTIFICATE REQUEST-----`
    76  
    77  	invaidCert = "certificate"
    78  )
    79  
    80  func TestValidateDestination(t *testing.T) {
    81  	ctx := context.Background()
    82  
    83  	validRef := KReference{
    84  		Kind:       kind,
    85  		APIVersion: apiVersion,
    86  		Name:       name,
    87  		Namespace:  namespace,
    88  	}
    89  
    90  	validURL := apis.URL{
    91  		Scheme: "http",
    92  		Host:   "host",
    93  	}
    94  
    95  	tests := map[string]struct {
    96  		dest *Destination
    97  		want string
    98  	}{"nil valid": {
    99  		dest: nil,
   100  	}, "valid ref": {
   101  		dest: &Destination{
   102  			Ref: &validRef,
   103  		},
   104  	}, "invalid ref, missing name": {
   105  		dest: &Destination{
   106  			Ref: &KReference{
   107  				Namespace:  namespace,
   108  				Kind:       kind,
   109  				APIVersion: apiVersion,
   110  			},
   111  		},
   112  		want: "missing field(s): ref.name",
   113  	}, "invalid ref, missing api version": {
   114  		dest: &Destination{
   115  			Ref: &KReference{
   116  				Namespace: namespace,
   117  				Kind:      kind,
   118  				Name:      name,
   119  			},
   120  		},
   121  		want: "missing field(s): ref.apiVersion",
   122  	}, "invalid ref, missing kind": {
   123  		dest: &Destination{
   124  			Ref: &KReference{
   125  				Namespace:  namespace,
   126  				APIVersion: apiVersion,
   127  				Name:       name,
   128  			},
   129  		},
   130  		want: "missing field(s): ref.kind",
   131  	}, "valid uri": {
   132  		dest: &Destination{
   133  			URI: &validURL,
   134  		},
   135  	}, "invalid, uri has no host": {
   136  		dest: &Destination{
   137  			URI: &apis.URL{
   138  				Scheme: "http",
   139  			},
   140  		},
   141  		want: "invalid value: Relative URI is not allowed when Ref and [apiVersion, kind, name] is absent: uri",
   142  	}, "invalid, uri is not absolute url": {
   143  		dest: &Destination{
   144  			URI: &apis.URL{
   145  				Host: "host",
   146  			},
   147  		},
   148  		want: "invalid value: Relative URI is not allowed when Ref and [apiVersion, kind, name] is absent: uri",
   149  	}, "invalid, both uri and ref, uri is absolute URL": {
   150  		dest: &Destination{
   151  			URI: &validURL,
   152  			Ref: &validRef,
   153  		},
   154  		want: "Absolute URI is not allowed when Ref or [apiVersion, kind, name] is present: [apiVersion, kind, name], ref, uri",
   155  	}, "invalid, both ref, [apiVersion, kind, name] and uri  are nil": {
   156  		dest: &Destination{},
   157  		want: "expected at least one, got none: ref, uri",
   158  	}, "valid, both uri and ref, uri is not a absolute URL": {
   159  		dest: &Destination{
   160  			URI: &apis.URL{
   161  				Path: "/handler",
   162  			},
   163  			Ref: &validRef,
   164  		},
   165  	}, "valid, CACert is valid": {
   166  		dest: &Destination{
   167  			URI: &apis.URL{
   168  				Path: "/handler",
   169  			},
   170  			Ref:     &validRef,
   171  			CACerts: &testCert,
   172  		},
   173  	}, "invalid,CACert is invalid": {
   174  		dest: &Destination{
   175  			URI: &apis.URL{
   176  				Path: "/handler",
   177  			},
   178  			Ref:     &validRef,
   179  			CACerts: &invaidCert,
   180  		},
   181  		want: "invalid value: CA Cert provided is invalid: caCert",
   182  	}, "invalid,CSR provided not CA Cert": {
   183  		dest: &Destination{
   184  			URI: &apis.URL{
   185  				Path: "/handler",
   186  			},
   187  			Ref:     &validRef,
   188  			CACerts: &csr,
   189  		},
   190  		want: "invalid value: CA Cert provided is not a certificate: caCert",
   191  	}}
   192  
   193  	for name, tc := range tests {
   194  		t.Run(name, func(t *testing.T) {
   195  			gotErr := tc.dest.Validate(ctx)
   196  
   197  			if tc.want != "" {
   198  				if got, want := gotErr.Error(), tc.want; got != want {
   199  					t.Errorf("%s: Error() = %v, wanted %v", name, got, want)
   200  				}
   201  			} else if gotErr != nil {
   202  				t.Errorf("%s: Validate() = %v, wanted nil", name, gotErr)
   203  			}
   204  		})
   205  	}
   206  }
   207  
   208  func TestDestinationGetRef(t *testing.T) {
   209  	ref := &KReference{
   210  		APIVersion: apiVersion,
   211  		Kind:       kind,
   212  		Name:       name,
   213  	}
   214  	tests := map[string]struct {
   215  		dest *Destination
   216  		want *KReference
   217  	}{"nil destination": {
   218  		dest: nil,
   219  		want: nil,
   220  	}, "uri": {
   221  		dest: &Destination{
   222  			URI: &apis.URL{
   223  				Host: "foo",
   224  			},
   225  		},
   226  		want: nil,
   227  	}, "ref": {
   228  		dest: &Destination{
   229  			Ref: ref,
   230  		},
   231  		want: ref,
   232  	}}
   233  
   234  	for n, tc := range tests {
   235  		t.Run(n, func(t *testing.T) {
   236  			got := tc.dest.GetRef()
   237  			if diff := cmp.Diff(tc.want, got); diff != "" {
   238  				t.Error("Unexpected result (-want +got):", diff)
   239  			}
   240  		})
   241  	}
   242  }
   243  
   244  func TestDestinationSetDefaults(t *testing.T) {
   245  	ctx := context.Background()
   246  
   247  	const parentNamespace = "parentNamespace"
   248  
   249  	tests := map[string]struct {
   250  		d    *Destination
   251  		ctx  context.Context
   252  		want string
   253  	}{"destination nil ": {
   254  		d:   nil,
   255  		ctx: ctx,
   256  	}, "uri set, nothing in ref, not modified ": {
   257  		d:   &Destination{URI: apis.HTTP("example.com")},
   258  		ctx: ctx,
   259  	}, "namespace set, nothing in context, not modified ": {
   260  		d:    &Destination{Ref: &KReference{Namespace: namespace}},
   261  		ctx:  ctx,
   262  		want: namespace,
   263  	}, "namespace set, context set, not modified ": {
   264  		d:    &Destination{Ref: &KReference{Namespace: namespace}},
   265  		ctx:  apis.WithinParent(ctx, metav1.ObjectMeta{Namespace: parentNamespace}),
   266  		want: namespace,
   267  	}, "namespace set, uri set, context set, not modified ": {
   268  		d:    &Destination{Ref: &KReference{Namespace: namespace}, URI: apis.HTTP("example.com")},
   269  		ctx:  apis.WithinParent(ctx, metav1.ObjectMeta{Namespace: parentNamespace}),
   270  		want: namespace,
   271  	}, "namespace not set, context set, defaulted": {
   272  		d:    &Destination{Ref: &KReference{}},
   273  		ctx:  apis.WithinParent(ctx, metav1.ObjectMeta{Namespace: parentNamespace}),
   274  		want: parentNamespace,
   275  	}, "namespace not set, uri set, context set, defaulted": {
   276  		d:    &Destination{Ref: &KReference{}, URI: apis.HTTP("example.com")},
   277  		ctx:  apis.WithinParent(ctx, metav1.ObjectMeta{Namespace: parentNamespace}),
   278  		want: parentNamespace,
   279  	}}
   280  	for name, tc := range tests {
   281  		t.Run(name, func(t *testing.T) {
   282  			tc.d.SetDefaults(tc.ctx)
   283  			if tc.d != nil {
   284  				if tc.d.Ref != nil && tc.d.Ref.Namespace != tc.want {
   285  					t.Errorf("Got: %s wanted %s", tc.d.Ref.Namespace, tc.want)
   286  				}
   287  				if tc.d.Ref == nil && tc.want != "" {
   288  					t.Error("Got: nil Ref wanted", tc.want)
   289  				}
   290  			}
   291  		})
   292  	}
   293  }