knative.dev/pkg@v0.0.0-20260602142205-ac97e43f6622/apis/duck/v1beta1/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 v1beta1
    18  
    19  import (
    20  	"context"
    21  	"testing"
    22  
    23  	"github.com/google/go-cmp/cmp"
    24  	corev1 "k8s.io/api/core/v1"
    25  	"knative.dev/pkg/apis"
    26  )
    27  
    28  const (
    29  	kind       = "SomeKind"
    30  	apiVersion = "v1mega1"
    31  	name       = "a-name"
    32  )
    33  
    34  var (
    35  	testCert = `-----BEGIN CERTIFICATE-----
    36  MIIDmjCCAoKgAwIBAgIUYzA4bTMXevuk3pl2Mn8hpCYL2C0wDQYJKoZIhvcNAQEL
    37  BQAwLzELMAkGA1UEBhMCVVMxIDAeBgNVBAMMF0tuYXRpdmUtRXhhbXBsZS1Sb290
    38  LUNBMB4XDTIzMDQwNTEzMTUyNFoXDTI2MDEyMzEzMTUyNFowbTELMAkGA1UEBhMC
    39  VVMxEjAQBgNVBAgMCVlvdXJTdGF0ZTERMA8GA1UEBwwIWW91ckNpdHkxHTAbBgNV
    40  BAoMFEV4YW1wbGUtQ2VydGlmaWNhdGVzMRgwFgYDVQQDDA9sb2NhbGhvc3QubG9j
    41  YWwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC5teo+En6U5nhqn7Sc
    42  uanqswUmPlgs9j/8l21Rhb4T+ezlYKGQGhbJyFFMuiCE1Rjn8bpCwi7Nnv12Y2nz
    43  FhEv2Jx0yL3Tqx0Q593myqKDq7326EtbO7wmDT0XD03twH5i9XZ0L0ihPWn1mjUy
    44  WxhnHhoFpXrsnQECJorZY6aTrFbGVYelIaj5AriwiqyL0fET8pueI2GwLjgWHFSH
    45  X8XsGAlcLUhkQG0Z+VO9usy4M1Wpt+cL6cnTiQ+sRmZ6uvaj8fKOT1Slk/oUeAi4
    46  WqFkChGzGzLik0QrhKGTdw3uUvI1F2sdQj0GYzXaWqRz+tP9qnXdzk1GrszKKSlm
    47  WBTLAgMBAAGjcDBuMB8GA1UdIwQYMBaAFJJcCftus4vj98N0zQQautsjEu82MAkG
    48  A1UdEwQCMAAwCwYDVR0PBAQDAgTwMBQGA1UdEQQNMAuCCWxvY2FsaG9zdDAdBgNV
    49  HQ4EFgQUnu/3vqA3VEzm128x/hLyZzR9JlgwDQYJKoZIhvcNAQELBQADggEBAFc+
    50  1cKt/CNjHXUsirgEhry2Mm96R6Yxuq//mP2+SEjdab+FaXPZkjHx118u3PPX5uTh
    51  gTT7rMfka6J5xzzQNqJbRMgNpdEFH1bbc11aYuhi0khOAe0cpQDtktyuDJQMMv3/
    52  3wu6rLr6fmENo0gdcyUY9EiYrglWGtdXhlo4ySRY8UZkUScG2upvyOhHTxVCAjhP
    53  efbMkNjmDuZOMK+wqanqr5YV6zMPzkQK7DspfRgasMAQmugQu7r2MZpXg8Ilhro1
    54  s/wImGnMVk5RzpBVrq2VB9SkX/ThTVYEC/Sd9BQM364MCR+TA1l8/ptaLFLuwyw8
    55  O2dgzikq8iSy1BlRsVw=
    56  -----END CERTIFICATE-----`
    57  
    58  	csr = `-----BEGIN CERTIFICATE REQUEST-----
    59  MIICvDCCAaQCAQAwdzELMAkGA1UEBhMCVVMxDTALBgNVBAgMBFV0YWgxDzANBgNV
    60  BAcMBkxpbmRvbjEWMBQGA1UECgwNRGlnaUNlcnQgSW5jLjERMA8GA1UECwwIRGln
    61  aUNlcnQxHTAbBgNVBAMMFGV4YW1wbGUuZGlnaWNlcnQuY29tMIIBIjANBgkqhkiG
    62  9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8+To7d+2kPWeBv/orU3LVbJwDrSQbeKamCmo
    63  wp5bqDxIwV20zqRb7APUOKYoVEFFOEQs6T6gImnIolhbiH6m4zgZ/CPvWBOkZc+c
    64  1Po2EmvBz+AD5sBdT5kzGQA6NbWyZGldxRthNLOs1efOhdnWFuhI162qmcflgpiI
    65  WDuwq4C9f+YkeJhNn9dF5+owm8cOQmDrV8NNdiTqin8q3qYAHHJRW28glJUCZkTZ
    66  wIaSR6crBQ8TbYNE0dc+Caa3DOIkz1EOsHWzTx+n0zKfqcbgXi4DJx+C1bjptYPR
    67  BPZL8DAeWuA8ebudVT44yEp82G96/Ggcf7F33xMxe0yc+Xa6owIDAQABoAAwDQYJ
    68  KoZIhvcNAQEFBQADggEBAB0kcrFccSmFDmxox0Ne01UIqSsDqHgL+XmHTXJwre6D
    69  hJSZwbvEtOK0G3+dr4Fs11WuUNt5qcLsx5a8uk4G6AKHMzuhLsJ7XZjgmQXGECpY
    70  Q4mC3yT3ZoCGpIXbw+iP3lmEEXgaQL0Tx5LFl/okKbKYwIqNiyKWOMj7ZR/wxWg/
    71  ZDGRs55xuoeLDJ/ZRFf9bI+IaCUd1YrfYcHIl3G87Av+r49YVwqRDT0VDV7uLgqn
    72  29XI1PpVUNCPQGn9p/eX6Qo7vpDaPybRtA2R7XLKjQaF9oXWeCUqy1hvJac9QFO2
    73  97Ob1alpHPoZ7mWiEuJwjBPii6a9M9G30nUo39lBi1w=
    74  -----END CERTIFICATE REQUEST-----`
    75  
    76  	invaidCert = "certificate"
    77  )
    78  
    79  func TestValidateDestination(t *testing.T) {
    80  	ctx := context.Background()
    81  
    82  	validRef := corev1.ObjectReference{
    83  		Kind:       kind,
    84  		APIVersion: apiVersion,
    85  		Name:       name,
    86  	}
    87  
    88  	validURL := apis.URL{
    89  		Scheme: "http",
    90  		Host:   "host",
    91  	}
    92  
    93  	tests := map[string]struct {
    94  		dest *Destination
    95  		want string
    96  	}{
    97  		"nil valid": {
    98  			dest: nil,
    99  			want: "",
   100  		},
   101  		"valid ref": {
   102  			dest: &Destination{
   103  				Ref: &validRef,
   104  			},
   105  			want: "",
   106  		},
   107  		"invalid ref, missing name": {
   108  			dest: &Destination{
   109  				Ref: &corev1.ObjectReference{
   110  					Kind:       kind,
   111  					APIVersion: apiVersion,
   112  				},
   113  			},
   114  			want: "missing field(s): ref.name",
   115  		},
   116  		"invalid ref, missing api version": {
   117  			dest: &Destination{
   118  				Ref: &corev1.ObjectReference{
   119  					Kind: kind,
   120  					Name: apiVersion,
   121  				},
   122  			},
   123  			want: "missing field(s): ref.apiVersion",
   124  		},
   125  		"invalid ref, missing kind": {
   126  			dest: &Destination{
   127  				Ref: &corev1.ObjectReference{
   128  					APIVersion: apiVersion,
   129  					Name:       name,
   130  				},
   131  			},
   132  			want: "missing field(s): ref.kind",
   133  		},
   134  		"valid [apiVersion, kind, name]": {
   135  			dest: &Destination{
   136  				DeprecatedKind:       kind,
   137  				DeprecatedAPIVersion: apiVersion,
   138  				DeprecatedName:       name,
   139  			},
   140  			want: "",
   141  		},
   142  		"invalid [apiVersion, kind, name], missing name": {
   143  			dest: &Destination{
   144  				DeprecatedKind:       kind,
   145  				DeprecatedAPIVersion: apiVersion,
   146  			},
   147  			want: "missing field(s): name",
   148  		},
   149  		"invalid [apiVersion, kind, name], missing api version": {
   150  			dest: &Destination{
   151  				DeprecatedKind: kind,
   152  				DeprecatedName: name,
   153  			},
   154  			want: "missing field(s): apiVersion",
   155  		},
   156  		"invalid [apiVersion, kind, name], missing kind": {
   157  			dest: &Destination{
   158  				DeprecatedAPIVersion: apiVersion,
   159  				DeprecatedName:       name,
   160  			},
   161  			want: "missing field(s): kind",
   162  		},
   163  		"valid uri": {
   164  			dest: &Destination{
   165  				URI: &validURL,
   166  			},
   167  		},
   168  		"invalid, uri has no host": {
   169  			dest: &Destination{
   170  				URI: &apis.URL{
   171  					Scheme: "http",
   172  				},
   173  			},
   174  			want: "invalid value: Relative URI is not allowed when Ref and [apiVersion, kind, name] is absent: uri",
   175  		},
   176  		"invalid, uri is not absolute url": {
   177  			dest: &Destination{
   178  				URI: &apis.URL{
   179  					Host: "host",
   180  				},
   181  			},
   182  			want: "invalid value: Relative URI is not allowed when Ref and [apiVersion, kind, name] is absent: uri",
   183  		},
   184  		"invalid, both ref and [apiVersion, kind, name] are present ": {
   185  			dest: &Destination{
   186  				Ref: &corev1.ObjectReference{
   187  					Kind:       "SomeKind",
   188  					APIVersion: "v1mega1",
   189  					Name:       "a-name",
   190  				},
   191  				DeprecatedKind:       kind,
   192  				DeprecatedAPIVersion: apiVersion,
   193  				DeprecatedName:       name,
   194  			},
   195  			want: "Ref and [apiVersion, kind, name] can't be both present: [apiVersion, kind, name], ref",
   196  		},
   197  		"invalid, both uri and ref, uri is absolute URL": {
   198  			dest: &Destination{
   199  				URI: &validURL,
   200  				Ref: &validRef,
   201  			},
   202  			want: "Absolute URI is not allowed when Ref or [apiVersion, kind, name] is present: [apiVersion, kind, name], ref, uri",
   203  		},
   204  		"invalid, both uri and [apiVersion, kind, name], uri is absolute URL": {
   205  			dest: &Destination{
   206  				URI:                  &validURL,
   207  				DeprecatedKind:       kind,
   208  				DeprecatedAPIVersion: apiVersion,
   209  				DeprecatedName:       name,
   210  			},
   211  			want: "Absolute URI is not allowed when Ref or [apiVersion, kind, name] is present: [apiVersion, kind, name], ref, uri",
   212  		},
   213  		"invalid, both ref, [apiVersion, kind, name] and uri  are nil": {
   214  			dest: &Destination{},
   215  			want: "expected at least one, got none: [apiVersion, kind, name], ref, uri",
   216  		},
   217  		"valid, both uri and ref, uri is not a absolute URL": {
   218  			dest: &Destination{
   219  				URI: &apis.URL{
   220  					Path: "/handler",
   221  				},
   222  				Ref: &validRef,
   223  			},
   224  		},
   225  		"valid, both uri and [apiVersion, kind, name], uri is not a absolute URL": {
   226  			dest: &Destination{
   227  				URI: &apis.URL{
   228  					Path: "/handler",
   229  				},
   230  				DeprecatedKind:       kind,
   231  				DeprecatedAPIVersion: apiVersion,
   232  				DeprecatedName:       name,
   233  			},
   234  		},
   235  		"valid, CACert is valid": {
   236  			dest: &Destination{
   237  				URI: &apis.URL{
   238  					Path: "/handler",
   239  				},
   240  				Ref:     &validRef,
   241  				CACerts: &testCert,
   242  			},
   243  		},
   244  		"invalid,CACert is invalid": {
   245  			dest: &Destination{
   246  				URI: &apis.URL{
   247  					Path: "/handler",
   248  				},
   249  				Ref:     &validRef,
   250  				CACerts: &invaidCert,
   251  			},
   252  			want: "invalid value: CA Cert provided is invalid: caCert",
   253  		},
   254  		"invalid,CSR provided not CA Cert": {
   255  			dest: &Destination{
   256  				URI: &apis.URL{
   257  					Path: "/handler",
   258  				},
   259  				Ref:     &validRef,
   260  				CACerts: &csr,
   261  			},
   262  			want: "invalid value: CA Cert provided is not a certificate: caCert",
   263  		},
   264  	}
   265  
   266  	for name, tc := range tests {
   267  		t.Run(name, func(t *testing.T) {
   268  			gotErr := tc.dest.Validate(ctx)
   269  
   270  			if tc.want != "" {
   271  				if got, want := gotErr.Error(), tc.want; got != want {
   272  					t.Errorf("%s: Error() = %v, wanted %v", name, got, want)
   273  				}
   274  			} else if gotErr != nil {
   275  				t.Errorf("%s: Validate() = %v, wanted nil", name, gotErr)
   276  			}
   277  		})
   278  	}
   279  }
   280  
   281  func TestValidateDestinationDisallowDeprecated(t *testing.T) {
   282  	ctx := context.Background()
   283  
   284  	validRef := corev1.ObjectReference{
   285  		Kind:       kind,
   286  		APIVersion: apiVersion,
   287  		Name:       name,
   288  	}
   289  
   290  	validURL := apis.URL{
   291  		Scheme: "http",
   292  		Host:   "host",
   293  	}
   294  
   295  	tests := map[string]struct {
   296  		dest *Destination
   297  		want string
   298  	}{
   299  		"nil valid": {
   300  			dest: nil,
   301  			want: "",
   302  		},
   303  		"valid ref": {
   304  			dest: &Destination{
   305  				Ref: &validRef,
   306  			},
   307  			want: "",
   308  		},
   309  		"invalid ref, missing name": {
   310  			dest: &Destination{
   311  				Ref: &corev1.ObjectReference{
   312  					Kind:       kind,
   313  					APIVersion: apiVersion,
   314  				},
   315  			},
   316  			want: "missing field(s): ref.name",
   317  		},
   318  		"invalid ref, missing api version": {
   319  			dest: &Destination{
   320  				Ref: &corev1.ObjectReference{
   321  					Kind: kind,
   322  					Name: apiVersion,
   323  				},
   324  			},
   325  			want: "missing field(s): ref.apiVersion",
   326  		},
   327  		"invalid ref, missing kind": {
   328  			dest: &Destination{
   329  				Ref: &corev1.ObjectReference{
   330  					APIVersion: apiVersion,
   331  					Name:       name,
   332  				},
   333  			},
   334  			want: "missing field(s): ref.kind",
   335  		},
   336  		"invalid deprecated [apiVersion, kind, name]": {
   337  			dest: &Destination{
   338  				DeprecatedKind:       kind,
   339  				DeprecatedAPIVersion: apiVersion,
   340  				DeprecatedName:       name,
   341  			},
   342  			want: "invalid value: apiVersion is not allowed here, it's a deprecated value: apiVersion\ninvalid value: kind is not allowed here, it's a deprecated value: kind\ninvalid value: name is not allowed here, it's a deprecated value: name",
   343  		},
   344  		"invalid deprecated [apiVersion, kind]": {
   345  			dest: &Destination{
   346  				DeprecatedKind:       kind,
   347  				DeprecatedAPIVersion: apiVersion,
   348  			},
   349  			want: "invalid value: apiVersion is not allowed here, it's a deprecated value: apiVersion\ninvalid value: kind is not allowed here, it's a deprecated value: kind",
   350  		},
   351  		"invalid deprecated [kind, name]": {
   352  			dest: &Destination{
   353  				DeprecatedKind: kind,
   354  				DeprecatedName: name,
   355  			},
   356  			want: "invalid value: kind is not allowed here, it's a deprecated value: kind\ninvalid value: name is not allowed here, it's a deprecated value: name",
   357  		},
   358  		"invalid deprecated [apiVersion, name]": {
   359  			dest: &Destination{
   360  				DeprecatedAPIVersion: apiVersion,
   361  				DeprecatedName:       name,
   362  			},
   363  			want: "invalid value: apiVersion is not allowed here, it's a deprecated value: apiVersion\ninvalid value: name is not allowed here, it's a deprecated value: name",
   364  		},
   365  		"valid uri": {
   366  			dest: &Destination{
   367  				URI: &validURL,
   368  			},
   369  		},
   370  		"invalid, uri has no host": {
   371  			dest: &Destination{
   372  				URI: &apis.URL{
   373  					Scheme: "http",
   374  				},
   375  			},
   376  			want: "invalid value: Relative URI is not allowed when Ref and [apiVersion, kind, name] is absent: uri",
   377  		},
   378  		"invalid, uri is not absolute url": {
   379  			dest: &Destination{
   380  				URI: &apis.URL{
   381  					Host: "host",
   382  				},
   383  			},
   384  			want: "invalid value: Relative URI is not allowed when Ref and [apiVersion, kind, name] is absent: uri",
   385  		},
   386  		"invalid deprecated, both ref and [apiVersion, kind, name] are present ": {
   387  			dest: &Destination{
   388  				Ref: &corev1.ObjectReference{
   389  					Kind:       "SomeKind",
   390  					APIVersion: "v1mega1",
   391  					Name:       "a-name",
   392  				},
   393  				DeprecatedKind:       kind,
   394  				DeprecatedAPIVersion: apiVersion,
   395  				DeprecatedName:       name,
   396  			},
   397  			want: "invalid value: apiVersion is not allowed here, it's a deprecated value: apiVersion\ninvalid value: kind is not allowed here, it's a deprecated value: kind\ninvalid value: name is not allowed here, it's a deprecated value: name",
   398  		},
   399  		"invalid, both uri and ref, uri is absolute URL": {
   400  			dest: &Destination{
   401  				URI: &validURL,
   402  				Ref: &validRef,
   403  			},
   404  			want: "Absolute URI is not allowed when Ref or [apiVersion, kind, name] is present: [apiVersion, kind, name], ref, uri",
   405  		},
   406  		"invalid, both uri and [apiVersion, kind, name], uri is absolute URL": {
   407  			dest: &Destination{
   408  				URI:                  &validURL,
   409  				DeprecatedKind:       kind,
   410  				DeprecatedAPIVersion: apiVersion,
   411  				DeprecatedName:       name,
   412  			},
   413  			want: "invalid value: apiVersion is not allowed here, it's a deprecated value: apiVersion\ninvalid value: kind is not allowed here, it's a deprecated value: kind\ninvalid value: name is not allowed here, it's a deprecated value: name",
   414  		},
   415  		"invalid, both ref, [apiVersion, kind, name] and uri  are nil": {
   416  			dest: &Destination{},
   417  			want: "expected at least one, got none: [apiVersion, kind, name], ref, uri",
   418  		},
   419  		"valid, both uri and ref, uri is not a absolute URL": {
   420  			dest: &Destination{
   421  				URI: &apis.URL{
   422  					Path: "/handler",
   423  				},
   424  				Ref: &validRef,
   425  			},
   426  		},
   427  		"invalid deprecated, both uri and [apiVersion, kind, name], uri is not a absolute URL": {
   428  			dest: &Destination{
   429  				URI: &apis.URL{
   430  					Path: "/handler",
   431  				},
   432  				DeprecatedKind:       kind,
   433  				DeprecatedAPIVersion: apiVersion,
   434  				DeprecatedName:       name,
   435  			},
   436  			want: "invalid value: apiVersion is not allowed here, it's a deprecated value: apiVersion\ninvalid value: kind is not allowed here, it's a deprecated value: kind\ninvalid value: name is not allowed here, it's a deprecated value: name",
   437  		},
   438  	}
   439  
   440  	for name, tc := range tests {
   441  		t.Run(name, func(t *testing.T) {
   442  			gotErr := tc.dest.ValidateDisallowDeprecated(ctx)
   443  
   444  			if tc.want != "" {
   445  				if got, want := gotErr.Error(), tc.want; got != want {
   446  					t.Errorf("%s: Error() = %v, wanted %v", name, got, want)
   447  				}
   448  			} else if gotErr != nil {
   449  				t.Errorf("%s: Validate() = %v, wanted nil", name, gotErr)
   450  			}
   451  		})
   452  	}
   453  }
   454  
   455  func TestDestination_GetRef(t *testing.T) {
   456  	ref := &corev1.ObjectReference{
   457  		APIVersion: apiVersion,
   458  		Kind:       kind,
   459  		Name:       name,
   460  	}
   461  	tests := map[string]struct {
   462  		dest *Destination
   463  		want *corev1.ObjectReference
   464  	}{
   465  		"nil destination": {
   466  			dest: nil,
   467  			want: nil,
   468  		},
   469  		"uri": {
   470  			dest: &Destination{
   471  				URI: &apis.URL{
   472  					Host: "foo",
   473  				},
   474  			},
   475  			want: nil,
   476  		},
   477  		"ref": {
   478  			dest: &Destination{
   479  				Ref: ref,
   480  			},
   481  			want: ref,
   482  		},
   483  		"deprecated ref": {
   484  			dest: &Destination{
   485  				DeprecatedAPIVersion: ref.APIVersion,
   486  				DeprecatedKind:       ref.Kind,
   487  				DeprecatedName:       ref.Name,
   488  			},
   489  			want: ref,
   490  		},
   491  	}
   492  
   493  	for n, tc := range tests {
   494  		t.Run(n, func(t *testing.T) {
   495  			got := tc.dest.GetRef()
   496  			if diff := cmp.Diff(tc.want, got); diff != "" {
   497  				t.Error("Unexpected result (-want +got):", diff)
   498  			}
   499  		})
   500  	}
   501  }