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 }