knative.dev/pkg@v0.0.0-20260602142205-ac97e43f6622/resolver/addressable_resolver_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 resolver_test
    18  
    19  import (
    20  	"context"
    21  	"errors"
    22  	"fmt"
    23  	"testing"
    24  
    25  	"github.com/google/go-cmp/cmp"
    26  	corev1 "k8s.io/api/core/v1"
    27  	"k8s.io/apimachinery/pkg/api/equality"
    28  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    29  	"k8s.io/apimachinery/pkg/runtime"
    30  	"k8s.io/apimachinery/pkg/runtime/schema"
    31  	"k8s.io/apimachinery/pkg/types"
    32  	"k8s.io/client-go/kubernetes/scheme"
    33  
    34  	"knative.dev/pkg/apis"
    35  	duckv1 "knative.dev/pkg/apis/duck/v1"
    36  	duckv1alpha1 "knative.dev/pkg/apis/duck/v1alpha1"
    37  	duckv1beta1 "knative.dev/pkg/apis/duck/v1beta1"
    38  	"knative.dev/pkg/client/injection/ducks/duck/v1/addressable"
    39  	fakedynamicclient "knative.dev/pkg/injection/clients/dynamicclient/fake"
    40  	"knative.dev/pkg/resolver"
    41  	"knative.dev/pkg/tracker"
    42  )
    43  
    44  const (
    45  	addressableDNS                           = "http://addressable.sink.svc.cluster.local"
    46  	addressableDNS1                          = "http://addressable.sink1.svc.cluster.local"
    47  	addressableDNS2                          = "http://addressable.sink2.svc.cluster.local"
    48  	addressableDNS3                          = "http://addressable.sink3.svc.cluster.local"
    49  	addressableDNSWithPathAndTrailingSlash   = "http://addressable.sink.svc.cluster.local/bar/"
    50  	addressableDNSWithPathAndNoTrailingSlash = "http://addressable.sink.svc.cluster.local/bar"
    51  
    52  	addressableName       = "testsink"
    53  	addressableName1      = "testsink1"
    54  	addressableName2      = "testsink2"
    55  	addressableName3      = "testsink3"
    56  	addressableKind       = "Sink"
    57  	addressableAPIVersion = "duck.knative.dev/v1"
    58  
    59  	unaddressableName       = "testunaddressable"
    60  	unaddressableKind       = "KResource"
    61  	unaddressableAPIVersion = "duck.knative.dev/v1alpha1"
    62  	unaddressableResource   = "kresources.duck.knative.dev"
    63  
    64  	testNS = "testnamespace"
    65  
    66  	CACert = `-----BEGIN CERTIFICATE-----
    67  MIICNDCCAaECEAKtZn5ORf5eV288mBle3cAwDQYJKoZIhvcNAQECBQAwXzELMAkG
    68  A1UEBhMCVVMxIDAeBgNVBAoTF1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMuMS4wLAYD
    69  VQQLEyVTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk0
    70  MTEwOTAwMDAwMFoXDTEwMDEwNzIzNTk1OVowXzELMAkGA1UEBhMCVVMxIDAeBgNV
    71  BAoTF1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMuMS4wLAYDVQQLEyVTZWN1cmUgU2Vy
    72  dmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGbMA0GCSqGSIb3DQEBAQUAA4GJ
    73  ADCBhQJ+AJLOesGugz5aqomDV6wlAXYMra6OLDfO6zV4ZFQD5YRAUcm/jwjiioII
    74  0haGN1XpsSECrXZogZoFokvJSyVmIlZsiAeP94FZbYQHZXATcXY+m3dM41CJVphI
    75  uR2nKRoTLkoRWZweFdVJVCxzOmmCsZc5nG1wZ0jl3S3WyB57AgMBAAEwDQYJKoZI
    76  hvcNAQECBQADfgBl3X7hsuyw4jrg7HFGmhkRuNPHoLQDQCYCPgmc4RKz0Vr2N6W3
    77  YQO2WxZpO8ZECAyIUwxrl0nHPjXcbLm7qt9cuzovk2C2qUtN8iD3zV9/ZHuO3ABc
    78  1/p3yjkWWW8O6tO1g39NTUJWdrTJXwT4OPjr0l91X817/OWOgHz8UA==
    79  -----END CERTIFICATE-----`
    80  
    81  	addressableAudience = "my-audience"
    82  )
    83  
    84  func init() {
    85  	// Add types to scheme
    86  	duckv1alpha1.AddToScheme(scheme.Scheme)
    87  	duckv1beta1.AddToScheme(scheme.Scheme)
    88  
    89  	scheme.Scheme.AddKnownTypeWithName(
    90  		schema.FromAPIVersionAndKind(unaddressableAPIVersion, unaddressableKind),
    91  		&unstructured.Unstructured{},
    92  	)
    93  	scheme.Scheme.AddKnownTypeWithName(
    94  		schema.FromAPIVersionAndKind(unaddressableAPIVersion, unaddressableKind+"List"),
    95  		&unstructured.UnstructuredList{},
    96  	)
    97  	scheme.Scheme.AddKnownTypeWithName(
    98  		schema.FromAPIVersionAndKind(addressableAPIVersion, addressableKind),
    99  		&unstructured.Unstructured{},
   100  	)
   101  	scheme.Scheme.AddKnownTypeWithName(
   102  		schema.FromAPIVersionAndKind(addressableAPIVersion, addressableKind+"List"),
   103  		&unstructured.UnstructuredList{},
   104  	)
   105  }
   106  
   107  func TestGetURIDestinationV1Beta1(t *testing.T) {
   108  	tests := map[string]struct {
   109  		objects []runtime.Object
   110  		dest    duckv1beta1.Destination
   111  		wantURI string
   112  		wantErr string
   113  	}{
   114  		"nil everything": {
   115  			wantErr: "destination missing Ref and URI, expected at least one",
   116  		}, "Happy URI with path": {
   117  			dest: duckv1beta1.Destination{
   118  				URI: &apis.URL{
   119  					Scheme: "http",
   120  					Host:   "example.com",
   121  					Path:   "/foo",
   122  				},
   123  			},
   124  			wantURI: "http://example.com/foo",
   125  		}, "URI is not absolute URL": {
   126  			dest: duckv1beta1.Destination{
   127  				URI: &apis.URL{
   128  					Host: "example.com",
   129  				},
   130  			},
   131  			wantErr: fmt.Sprintf("URI is not absolute (both scheme and host should be non-empty): %q", "//example.com"),
   132  		}, "URI with no host": {
   133  			dest: duckv1beta1.Destination{
   134  				URI: &apis.URL{
   135  					Scheme: "http",
   136  				},
   137  			},
   138  			wantErr: fmt.Sprintf("URI is not absolute (both scheme and host should be non-empty): %q", "http:"),
   139  		},
   140  		"Ref and [apiVersion, kind, name] both exists": {
   141  			objects: []runtime.Object{
   142  				getAddressable(),
   143  			},
   144  			dest: duckv1beta1.Destination{
   145  				Ref:                  addressableRef(),
   146  				DeprecatedKind:       addressableKind,
   147  				DeprecatedName:       addressableName,
   148  				DeprecatedAPIVersion: addressableAPIVersion,
   149  				DeprecatedNamespace:  testNS,
   150  			},
   151  			wantErr: "ref and [apiVersion, kind, name] can't be both present",
   152  		},
   153  		"happy ref": {
   154  			objects: []runtime.Object{
   155  				getAddressable(),
   156  			},
   157  			dest:    duckv1beta1.Destination{Ref: addressableRef()},
   158  			wantURI: addressableDNS,
   159  		}, "ref with relative uri": {
   160  			objects: []runtime.Object{
   161  				getAddressable(),
   162  			},
   163  			dest: duckv1beta1.Destination{
   164  				Ref: addressableRef(),
   165  				URI: &apis.URL{
   166  					Path: "/foo",
   167  				},
   168  			},
   169  			wantURI: addressableDNS + "/foo",
   170  		}, "ref with relative URI without leading slash": {
   171  			objects: []runtime.Object{
   172  				getAddressable(),
   173  			},
   174  			dest: duckv1beta1.Destination{
   175  				Ref: addressableRef(),
   176  				URI: &apis.URL{
   177  					Path: "foo",
   178  				},
   179  			},
   180  			wantURI: addressableDNS + "/foo",
   181  		}, "ref ends with path and trailing slash and relative URI without leading slash ": {
   182  			objects: []runtime.Object{
   183  				addressableWithPathAndTrailingSlash(),
   184  			},
   185  			dest: duckv1beta1.Destination{
   186  				Ref: addressableRef(),
   187  				URI: &apis.URL{
   188  					Path: "foo",
   189  				},
   190  			},
   191  			wantURI: addressableDNSWithPathAndTrailingSlash + "foo",
   192  		}, "ref ends with path and trailing slash and relative URI with leading slash ": {
   193  			objects: []runtime.Object{
   194  				addressableWithPathAndTrailingSlash(),
   195  			},
   196  			dest: duckv1beta1.Destination{
   197  				Ref: addressableRef(),
   198  				URI: &apis.URL{
   199  					Path: "/foo",
   200  				},
   201  			},
   202  			wantURI: addressableDNS + "/foo",
   203  		}, "ref ends with path and no trailing slash and relative URI without leading slash ": {
   204  			objects: []runtime.Object{
   205  				addressableWithPathAndNoTrailingSlash(),
   206  			},
   207  			dest: duckv1beta1.Destination{
   208  				Ref: addressableRef(),
   209  				URI: &apis.URL{
   210  					Path: "foo",
   211  				},
   212  			},
   213  			wantURI: addressableDNS + "/foo",
   214  		}, "ref ends with path and no trailing slash and relative URI with leading slash ": {
   215  			objects: []runtime.Object{
   216  				addressableWithPathAndNoTrailingSlash(),
   217  			},
   218  			dest: duckv1beta1.Destination{
   219  				Ref: addressableRef(),
   220  				URI: &apis.URL{
   221  					Path: "/foo",
   222  				},
   223  			},
   224  			wantURI: addressableDNS + "/foo",
   225  		}, "ref with URI which is absolute URL": {
   226  			objects: []runtime.Object{
   227  				getAddressable(),
   228  			},
   229  			dest: duckv1beta1.Destination{
   230  				Ref: addressableRef(),
   231  				URI: &apis.URL{
   232  					Scheme: "http",
   233  					Host:   "example.com",
   234  					Path:   "/foo",
   235  				},
   236  			},
   237  			wantErr: "absolute URI is not allowed when Ref or [apiVersion, kind, name] exists",
   238  		},
   239  		"happy [apiVersion, kind, name]": {
   240  			objects: []runtime.Object{
   241  				getAddressable(),
   242  			},
   243  			dest: duckv1beta1.Destination{
   244  				DeprecatedKind:       addressableKind,
   245  				DeprecatedName:       addressableName,
   246  				DeprecatedAPIVersion: addressableAPIVersion,
   247  				DeprecatedNamespace:  testNS,
   248  			},
   249  			wantURI: addressableDNS,
   250  		},
   251  		"[apiVersion, kind, name] with relative uri": {
   252  			objects: []runtime.Object{
   253  				getAddressable(),
   254  			},
   255  			dest: duckv1beta1.Destination{
   256  				DeprecatedKind:       addressableKind,
   257  				DeprecatedName:       addressableName,
   258  				DeprecatedAPIVersion: addressableAPIVersion,
   259  				DeprecatedNamespace:  testNS,
   260  				URI: &apis.URL{
   261  					Path: "/foo",
   262  				},
   263  			},
   264  			wantURI: addressableDNS + "/foo",
   265  		}, "[apiVersion, kind, name] with relative URI without leading slash": {
   266  			objects: []runtime.Object{
   267  				getAddressable(),
   268  			},
   269  			dest: duckv1beta1.Destination{
   270  				DeprecatedKind:       addressableKind,
   271  				DeprecatedName:       addressableName,
   272  				DeprecatedAPIVersion: addressableAPIVersion,
   273  				DeprecatedNamespace:  testNS,
   274  				URI: &apis.URL{
   275  					Path: "foo",
   276  				},
   277  			},
   278  			wantURI: addressableDNS + "/foo",
   279  		}, "[apiVersion, kind, name] ends with path and trailing slash and relative URI without leading slash ": {
   280  			objects: []runtime.Object{
   281  				addressableWithPathAndTrailingSlash(),
   282  			},
   283  			dest: duckv1beta1.Destination{
   284  				DeprecatedKind:       addressableKind,
   285  				DeprecatedName:       addressableName,
   286  				DeprecatedAPIVersion: addressableAPIVersion,
   287  				DeprecatedNamespace:  testNS,
   288  				URI: &apis.URL{
   289  					Path: "foo",
   290  				},
   291  			},
   292  			wantURI: addressableDNSWithPathAndTrailingSlash + "foo",
   293  		}, "[apiVersion, kind, name] ends with path and trailing slash and relative URI with leading slash ": {
   294  			objects: []runtime.Object{
   295  				addressableWithPathAndTrailingSlash(),
   296  			},
   297  			dest: duckv1beta1.Destination{
   298  				DeprecatedKind:       addressableKind,
   299  				DeprecatedName:       addressableName,
   300  				DeprecatedAPIVersion: addressableAPIVersion,
   301  				DeprecatedNamespace:  testNS,
   302  				URI: &apis.URL{
   303  					Path: "/foo",
   304  				},
   305  			},
   306  			wantURI: addressableDNS + "/foo",
   307  		}, "[apiVersion, kind, name] ends with path and no trailing slash and relative URI without leading slash ": {
   308  			objects: []runtime.Object{
   309  				addressableWithPathAndNoTrailingSlash(),
   310  			},
   311  			dest: duckv1beta1.Destination{
   312  				DeprecatedKind:       addressableKind,
   313  				DeprecatedName:       addressableName,
   314  				DeprecatedAPIVersion: addressableAPIVersion,
   315  				DeprecatedNamespace:  testNS,
   316  				URI: &apis.URL{
   317  					Path: "foo",
   318  				},
   319  			},
   320  			wantURI: addressableDNS + "/foo",
   321  		}, "[apiVersion, kind, name] ends with path and no trailing slash and relative URI with leading slash ": {
   322  			objects: []runtime.Object{
   323  				addressableWithPathAndNoTrailingSlash(),
   324  			},
   325  			dest: duckv1beta1.Destination{
   326  				DeprecatedKind:       addressableKind,
   327  				DeprecatedName:       addressableName,
   328  				DeprecatedAPIVersion: addressableAPIVersion,
   329  				DeprecatedNamespace:  testNS,
   330  				URI: &apis.URL{
   331  					Path: "/foo",
   332  				},
   333  			},
   334  			wantURI: addressableDNS + "/foo",
   335  		}, "[apiVersion, kind, name] with URI which is absolute URL": {
   336  			objects: []runtime.Object{
   337  				getAddressable(),
   338  			},
   339  			dest: duckv1beta1.Destination{
   340  				DeprecatedKind:       addressableKind,
   341  				DeprecatedName:       addressableName,
   342  				DeprecatedAPIVersion: addressableAPIVersion,
   343  				DeprecatedNamespace:  testNS,
   344  				URI: &apis.URL{
   345  					Scheme: "http",
   346  					Host:   "example.com",
   347  					Path:   "/foo",
   348  				},
   349  			},
   350  			wantErr: "absolute URI is not allowed when Ref or [apiVersion, kind, name] exists",
   351  		},
   352  		"nil url": {
   353  			objects: []runtime.Object{
   354  				addressableNilURL(),
   355  			},
   356  			dest:    duckv1beta1.Destination{Ref: unaddressableRef()},
   357  			wantErr: fmt.Sprintf("URL missing in address of %s", unaddressableKnativeRef()),
   358  		},
   359  		"nil address": {
   360  			objects: []runtime.Object{
   361  				addressableNilAddress(),
   362  			},
   363  			dest:    duckv1beta1.Destination{Ref: unaddressableRef()},
   364  			wantErr: fmt.Sprintf("address not set for %s", unaddressableKnativeRef()),
   365  		}, "missing host": {
   366  			objects: []runtime.Object{
   367  				addressableNoHostURL(),
   368  			},
   369  			dest:    duckv1beta1.Destination{Ref: unaddressableRef()},
   370  			wantErr: fmt.Sprintf("hostname missing in address of %s", unaddressableKnativeRef()),
   371  		}, "missing status": {
   372  			objects: []runtime.Object{
   373  				addressableNoStatus(),
   374  			},
   375  			dest:    duckv1beta1.Destination{Ref: unaddressableRef()},
   376  			wantErr: fmt.Sprintf("address not set for %s", unaddressableKnativeRef()),
   377  		}, "notFound": {
   378  			dest:    duckv1beta1.Destination{Ref: unaddressableRef()},
   379  			wantErr: fmt.Sprintf("failed to get object %s/%s: %s %q not found", testNS, unaddressableName, unaddressableResource, unaddressableName),
   380  		},
   381  	}
   382  
   383  	for n, tc := range tests {
   384  		t.Run(n, func(t *testing.T) {
   385  			ctx, _ := fakedynamicclient.With(context.Background(), scheme.Scheme, tc.objects...)
   386  			ctx = addressable.WithDuck(ctx)
   387  			r := resolver.NewURIResolverFromTracker(ctx, tracker.New(func(types.NamespacedName) {}, 0))
   388  
   389  			// Run it twice since this should be idempotent. URI Resolver should
   390  			// not modify the cache's copy.
   391  			_, _ = r.URIFromDestination(ctx, tc.dest, getAddressable())
   392  			uri, gotErr := r.URIFromDestination(ctx, tc.dest, getAddressable())
   393  
   394  			if gotErr != nil {
   395  				if tc.wantErr != "" {
   396  					if got, want := gotErr.Error(), tc.wantErr; got != want {
   397  						t.Errorf("Unexpected error (-want, +got) =\n%s", cmp.Diff(want, got))
   398  					}
   399  				} else {
   400  					t.Error("Unexpected error:", gotErr)
   401  				}
   402  				return
   403  			}
   404  			if got, want := uri, tc.wantURI; got != want {
   405  				t.Errorf("Unexpected object (-want, +got) =\n%s", cmp.Diff(got, want))
   406  			}
   407  		})
   408  	}
   409  }
   410  
   411  func TestGetURIDestinationV1(t *testing.T) {
   412  	tests := map[string]struct {
   413  		objects         []runtime.Object
   414  		dest            duckv1.Destination
   415  		customResolvers []resolver.RefResolverFunc
   416  		wantURI         string
   417  		wantErr         string
   418  	}{
   419  		"nil everything": {
   420  			wantErr: "destination missing Ref and URI, expected at least one",
   421  		}, "Happy URI with path": {
   422  			dest: duckv1.Destination{
   423  				URI: &apis.URL{
   424  					Scheme: "http",
   425  					Host:   "example.com",
   426  					Path:   "/foo",
   427  				},
   428  			},
   429  			wantURI: "http://example.com/foo",
   430  		}, "URI is not absolute URL": {
   431  			dest: duckv1.Destination{
   432  				URI: &apis.URL{
   433  					Host: "example.com",
   434  				},
   435  			},
   436  			wantErr: fmt.Sprintf("URI is not absolute (both scheme and host should be non-empty): %q", "//example.com"),
   437  		}, "URI with no host": {
   438  			dest: duckv1.Destination{
   439  				URI: &apis.URL{
   440  					Scheme: "http",
   441  				},
   442  			},
   443  			wantErr: fmt.Sprintf("URI is not absolute (both scheme and host should be non-empty): %q", "http:"),
   444  		},
   445  		"happy ref": {
   446  			objects: []runtime.Object{
   447  				getAddressable(),
   448  			},
   449  			dest:    duckv1.Destination{Ref: addressableKnativeRef()},
   450  			wantURI: addressableDNS,
   451  		}, "happy ref to k8s service": {
   452  			objects: []runtime.Object{
   453  				getAddressableFromKRef(k8sServiceRef()),
   454  			},
   455  			dest:    duckv1.Destination{Ref: k8sServiceRef()},
   456  			wantURI: "http://testsink.testnamespace.svc.cluster.local",
   457  		}, "ref with relative uri": {
   458  			objects: []runtime.Object{
   459  				getAddressable(),
   460  			},
   461  			dest: duckv1.Destination{
   462  				Ref: addressableKnativeRef(),
   463  				URI: &apis.URL{
   464  					Path: "/foo",
   465  				},
   466  			},
   467  			wantURI: addressableDNS + "/foo",
   468  		}, "ref with relative URI without leading slash": {
   469  			objects: []runtime.Object{
   470  				getAddressable(),
   471  			},
   472  			dest: duckv1.Destination{
   473  				Ref: addressableKnativeRef(),
   474  				URI: &apis.URL{
   475  					Path: "foo",
   476  				},
   477  			},
   478  			wantURI: addressableDNS + "/foo",
   479  		}, "ref ends with path and trailing slash and relative URI without leading slash ": {
   480  			objects: []runtime.Object{
   481  				addressableWithPathAndTrailingSlash(),
   482  			},
   483  			dest: duckv1.Destination{
   484  				Ref: addressableKnativeRef(),
   485  				URI: &apis.URL{
   486  					Path: "foo",
   487  				},
   488  			},
   489  			wantURI: addressableDNSWithPathAndTrailingSlash + "foo",
   490  		}, "ref ends with path and trailing slash and relative URI with leading slash ": {
   491  			objects: []runtime.Object{
   492  				addressableWithPathAndTrailingSlash(),
   493  			},
   494  			dest: duckv1.Destination{
   495  				Ref: addressableKnativeRef(),
   496  				URI: &apis.URL{
   497  					Path: "/foo",
   498  				},
   499  			},
   500  			wantURI: addressableDNS + "/foo",
   501  		}, "ref ends with path and no trailing slash and relative URI without leading slash ": {
   502  			objects: []runtime.Object{
   503  				addressableWithPathAndNoTrailingSlash(),
   504  			},
   505  			dest: duckv1.Destination{
   506  				Ref: addressableKnativeRef(),
   507  				URI: &apis.URL{
   508  					Path: "foo",
   509  				},
   510  			},
   511  			wantURI: addressableDNS + "/foo",
   512  		}, "ref ends with path and no trailing slash and relative URI with leading slash ": {
   513  			objects: []runtime.Object{
   514  				addressableWithPathAndNoTrailingSlash(),
   515  			},
   516  			dest: duckv1.Destination{
   517  				Ref: addressableKnativeRef(),
   518  				URI: &apis.URL{
   519  					Path: "/foo",
   520  				},
   521  			},
   522  			wantURI: addressableDNS + "/foo",
   523  		}, "ref with URI which is absolute URL": {
   524  			objects: []runtime.Object{
   525  				getAddressable(),
   526  			},
   527  			dest: duckv1.Destination{
   528  				Ref: addressableKnativeRef(),
   529  				URI: &apis.URL{
   530  					Scheme: "http",
   531  					Host:   "example.com",
   532  					Path:   "/foo",
   533  				},
   534  			},
   535  			wantErr: "absolute URI is not allowed when Ref or [apiVersion, kind, name] exists",
   536  		},
   537  		"nil url": {
   538  			objects: []runtime.Object{
   539  				addressableNilURL(),
   540  			},
   541  			dest:    duckv1.Destination{Ref: unaddressableKnativeRef()},
   542  			wantErr: fmt.Sprintf("URL missing in address of %s", unaddressableKnativeRef()),
   543  		},
   544  		"nil address": {
   545  			objects: []runtime.Object{
   546  				addressableNilAddress(),
   547  			},
   548  			dest:    duckv1.Destination{Ref: unaddressableKnativeRef()},
   549  			wantErr: fmt.Sprintf("address not set for %s", unaddressableKnativeRef()),
   550  		}, "missing host": {
   551  			objects: []runtime.Object{
   552  				addressableNoHostURL(),
   553  			},
   554  			dest:    duckv1.Destination{Ref: unaddressableKnativeRef()},
   555  			wantErr: fmt.Sprintf("hostname missing in address of %s", unaddressableKnativeRef()),
   556  		}, "missing status": {
   557  			objects: []runtime.Object{
   558  				addressableNoStatus(),
   559  			},
   560  			dest:    duckv1.Destination{Ref: unaddressableKnativeRef()},
   561  			wantErr: fmt.Sprintf("address not set for %s", unaddressableKnativeRef()),
   562  		}, "notFound": {
   563  			dest:    duckv1.Destination{Ref: unaddressableKnativeRef()},
   564  			wantErr: fmt.Sprintf("failed to get object %s/%s: %s %q not found", testNS, unaddressableName, unaddressableResource, unaddressableName),
   565  		}, "notFound k8s service": {
   566  			dest:    duckv1.Destination{Ref: k8sServiceRef()},
   567  			wantErr: fmt.Sprintf("failed to get object %s/%s: services %q not found", testNS, addressableName, addressableName),
   568  		}, "with sample resolver": {
   569  			dest:            duckv1.Destination{Ref: k8sServiceRef()},
   570  			customResolvers: []resolver.RefResolverFunc{sampleURIResolver},
   571  			wantURI:         "ref://" + addressableName + ".Service.v1",
   572  		}, "happy ref with sample resolver": {
   573  			objects: []runtime.Object{
   574  				getAddressable(),
   575  			},
   576  			dest:            duckv1.Destination{Ref: addressableKnativeRef()},
   577  			wantURI:         addressableDNS,
   578  			customResolvers: []resolver.RefResolverFunc{sampleURIResolver},
   579  		}, "unaddressable with sample resolver": {
   580  			dest:            duckv1.Destination{Ref: unaddressableKnativeRef()},
   581  			customResolvers: []resolver.RefResolverFunc{sampleURIResolver},
   582  			wantErr:         "cannot be referenced",
   583  		}, "happy with two sample resolvers, first one passes": {
   584  			dest:            duckv1.Destination{Ref: k8sServiceRef()},
   585  			customResolvers: []resolver.RefResolverFunc{sampleURIResolver, noopURIResolver},
   586  			wantURI:         "ref://" + addressableName + ".Service.v1",
   587  		}, "happy with two sample resolvers, second one passes": {
   588  			dest:            duckv1.Destination{Ref: k8sServiceRef()},
   589  			customResolvers: []resolver.RefResolverFunc{noopURIResolver, sampleURIResolver},
   590  			wantURI:         "ref://" + addressableName + ".Service.v1",
   591  		},
   592  	}
   593  
   594  	for n, tc := range tests {
   595  		t.Run(n, func(t *testing.T) {
   596  			ctx, _ := fakedynamicclient.With(context.Background(), scheme.Scheme, tc.objects...)
   597  			ctx = addressable.WithDuck(ctx)
   598  			r := resolver.NewURIResolverFromTracker(ctx, tracker.New(func(types.NamespacedName) {}, 0), tc.customResolvers...)
   599  
   600  			// Run it twice since this should be idempotent. URI Resolver should
   601  			// not modify the cache's copy.
   602  			_, _ = r.URIFromDestinationV1(ctx, tc.dest, getAddressable())
   603  			uri, gotErr := r.URIFromDestinationV1(ctx, tc.dest, getAddressable())
   604  
   605  			if gotErr != nil {
   606  				if tc.wantErr != "" {
   607  					if got, want := gotErr.Error(), tc.wantErr; got != want {
   608  						t.Errorf("Unexpected error (-want, +got) =\n%s", cmp.Diff(want, got))
   609  					}
   610  				} else {
   611  					t.Error("Unexpected error:", gotErr)
   612  				}
   613  			}
   614  			if got, want := uri.String(), tc.wantURI; got != want {
   615  				t.Errorf("Unexpected object (-want, +got) =\n%s", cmp.Diff(want, got))
   616  			}
   617  		})
   618  	}
   619  }
   620  
   621  func TestURIFromObjectReferenceErrors(t *testing.T) {
   622  	tests := map[string]struct {
   623  		objects []runtime.Object
   624  		ref     *corev1.ObjectReference
   625  		wantErr string
   626  	}{"nil": {
   627  		wantErr: "ref is nil",
   628  	}, "fail tracker with bad object": {
   629  		ref: invalidObjectRef(),
   630  		wantErr: `failed to track reference duck.knative.dev/v1, Resource=sinks -bad/testsink: invalid Reference:
   631  Namespace: a lowercase RFC 1123 label must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name',  or '123-abc', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?')`,
   632  	}, "fail get": {
   633  		ref:     addressableRef(),
   634  		wantErr: `failed to get object testnamespace/testsink: sinks.duck.knative.dev "testsink" not found`,
   635  	}}
   636  
   637  	for n, tc := range tests {
   638  		t.Run(n, func(t *testing.T) {
   639  			ctx, _ := fakedynamicclient.With(context.Background(), scheme.Scheme, tc.objects...)
   640  			ctx = addressable.WithDuck(ctx)
   641  			r := resolver.NewURIResolverFromTracker(ctx, tracker.New(func(types.NamespacedName) {}, 0))
   642  
   643  			// Run it twice since this should be idempotent. URI Resolver should
   644  			// not modify the cache's copy.
   645  			_, err1 := r.URIFromObjectReference(ctx, tc.ref, getAddressable())
   646  			_, err2 := r.URIFromObjectReference(ctx, tc.ref, getAddressable())
   647  
   648  			if err2 == nil {
   649  				t.Fatal("Expected failure")
   650  			}
   651  			if got, want := err2.Error(), tc.wantErr; got != want {
   652  				t.Errorf("Unexpected error (-want, +got) =\n%s", cmp.Diff(want, got))
   653  			}
   654  			if err1.Error() != err2.Error() {
   655  				t.Errorf("Idempotency fail: first err = %+v, second err = %+v", err1, err2)
   656  			}
   657  		})
   658  	}
   659  }
   660  
   661  func TestAddressableFromDestinationV1(t *testing.T) {
   662  	tests := map[string]struct {
   663  		objects         []runtime.Object
   664  		dest            duckv1.Destination
   665  		addr            *unstructured.Unstructured
   666  		customResolvers []resolver.RefResolverFunc
   667  		wantAddress     *duckv1.Addressable
   668  		wantErr         string
   669  	}{"address and addresses are not set": {
   670  		dest: duckv1.Destination{
   671  			Ref: addressableKnativeRef(),
   672  			URI: &apis.URL{
   673  				Path: "/foo",
   674  			},
   675  		},
   676  		objects: []runtime.Object{
   677  			addressableNoAddresses(),
   678  		},
   679  		addr:    addressableNoAddresses(),
   680  		wantErr: fmt.Sprintf("address not set for %s", addressableKnativeRef()),
   681  	}, "ref.address is set on destination and is present in target addressable addresses": {
   682  		dest: duckv1.Destination{
   683  			Ref: addressableKnativeRefWithAddress(),
   684  			URI: &apis.URL{
   685  				Path: "/foo",
   686  			},
   687  		},
   688  		objects: []runtime.Object{
   689  			addressableWithAddresses(),
   690  		},
   691  		wantAddress: addrWithName(),
   692  		addr:        addressableWithAddresses(),
   693  	}, "ref.address is set on destination and is NOT present in target addressable addresses": {
   694  		dest: duckv1.Destination{
   695  			Ref: addressableKnativeRefWithAddress(),
   696  			URI: &apis.URL{
   697  				Path: "/foo",
   698  			},
   699  		},
   700  		objects: []runtime.Object{
   701  			addressableWithDifferentAddresses(),
   702  		},
   703  		addr:    addressableWithDifferentAddresses(),
   704  		wantErr: fmt.Sprintf("address with name %q not found for %s", *addressableKnativeRefWithAddress().Address, addressableKnativeRefWithAddress()),
   705  	}, "address and addresses are set but no destination.ref.address is set": {
   706  		dest: duckv1.Destination{
   707  			Ref: addressableKnativeRef(),
   708  			URI: &apis.URL{
   709  				Path: "/foo",
   710  			},
   711  		},
   712  		objects: []runtime.Object{
   713  			addressableWithAddresses(),
   714  		},
   715  		addr:        addressableWithAddresses(),
   716  		wantAddress: addrWithName(),
   717  	}, "only address is set and no destination.ref.address is set": {
   718  		dest: duckv1.Destination{
   719  			Ref: addressableKnativeRef(),
   720  			URI: &apis.URL{
   721  				Path: "/foo",
   722  			},
   723  		},
   724  		objects: []runtime.Object{
   725  			addressableWithAddressOnly(),
   726  		},
   727  		addr:        addressableWithAddressOnly(),
   728  		wantAddress: addrWithName(),
   729  	}}
   730  
   731  	for n, tc := range tests {
   732  		t.Run(n, func(t *testing.T) {
   733  			ctx, _ := fakedynamicclient.With(context.Background(), scheme.Scheme, tc.objects...)
   734  			ctx = addressable.WithDuck(ctx)
   735  			r := resolver.NewURIResolverFromTracker(ctx, tracker.New(func(types.NamespacedName) {}, 0), tc.customResolvers...)
   736  
   737  			// Run it twice since this should be idempotent. URI Resolver should
   738  			// not modify the cache's copy.
   739  			_, _ = r.AddressableFromDestinationV1(ctx, tc.dest, tc.addr)
   740  			addr, gotErr := r.AddressableFromDestinationV1(ctx, tc.dest, tc.addr)
   741  
   742  			if gotErr != nil {
   743  				if tc.wantErr != "" {
   744  					if got, want := gotErr.Error(), tc.wantErr; got != want {
   745  						t.Errorf("Unexpected error (-want, +got) =\n%s", cmp.Diff(want, got))
   746  					}
   747  				} else {
   748  					t.Error("Unexpected error:", gotErr)
   749  				}
   750  				return
   751  			}
   752  			if !equality.Semantic.DeepEqual(addr, tc.wantAddress) {
   753  				t.Errorf("Unexpected object (-want, +got) =\n%s", cmp.Diff(addr, tc.wantAddress))
   754  			}
   755  		})
   756  	}
   757  }
   758  
   759  func TestAddressableFromDestinationScheme(t *testing.T) {
   760  	cert := CACert
   761  	tests := map[string]struct {
   762  		objects         []runtime.Object
   763  		dest            duckv1.Destination
   764  		addr            *unstructured.Unstructured
   765  		customResolvers []resolver.RefResolverFunc
   766  		wantScheme      string
   767  		wantErr         string
   768  	}{"destination is a raw k8s serving and there is CACerts set ": {
   769  		dest: duckv1.Destination{
   770  			Ref: k8sServiceRef(),
   771  			URI: &apis.URL{
   772  				Path: "/foo",
   773  			},
   774  			CACerts: &cert,
   775  		},
   776  		objects: []runtime.Object{
   777  			getAddressableFromKRef(k8sServiceRef()),
   778  		},
   779  		wantScheme: "https",
   780  		addr:       addressableWithAddresses(),
   781  	}}
   782  
   783  	for n, tc := range tests {
   784  		t.Run(n, func(t *testing.T) {
   785  			ctx, _ := fakedynamicclient.With(context.Background(), scheme.Scheme, tc.objects...)
   786  			ctx = addressable.WithDuck(ctx)
   787  			r := resolver.NewURIResolverFromTracker(ctx, tracker.New(func(types.NamespacedName) {}, 0), tc.customResolvers...)
   788  
   789  			// Run it twice since this should be idempotent. URI Resolver should
   790  			// not modify the cache's copy.
   791  			_, _ = r.AddressableFromDestinationV1(ctx, tc.dest, tc.addr)
   792  			addr, gotErr := r.AddressableFromDestinationV1(ctx, tc.dest, tc.addr)
   793  
   794  			if gotErr != nil {
   795  				if tc.wantErr != "" {
   796  					if got, want := gotErr.Error(), tc.wantErr; got != want {
   797  						t.Errorf("Unexpected error (-want, +got) =\n%s", cmp.Diff(want, got))
   798  					}
   799  				} else {
   800  					t.Error("Unexpected error:", gotErr)
   801  				}
   802  			}
   803  			if got, want := addr.URL.Scheme, tc.wantScheme; got != want {
   804  				t.Errorf("Unexpected object (-want, +got) =\n%s", cmp.Diff(want, got))
   805  			}
   806  		})
   807  	}
   808  }
   809  
   810  func TestAddressableFromDestinationV1CACerts(t *testing.T) {
   811  	certDestination := "CA CERT FOR DESTINATION"
   812  	tests := map[string]struct {
   813  		objects         []runtime.Object
   814  		dest            duckv1.Destination
   815  		addr            *unstructured.Unstructured
   816  		customResolvers []resolver.RefResolverFunc
   817  		wantCert        string
   818  		wantErr         string
   819  	}{"CACerts is set on the target addressable": {
   820  		dest: duckv1.Destination{
   821  			Ref: addressableKnativeRef(),
   822  			URI: &apis.URL{
   823  				Path: "/foo",
   824  			},
   825  		},
   826  		objects: []runtime.Object{
   827  			addressableWithCACert(),
   828  		},
   829  		addr:     addressableWithCACert(),
   830  		wantErr:  fmt.Sprintf("address with name %q not found for %+v", *addressableKnativeRefWithAddress().Address, addressableKnativeRefWithAddress()),
   831  		wantCert: CACert,
   832  	}, "CACerts is not set on the target addressable but it is set on the destination": {
   833  		dest: duckv1.Destination{
   834  			Ref: addressableKnativeRef(),
   835  			URI: &apis.URL{
   836  				Path: "/foo",
   837  			},
   838  			CACerts: &certDestination,
   839  		},
   840  		objects: []runtime.Object{
   841  			addressableWithAddresses(),
   842  		},
   843  		addr:     addressableWithAddresses(),
   844  		wantCert: certDestination,
   845  	}, "CACerts is set on the target addressable and it is set on the destination": {
   846  		dest: duckv1.Destination{
   847  			Ref: addressableKnativeRef(),
   848  			URI: &apis.URL{
   849  				Path: "/foo",
   850  			},
   851  			CACerts: &certDestination,
   852  		},
   853  		objects: []runtime.Object{
   854  			addressableWithCACert(),
   855  		},
   856  		addr:     addressableWithCACert(),
   857  		wantCert: certDestination,
   858  	}}
   859  
   860  	for n, tc := range tests {
   861  		t.Run(n, func(t *testing.T) {
   862  			ctx, _ := fakedynamicclient.With(context.Background(), scheme.Scheme, tc.objects...)
   863  			ctx = addressable.WithDuck(ctx)
   864  			r := resolver.NewURIResolverFromTracker(ctx, tracker.New(func(types.NamespacedName) {}, 0), tc.customResolvers...)
   865  
   866  			// Run it twice since this should be idempotent. URI Resolver should
   867  			// not modify the cache's copy.
   868  			_, _ = r.AddressableFromDestinationV1(ctx, tc.dest, tc.addr)
   869  			addr, gotErr := r.AddressableFromDestinationV1(ctx, tc.dest, tc.addr)
   870  
   871  			if gotErr != nil {
   872  				if tc.wantErr != "" {
   873  					if got, want := gotErr.Error(), tc.wantErr; got != want {
   874  						t.Errorf("Unexpected error (-want, +got) =\n%s", cmp.Diff(want, got))
   875  					}
   876  				} else {
   877  					t.Error("Unexpected error:", gotErr)
   878  				}
   879  			}
   880  			if got, want := *addr.CACerts, tc.wantCert; got != want {
   881  				t.Errorf("Unexpected object (-want, +got) =\n%s", cmp.Diff(want, got))
   882  			}
   883  		})
   884  	}
   885  }
   886  
   887  func TestAddressableFromDestinationV1Audience(t *testing.T) {
   888  	destinationAudience := "destination-audience"
   889  
   890  	tests := map[string]struct {
   891  		objects         []runtime.Object
   892  		dest            duckv1.Destination
   893  		addr            *unstructured.Unstructured
   894  		customResolvers []resolver.RefResolverFunc
   895  		wantAudience    string
   896  		wantErr         string
   897  	}{"Audience is set on destination": {
   898  		dest: duckv1.Destination{
   899  			Ref: addressableKnativeRef(),
   900  			URI: &apis.URL{
   901  				Path: "/foo",
   902  			},
   903  			Audience: &destinationAudience,
   904  		},
   905  		objects: []runtime.Object{
   906  			addressableWithAddresses(),
   907  		},
   908  		addr:         addressableWithAddresses(),
   909  		wantAudience: destinationAudience,
   910  	}, "Audience is set on the target addressable but not set on the destination": {
   911  		dest: duckv1.Destination{
   912  			Ref: addressableKnativeRef(),
   913  			URI: &apis.URL{
   914  				Path: "/foo",
   915  			},
   916  		},
   917  		objects: []runtime.Object{
   918  			addressableWithAudience(),
   919  		},
   920  		addr:         addressableWithAudience(),
   921  		wantAudience: addressableAudience,
   922  	}, "Audience is set on the target addressable and set on the destination (destination should have priority)": {
   923  		dest: duckv1.Destination{
   924  			Ref: addressableKnativeRef(),
   925  			URI: &apis.URL{
   926  				Path: "/foo",
   927  			},
   928  			Audience: &destinationAudience,
   929  		},
   930  		objects: []runtime.Object{
   931  			addressableWithAudience(),
   932  		},
   933  		addr:         addressableWithAudience(),
   934  		wantAudience: destinationAudience,
   935  	}}
   936  
   937  	for n, tc := range tests {
   938  		t.Run(n, func(t *testing.T) {
   939  			ctx, _ := fakedynamicclient.With(context.Background(), scheme.Scheme, tc.objects...)
   940  			ctx = addressable.WithDuck(ctx)
   941  			r := resolver.NewURIResolverFromTracker(ctx, tracker.New(func(types.NamespacedName) {}, 0), tc.customResolvers...)
   942  
   943  			// Run it twice since this should be idempotent. URI Resolver should
   944  			// not modify the cache's copy.
   945  			_, _ = r.AddressableFromDestinationV1(ctx, tc.dest, tc.addr)
   946  			addr, gotErr := r.AddressableFromDestinationV1(ctx, tc.dest, tc.addr)
   947  
   948  			if gotErr != nil {
   949  				if tc.wantErr != "" {
   950  					if got, want := gotErr.Error(), tc.wantErr; got != want {
   951  						t.Errorf("Unexpected error (-want, +got) =\n%s", cmp.Diff(want, got))
   952  					}
   953  				} else {
   954  					t.Error("Unexpected error:", gotErr)
   955  				}
   956  			}
   957  			if got, want := *addr.Audience, tc.wantAudience; got != want {
   958  				t.Errorf("Unexpected object (-want, +got) =\n%s", cmp.Diff(want, got))
   959  			}
   960  		})
   961  	}
   962  }
   963  
   964  func getAddressable() *unstructured.Unstructured {
   965  	return &unstructured.Unstructured{
   966  		Object: map[string]interface{}{
   967  			"apiVersion": addressableAPIVersion,
   968  			"kind":       addressableKind,
   969  			"metadata": map[string]interface{}{
   970  				"namespace": testNS,
   971  				"name":      addressableName,
   972  			},
   973  			"status": map[string]interface{}{
   974  				"address": map[string]interface{}{
   975  					"url": addressableDNS,
   976  				},
   977  			},
   978  		},
   979  	}
   980  }
   981  
   982  func addressableWithPathAndTrailingSlash() *unstructured.Unstructured {
   983  	return &unstructured.Unstructured{
   984  		Object: map[string]interface{}{
   985  			"apiVersion": addressableAPIVersion,
   986  			"kind":       addressableKind,
   987  			"metadata": map[string]interface{}{
   988  				"namespace": testNS,
   989  				"name":      addressableName,
   990  			},
   991  			"status": map[string]interface{}{
   992  				"address": map[string]interface{}{
   993  					"url": addressableDNSWithPathAndTrailingSlash,
   994  				},
   995  			},
   996  		},
   997  	}
   998  }
   999  
  1000  func addressableWithPathAndNoTrailingSlash() *unstructured.Unstructured {
  1001  	return &unstructured.Unstructured{
  1002  		Object: map[string]interface{}{
  1003  			"apiVersion": addressableAPIVersion,
  1004  			"kind":       addressableKind,
  1005  			"metadata": map[string]interface{}{
  1006  				"namespace": testNS,
  1007  				"name":      addressableName,
  1008  			},
  1009  			"status": map[string]interface{}{
  1010  				"address": map[string]interface{}{
  1011  					"url": addressableDNSWithPathAndNoTrailingSlash,
  1012  				},
  1013  			},
  1014  		},
  1015  	}
  1016  }
  1017  
  1018  func addressableNoStatus() *unstructured.Unstructured {
  1019  	return &unstructured.Unstructured{
  1020  		Object: map[string]interface{}{
  1021  			"apiVersion": unaddressableAPIVersion,
  1022  			"kind":       unaddressableKind,
  1023  			"metadata": map[string]interface{}{
  1024  				"namespace": testNS,
  1025  				"name":      unaddressableName,
  1026  			},
  1027  		},
  1028  	}
  1029  }
  1030  
  1031  func addressableNilAddress() *unstructured.Unstructured {
  1032  	return &unstructured.Unstructured{
  1033  		Object: map[string]interface{}{
  1034  			"apiVersion": unaddressableAPIVersion,
  1035  			"kind":       unaddressableKind,
  1036  			"metadata": map[string]interface{}{
  1037  				"namespace": testNS,
  1038  				"name":      unaddressableName,
  1039  			},
  1040  			"status": map[string]interface{}{
  1041  				"address": map[string]interface{}(nil),
  1042  			},
  1043  		},
  1044  	}
  1045  }
  1046  
  1047  func addressableNilURL() *unstructured.Unstructured {
  1048  	return &unstructured.Unstructured{
  1049  		Object: map[string]interface{}{
  1050  			"apiVersion": unaddressableAPIVersion,
  1051  			"kind":       unaddressableKind,
  1052  			"metadata": map[string]interface{}{
  1053  				"namespace": testNS,
  1054  				"name":      unaddressableName,
  1055  			},
  1056  			"status": map[string]interface{}{
  1057  				"address": map[string]interface{}{
  1058  					"url": nil,
  1059  				},
  1060  			},
  1061  		},
  1062  	}
  1063  }
  1064  
  1065  func addressableNoHostURL() *unstructured.Unstructured {
  1066  	return &unstructured.Unstructured{
  1067  		Object: map[string]interface{}{
  1068  			"apiVersion": unaddressableAPIVersion,
  1069  			"kind":       unaddressableKind,
  1070  			"metadata": map[string]interface{}{
  1071  				"namespace": testNS,
  1072  				"name":      unaddressableName,
  1073  			},
  1074  			"status": map[string]interface{}{
  1075  				"address": map[string]interface{}{
  1076  					"url": "http://",
  1077  				},
  1078  			},
  1079  		},
  1080  	}
  1081  }
  1082  
  1083  func invalidObjectRef() *corev1.ObjectReference {
  1084  	return &corev1.ObjectReference{
  1085  		Kind:       addressableKind,
  1086  		Name:       addressableName,
  1087  		APIVersion: addressableAPIVersion,
  1088  		Namespace:  "-bad",
  1089  	}
  1090  }
  1091  
  1092  func k8sServiceRef() *duckv1.KReference {
  1093  	return &duckv1.KReference{
  1094  		Kind:       "Service",
  1095  		Name:       addressableName,
  1096  		APIVersion: "v1",
  1097  		Namespace:  testNS,
  1098  	}
  1099  }
  1100  
  1101  func addressableKnativeRef() *duckv1.KReference {
  1102  	return &duckv1.KReference{
  1103  		Kind:       addressableKind,
  1104  		Name:       addressableName,
  1105  		APIVersion: addressableAPIVersion,
  1106  		Namespace:  testNS,
  1107  	}
  1108  }
  1109  
  1110  func addressableKnativeRefWithAddress() *duckv1.KReference {
  1111  	address := addressableName
  1112  	return &duckv1.KReference{
  1113  		Kind:       addressableKind,
  1114  		Name:       addressableName,
  1115  		APIVersion: addressableAPIVersion,
  1116  		Namespace:  testNS,
  1117  		Address:    &address,
  1118  	}
  1119  }
  1120  
  1121  func addressableRef() *corev1.ObjectReference {
  1122  	return &corev1.ObjectReference{
  1123  		Kind:       addressableKind,
  1124  		Name:       addressableName,
  1125  		APIVersion: addressableAPIVersion,
  1126  		Namespace:  testNS,
  1127  	}
  1128  }
  1129  
  1130  func unaddressableKnativeRef() *duckv1.KReference {
  1131  	return &duckv1.KReference{
  1132  		Kind:       unaddressableKind,
  1133  		Name:       unaddressableName,
  1134  		APIVersion: unaddressableAPIVersion,
  1135  		Namespace:  testNS,
  1136  	}
  1137  }
  1138  
  1139  func unaddressableRef() *corev1.ObjectReference {
  1140  	return &corev1.ObjectReference{
  1141  		Kind:       unaddressableKind,
  1142  		Name:       unaddressableName,
  1143  		APIVersion: unaddressableAPIVersion,
  1144  		Namespace:  testNS,
  1145  	}
  1146  }
  1147  
  1148  func getAddressableFromKRef(ref *duckv1.KReference) *unstructured.Unstructured {
  1149  	return &unstructured.Unstructured{
  1150  		Object: map[string]interface{}{
  1151  			"apiVersion": ref.APIVersion,
  1152  			"kind":       ref.Kind,
  1153  			"metadata": map[string]interface{}{
  1154  				"namespace": ref.Namespace,
  1155  				"name":      ref.Name,
  1156  			},
  1157  			"status": map[string]interface{}{
  1158  				"address": map[string]interface{}{
  1159  					"url":  addressableDNS,
  1160  					"name": addressableDNS,
  1161  				},
  1162  			},
  1163  		},
  1164  	}
  1165  }
  1166  
  1167  func addressableNoAddresses() *unstructured.Unstructured {
  1168  	return &unstructured.Unstructured{
  1169  		Object: map[string]interface{}{
  1170  			"apiVersion": addressableAPIVersion,
  1171  			"kind":       addressableKind,
  1172  			"metadata": map[string]interface{}{
  1173  				"namespace": testNS,
  1174  				"name":      addressableName,
  1175  			},
  1176  			"status": map[string]interface{}{
  1177  				"address":   map[string]interface{}(nil),
  1178  				"addresses": []interface{}{},
  1179  			},
  1180  		},
  1181  	}
  1182  }
  1183  
  1184  func addressableWithAddresses() *unstructured.Unstructured {
  1185  	return &unstructured.Unstructured{
  1186  		Object: map[string]interface{}{
  1187  			"apiVersion": addressableAPIVersion,
  1188  			"kind":       addressableKind,
  1189  			"metadata": map[string]interface{}{
  1190  				"namespace": testNS,
  1191  				"name":      addressableName,
  1192  			},
  1193  			"status": map[string]interface{}{
  1194  				"address": map[string]interface{}{
  1195  					"url":  addressableDNS,
  1196  					"name": addressableName,
  1197  				},
  1198  				"addresses": []interface{}{
  1199  					map[string]interface{}{
  1200  						"url":  addressableDNS,
  1201  						"name": addressableName,
  1202  					}, map[string]interface{}{
  1203  						"url":  addressableDNS1,
  1204  						"name": addressableName1,
  1205  					}, map[string]interface{}{
  1206  						"url":  addressableDNS2,
  1207  						"name": addressableName2,
  1208  					}, map[string]interface{}{
  1209  						"url":  addressableDNS3,
  1210  						"name": addressableName3,
  1211  					},
  1212  				},
  1213  			},
  1214  		},
  1215  	}
  1216  }
  1217  
  1218  func addressableWithAddressOnly() *unstructured.Unstructured {
  1219  	return &unstructured.Unstructured{
  1220  		Object: map[string]interface{}{
  1221  			"apiVersion": addressableAPIVersion,
  1222  			"kind":       addressableKind,
  1223  			"metadata": map[string]interface{}{
  1224  				"namespace": testNS,
  1225  				"name":      addressableName,
  1226  			},
  1227  			"status": map[string]interface{}{
  1228  				"address": map[string]interface{}{
  1229  					"url":  addressableDNS,
  1230  					"name": addressableName,
  1231  				},
  1232  				"addresses": []interface{}{},
  1233  			},
  1234  		},
  1235  	}
  1236  }
  1237  
  1238  func addressableWithDifferentAddresses() *unstructured.Unstructured {
  1239  	return &unstructured.Unstructured{
  1240  		Object: map[string]interface{}{
  1241  			"apiVersion": addressableAPIVersion,
  1242  			"kind":       addressableKind,
  1243  			"metadata": map[string]interface{}{
  1244  				"namespace": testNS,
  1245  				"name":      addressableName,
  1246  			},
  1247  			"status": map[string]interface{}{
  1248  				"address": map[string]interface{}{
  1249  					"url":  addressableDNS,
  1250  					"name": addressableName,
  1251  				},
  1252  				"addresses": []interface{}{
  1253  					map[string]interface{}{
  1254  						"url":  addressableDNS1,
  1255  						"name": addressableName1,
  1256  					}, map[string]interface{}{
  1257  						"url":  addressableDNS2,
  1258  						"name": addressableName2,
  1259  					},
  1260  				},
  1261  			},
  1262  		},
  1263  	}
  1264  }
  1265  
  1266  func addressableWithCACert() *unstructured.Unstructured {
  1267  	return &unstructured.Unstructured{
  1268  		Object: map[string]interface{}{
  1269  			"apiVersion": addressableAPIVersion,
  1270  			"kind":       addressableKind,
  1271  			"metadata": map[string]interface{}{
  1272  				"namespace": testNS,
  1273  				"name":      addressableName,
  1274  			},
  1275  			"status": map[string]interface{}{
  1276  				"address": map[string]interface{}{
  1277  					"url":     addressableDNS,
  1278  					"name":    addressableName,
  1279  					"CACerts": CACert,
  1280  				},
  1281  			},
  1282  		},
  1283  	}
  1284  }
  1285  
  1286  func addressableWithAudience() *unstructured.Unstructured {
  1287  	return &unstructured.Unstructured{
  1288  		Object: map[string]interface{}{
  1289  			"apiVersion": addressableAPIVersion,
  1290  			"kind":       addressableKind,
  1291  			"metadata": map[string]interface{}{
  1292  				"namespace": testNS,
  1293  				"name":      addressableName,
  1294  			},
  1295  			"status": map[string]interface{}{
  1296  				"address": map[string]interface{}{
  1297  					"url":      addressableDNS,
  1298  					"name":     addressableName,
  1299  					"audience": addressableAudience,
  1300  				},
  1301  			},
  1302  		},
  1303  	}
  1304  }
  1305  
  1306  func sampleURIResolver(ctx context.Context, ref *corev1.ObjectReference) (bool, *apis.URL, error) {
  1307  	if ref.Kind == "Service" {
  1308  		parsed, err := apis.ParseURL(fmt.Sprintf("ref://%s.%s.%s", ref.Name, ref.Kind, ref.APIVersion))
  1309  		return true, parsed, err
  1310  	}
  1311  	if ref.Kind == unaddressableKind {
  1312  		return true, nil, errors.New("cannot be referenced")
  1313  	}
  1314  	return false, nil, nil
  1315  }
  1316  
  1317  func noopURIResolver(ctx context.Context, ref *corev1.ObjectReference) (bool, *apis.URL, error) {
  1318  	return false, nil, nil
  1319  }
  1320  
  1321  func addrWithName() *duckv1.Addressable {
  1322  	addrName := addressableName
  1323  	return &duckv1.Addressable{
  1324  		Name: &addrName,
  1325  		URL: &apis.URL{
  1326  			Host:   "addressable.sink.svc.cluster.local",
  1327  			Scheme: "http",
  1328  			Path:   "/foo",
  1329  		},
  1330  	}
  1331  }