Repository: knative/serving
Pull request #10166 (2020-11-20 07:49:36)

Remove latest_version function
The function is part of the hack repository, see https://github.com/knative/hack/blob/d3cb354f49ffe4a15f1f509413efbd05bfd2ca21/library.sh#L749-L755

Reference: https://github.com/knative/hack/pull/23

<!-- Please include the 'why' behind your changes if no issue exists -->

## Proposed Changes

- Remove latest_version function

/kind cleanup

knative-prow-robot: [APPROVALNOTIFIER] This PR is **NOT APPROVED**

This pull-request has been approved by: *<a href="https://github.com/knative/serving/pull/10166#" title="Author self-approved">pierDipi</a>*
To complete the [pull request process](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process), please assign **vagababov** after the PR has been reviewed.
You can assign the PR to them by writing `/assign @vagababov` in a comment when ready.

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=knative%2Fserving).

<details open>
Needs approval from an approver in each of these files:

- **[test/OWNERS](https://github.com/knative/serving/blob/master/test/OWNERS)**

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":["vagababov"]} -->
codecov[bot]: # [Codecov](https://codecov.io/gh/knative/serving/pull/10166?src=pr&el=h1) Report
> Merging [#10166](https://codecov.io/gh/knative/serving/pull/10166?src=pr&el=desc) (2e251a7) into [master](https://codecov.io/gh/knative/serving/commit/d6dc616ded226eddb0f81397d1abd60dd601e7b3?el=desc) (d6dc616) will **increase** coverage by `0.04%`.
> The diff coverage is `n/a`.

[![Impacted file tree graph](https://codecov.io/gh/knative/serving/pull/10166/graphs/tree.svg?width=650&height=150&src=pr&token=MPpDfAj4Ui)](https://codecov.io/gh/knative/serving/pull/10166?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master   #10166      +/-   ##
==========================================
+ Coverage   88.00%   88.05%   +0.04%     
==========================================
  Files         184      184              
  Lines        8606     8606              
==========================================
+ Hits         7574     7578       +4     
+ Misses        789      786       -3     
+ Partials      243      242       -1     
```


| [Impacted Files](https://codecov.io/gh/knative/serving/pull/10166?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [pkg/activator/net/revision\_backends.go](https://codecov.io/gh/knative/serving/pull/10166/diff?src=pr&el=tree#diff-cGtnL2FjdGl2YXRvci9uZXQvcmV2aXNpb25fYmFja2VuZHMuZ28=) | `91.40% <0.00%> (+0.90%)` | :arrow_up: |
| [pkg/autoscaler/statforwarder/forwarder.go](https://codecov.io/gh/knative/serving/pull/10166/diff?src=pr&el=tree#diff-cGtnL2F1dG9zY2FsZXIvc3RhdGZvcndhcmRlci9mb3J3YXJkZXIuZ28=) | `82.44% <0.00%> (+1.06%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/knative/serving/pull/10166?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/knative/serving/pull/10166?src=pr&el=footer). Last update [d6dc616...2e251a7](https://codecov.io/gh/knative/serving/pull/10166?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

knative-prow-robot: @pierDipi: The following test **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-knative-serving-istio-stable-no-mesh-tls | 2e251a7b23043511c7c4ae3d89653185dde3aa03 | [link](https://prow.knative.dev/view/gs/knative-prow/pr-logs/pull/knative_serving/10166/pull-knative-serving-istio-stable-no-mesh-tls/1329693387154001920) | `/test pull-knative-serving-istio-stable-no-mesh-tls`

[Full PR test history](https://gubernator.knative.dev/pr/knative_serving/10166). [Your PR dashboard](https://gubernator.knative.dev/pr/pierDipi).

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
pierDipi: /retest
knative-prow-robot: @pierDipi: The following test **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-knative-serving-istio-stable-no-mesh-tls | 2e251a7b23043511c7c4ae3d89653185dde3aa03 | [link](https://prow.knative.dev/view/gs/knative-prow/pr-logs/pull/knative_serving/10166/pull-knative-serving-istio-stable-no-mesh-tls/1329722648824909824) | `/test pull-knative-serving-istio-stable-no-mesh-tls`

[Full PR test history](https://gubernator.knative.dev/pr/knative_serving/10166). [Your PR dashboard](https://gubernator.knative.dev/pr/pierDipi).

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
pierDipi: /retest

Patch:
diff --git a/cmd/queue/main.go b/cmd/queue/main.go
index d6bc76446..0c988ce97 100644
--- a/cmd/queue/main.go
+++ b/cmd/queue/main.go
@@ -70,8 +70,8 @@ var (
 
 type config struct {
 	ContainerConcurrency   int    `split_words:"true" required:"true"`
-	QueueServingPort       int    `split_words:"true" required:"true"`
-	UserPort               int    `split_words:"true" required:"true"`
+	QueueServingPort       string `split_words:"true" required:"true"`
+	UserPort               string `split_words:"true" required:"true"`
 	RevisionTimeoutSeconds int    `split_words:"true" required:"true"`
 	ServingReadinessProbe  string `split_words:"true" required:"true"`
 	EnableProfiling        bool   `split_words:"true"` // optional
@@ -268,7 +268,7 @@ func buildServer(ctx context.Context, env config, healthState *health.State, rp
 	logger *zap.SugaredLogger) *http.Server {
 	target := &url.URL{
 		Scheme: "http",
-		Host:   net.JoinHostPort("127.0.0.1", strconv.Itoa(env.UserPort)),
+		Host:   net.JoinHostPort("127.0.0.1", env.UserPort),
 	}
 
 	maxIdleConns := 1000 // TODO: somewhat arbitrary value for CC=0, needs experimental validation.
@@ -309,7 +309,7 @@ func buildServer(ctx context.Context, env config, healthState *health.State, rp
 	// logs. Hence we need to have RequestLogHandler to be the first one.
 	composedHandler = pushRequestLogHandler(logger, composedHandler, env)
 
-	return pkgnet.NewServer(":"+strconv.Itoa(env.QueueServingPort), composedHandler)
+	return pkgnet.NewServer(":"+env.QueueServingPort, composedHandler)
 }
 
 func buildTransport(env config, logger *zap.SugaredLogger, maxConns int) http.RoundTripper {
@@ -342,10 +342,13 @@ func buildBreaker(logger *zap.SugaredLogger, env config) *queue.Breaker {
 
 	// We set the queue depth to be equal to the container concurrency * 10 to
 	// allow the autoscaler time to react.
-	queueDepth := env.ContainerConcurrency * 10
-	params := queue.BreakerParams{QueueDepth: queueDepth, MaxConcurrency: env.ContainerConcurrency, InitialCapacity: env.ContainerConcurrency}
-	logger.Infof("Queue container is starting with %#v", params)
-
+	queueDepth := 10 * env.ContainerConcurrency
+	params := queue.BreakerParams{
+		QueueDepth:      queueDepth,
+		MaxConcurrency:  env.ContainerConcurrency,
+		InitialCapacity: env.ContainerConcurrency,
+	}
+	logger.Infof("Queue container is starting with BreakerParams = %#v", params)
 	return queue.NewBreaker(params)
 }
 
diff --git a/go.mod b/go.mod
index 990ab8ae3..b519f4026 100644
--- a/go.mod
+++ b/go.mod
@@ -34,8 +34,8 @@ require (
 	k8s.io/client-go v0.18.12
 	k8s.io/code-generator v0.18.12
 	k8s.io/kube-openapi v0.0.0-20200410145947-bcb3869e6f29
-	knative.dev/caching v0.0.0-20201119021451-514d4f69f7bc
-	knative.dev/hack v0.0.0-20201119025252-d3cb354f49ff
-	knative.dev/networking v0.0.0-20201119023952-faeea4d06427
-	knative.dev/pkg v0.0.0-20201119021551-260026d54739
+	knative.dev/caching v0.0.0-20201125150135-91fb5833c3c6
+	knative.dev/hack v0.0.0-20201125230335-c46a6498e9ed
+	knative.dev/networking v0.0.0-20201125133435-4b21f11ccfa7
+	knative.dev/pkg v0.0.0-20201125095035-9bf616d2f46a
 )
diff --git a/go.sum b/go.sum
index 5bf021a22..530275691 100644
--- a/go.sum
+++ b/go.sum
@@ -1214,20 +1214,16 @@ k8s.io/legacy-cloud-providers v0.18.8/go.mod h1:tgp4xYf6lvjrWnjQwTOPvWQE9IVqSBGP
 k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
 k8s.io/utils v0.0.0-20200603063816-c1c6865ac451 h1:v8ud2Up6QK1lNOKFgiIVrZdMg7MpmSnvtrOieolJKoE=
 k8s.io/utils v0.0.0-20200603063816-c1c6865ac451/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
-knative.dev/caching v0.0.0-20201119021451-514d4f69f7bc h1:ZuSbgFDDtVfgAaio8UPz4MU2aZIeCzFkpHldItplX+c=
-knative.dev/caching v0.0.0-20201119021451-514d4f69f7bc/go.mod h1:sYIq8F/G828PcuMGz6+VxU8oCBhhz2RBRl1oWGDHXSI=
-knative.dev/hack v0.0.0-20201112185459-01a34c573bd8 h1:RNbZsAjhswBPtl4C5C5gEFX5/GfWIOZQxfYD9DhkHdY=
-knative.dev/hack v0.0.0-20201112185459-01a34c573bd8/go.mod h1:PHt8x8yX5Z9pPquBEfIj0X66f8iWkWfR0S/sarACJrI=
-knative.dev/hack v0.0.0-20201118155651-b31d3bb6bff9 h1:OgYL1cATsWTS6kztSOuQqhmYfcn6ZdpPAQQ6TKCx00I=
-knative.dev/hack v0.0.0-20201118155651-b31d3bb6bff9/go.mod h1:PHt8x8yX5Z9pPquBEfIj0X66f8iWkWfR0S/sarACJrI=
-knative.dev/hack v0.0.0-20201119025252-d3cb354f49ff h1:+bdPPtgog4EAuibiiW1uMdWX2DVij0+elXSh+Yfey78=
-knative.dev/hack v0.0.0-20201119025252-d3cb354f49ff/go.mod h1:PHt8x8yX5Z9pPquBEfIj0X66f8iWkWfR0S/sarACJrI=
-knative.dev/networking v0.0.0-20201119023952-faeea4d06427 h1:JHpzPRDnADEo32O/0oHn/vMQMbK55qAVCzDmFw3g7xM=
-knative.dev/networking v0.0.0-20201119023952-faeea4d06427/go.mod h1:kUYwYHjpttuBQOy/NFELDC047Phehof+m2aU0C3k7u8=
-knative.dev/pkg v0.0.0-20201117221452-0fccc54273ed h1:4LNEFhvD2Ya4WgCD3SC1WGXz81bjEvQgbcpe5XACI3I=
-knative.dev/pkg v0.0.0-20201117221452-0fccc54273ed/go.mod h1:nxlh3CUvx6WBPr1WKD96AHxFZPD2UKRDo9RUp8ILTyQ=
-knative.dev/pkg v0.0.0-20201119021551-260026d54739 h1:23XBvGmbprZ86TY9HJQmO7ZKp/te3LzJdKeVX7o9TAw=
-knative.dev/pkg v0.0.0-20201119021551-260026d54739/go.mod h1:3Udj7GogdjFg0M05MJm+aJjHx1BK/tyQarl5RB2k0Xo=
+knative.dev/caching v0.0.0-20201125150135-91fb5833c3c6 h1:W1R7UnGSGJmL6btl8AY8AVCT2cEwgHzRtlort7icB5M=
+knative.dev/caching v0.0.0-20201125150135-91fb5833c3c6/go.mod h1:IocU4F1XK8udXpTRC4m9KWyEVtT928sSP+T7Oy34UDg=
+knative.dev/hack v0.0.0-20201120192952-353db687ec5b h1:Lc+AKgwhAZUD98mN++qTHeeaP6FRmS8fcwc/rXkP8G0=
+knative.dev/hack v0.0.0-20201120192952-353db687ec5b/go.mod h1:PHt8x8yX5Z9pPquBEfIj0X66f8iWkWfR0S/sarACJrI=
+knative.dev/hack v0.0.0-20201125230335-c46a6498e9ed h1:DrTU+vxQrNJtySxyNovUtl4si0ozjtU/AYhYaTz34YA=
+knative.dev/hack v0.0.0-20201125230335-c46a6498e9ed/go.mod h1:PHt8x8yX5Z9pPquBEfIj0X66f8iWkWfR0S/sarACJrI=
+knative.dev/networking v0.0.0-20201125133435-4b21f11ccfa7 h1:O40i4ZCYfpaw7m1yUwtmRhBOdT0HRp3MYD4PWaRzYqI=
+knative.dev/networking v0.0.0-20201125133435-4b21f11ccfa7/go.mod h1:EpImbpW3gu85Mg39GT7gUJTVYLtFYWDsZQCZlKFmGUM=
+knative.dev/pkg v0.0.0-20201125095035-9bf616d2f46a h1:pdJpLaq50mLKrPWYSQgTH2p64Dk7Fq/xID6l0F69cVY=
+knative.dev/pkg v0.0.0-20201125095035-9bf616d2f46a/go.mod h1:wXZqP8MXCxb51yNFlecA13BwG7Hk370SWDFWV4dx4ug=
 modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw=
 modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk=
 modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k=
diff --git a/pkg/autoscaler/statserver/server.go b/pkg/autoscaler/statserver/server.go
index 8ce7db577..20774efc9 100644
--- a/pkg/autoscaler/statserver/server.go
+++ b/pkg/autoscaler/statserver/server.go
@@ -17,9 +17,7 @@ limitations under the License.
 package statserver
 
 import (
-	"bytes"
 	"context"
-	"encoding/json"
 	"errors"
 	"net"
 	"net/http"
@@ -175,8 +173,6 @@ func (s *Server) Handler(w http.ResponseWriter, r *http.Request) {
 			return
 		}
 
-		// We accept either protobuf-encoded or JSON-encoded messages depending on the
-		// message type to ensure safe upgrades.
 		switch messageType {
 		case websocket.BinaryMessage:
 			var wsms metrics.WireStatMessages
@@ -195,16 +191,6 @@ func (s *Server) Handler(w http.ResponseWriter, r *http.Request) {
 				s.logger.Debugf("Received stat message: %+v", sm)
 				s.statsCh <- sm
 			}
-		case websocket.TextMessage:
-			dec := json.NewDecoder(bytes.NewBuffer(msg))
-			var sm metrics.StatMessage
-			if err = dec.Decode(&sm); err != nil {
-				s.logger.Errorw("Failed to decode json", zap.Error(err))
-				continue
-			}
-
-			s.logger.Debugf("Received stat message: %+v", sm)
-			s.statsCh <- sm
 		default:
 			s.logger.Error("Dropping unknown message type.")
 			continue
diff --git a/pkg/client/injection/client/client.go b/pkg/client/injection/client/client.go
index a20bf9744..888c3c935 100644
--- a/pkg/client/injection/client/client.go
+++ b/pkg/client/injection/client/client.go
@@ -42,8 +42,13 @@ func withClient(ctx context.Context, cfg *rest.Config) context.Context {
 func Get(ctx context.Context) versioned.Interface {
 	untyped := ctx.Value(Key{})
 	if untyped == nil {
-		logging.FromContext(ctx).Panic(
-			"Unable to fetch knative.dev/serving/pkg/client/clientset/versioned.Interface from context.")
+		if injection.GetConfig(ctx) == nil {
+			logging.FromContext(ctx).Panic(
+				"Unable to fetch knative.dev/serving/pkg/client/clientset/versioned.Interface from context. This context is not the application context (which is typically given to constructors via sharedmain).")
+		} else {
+			logging.FromContext(ctx).Panic(
+				"Unable to fetch knative.dev/serving/pkg/client/clientset/versioned.Interface from context.")
+		}
 	}
 	return untyped.(versioned.Interface)
 }
diff --git a/pkg/networking/constants.go b/pkg/networking/constants.go
index 8e9f47a0d..e85118bf9 100644
--- a/pkg/networking/constants.go
+++ b/pkg/networking/constants.go
@@ -20,10 +20,10 @@ import "knative.dev/networking/pkg/apis/networking"
 
 // The ports we setup on our services.
 const (
-	// BackendHTTPPort is the backend, i.e. `targetPort` that we setup for HTTP services.
+	// BackendHTTPPort is the backend, i.e. `targetPort` that we setup for HTTP/1 services.
 	BackendHTTPPort = 8012
 
-	// BackendHTTP2Port is the backend, i.e. `targetPort` that we setup for HTTP services.
+	// BackendHTTP2Port is the backend, i.e. `targetPort` that we setup for HTTP/2 services.
 	BackendHTTP2Port = 8013
 
 	// QueueAdminPort specifies the port number for
diff --git a/pkg/queue/breaker.go b/pkg/queue/breaker.go
index c81efc296..0d89e6572 100644
--- a/pkg/queue/breaker.go
+++ b/pkg/queue/breaker.go
@@ -238,13 +238,13 @@ func (s *semaphore) acquire(ctx context.Context) error {
 // release releases capacity in the semaphore.
 // If the semaphore capacity was reduced in between and as a result inFlight is greater
 // than capacity, we don't wake up goroutines as they'd not get any capacity anyway.
-func (s *semaphore) release() error {
+func (s *semaphore) release() {
 	for {
 		old := s.state.Load()
 		capacity, in := unpack(old)
 
 		if in == 0 {
-			return ErrRelease
+			panic("release and acquire are not paired")
 		}
 
 		in--
@@ -260,7 +260,7 @@ func (s *semaphore) release() error {
 					// can take, which is guaranteed to be enough.
 				}
 			}
-			return nil
+			return
 		}
 	}
 }
diff --git a/pkg/reconciler/domainmapping/controller.go b/pkg/reconciler/domainmapping/controller.go
index b5808d056..45005a296 100644
--- a/pkg/reconciler/domainmapping/controller.go
+++ b/pkg/reconciler/domainmapping/controller.go
@@ -26,6 +26,7 @@ import (
 	"knative.dev/pkg/configmap"
 	"knative.dev/pkg/controller"
 	"knative.dev/pkg/logging"
+	"knative.dev/pkg/resolver"
 	"knative.dev/serving/pkg/apis/serving/v1alpha1"
 	"knative.dev/serving/pkg/client/injection/informers/serving/v1alpha1/domainmapping"
 	kindreconciler "knative.dev/serving/pkg/client/injection/reconciler/serving/v1alpha1/domainmapping"
@@ -64,5 +65,7 @@ func NewController(ctx context.Context, cmw configmap.Watcher) *controller.Impl
 	}
 	ingressInformer.Informer().AddEventHandler(handleControllerOf)
 
+	r.resolver = resolver.NewURIResolver(ctx, impl.EnqueueKey)
+
 	return impl
 }
diff --git a/pkg/reconciler/domainmapping/reconciler.go b/pkg/reconciler/domainmapping/reconciler.go
index 58888fb2b..a76d05fe9 100644
--- a/pkg/reconciler/domainmapping/reconciler.go
+++ b/pkg/reconciler/domainmapping/reconciler.go
@@ -19,6 +19,7 @@ package domainmapping
 import (
 	"context"
 	"fmt"
+	"strings"
 
 	corev1 "k8s.io/api/core/v1"
 	"k8s.io/apimachinery/pkg/api/equality"
@@ -33,7 +34,9 @@ import (
 	duckv1 "knative.dev/pkg/apis/duck/v1"
 	"knative.dev/pkg/controller"
 	"knative.dev/pkg/logging"
+	"knative.dev/pkg/network"
 	"knative.dev/pkg/reconciler"
+	"knative.dev/pkg/resolver"
 	"knative.dev/serving/pkg/apis/serving/v1alpha1"
 	domainmappingreconciler "knative.dev/serving/pkg/client/injection/reconciler/serving/v1alpha1/domainmapping"
 	"knative.dev/serving/pkg/reconciler/domainmapping/config"
@@ -44,6 +47,7 @@ import (
 type Reconciler struct {
 	ingressLister networkinglisters.IngressLister
 	netclient     netclientset.Interface
+	resolver      *resolver.URIResolver
 }
 
 // Check that our Reconciler implements Interface
@@ -79,13 +83,15 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, dm *v1alpha1.DomainMappi
 		return err
 	}
 
-	// Since we currently assume all DomainMapping References are KServices we
-	// don't do any resolution yet, so we'll just immediately mark the condition.
-	dm.Status.MarkReferenceResolved()
+	// Resolve the spec.Ref to a URI following the Addressable contract.
+	targetHost, targetBackendSvc, err := r.resolveRef(ctx, dm)
+	if err != nil {
+		return err
+	}
 
 	// Reconcile the Ingress resource corresponding to the requested Mapping.
-	logger.Debugf("Mapping %s to %s/%s", url, dm.Spec.Ref.Namespace, dm.Spec.Ref.Name)
-	desired := resources.MakeIngress(dm, ingressClass)
+	logger.Debugf("Mapping %s to ref %s/%s (host: %q, svc: %q)", url, dm.Spec.Ref.Namespace, dm.Spec.Ref.Name, targetHost, targetBackendSvc)
+	desired := resources.MakeIngress(dm, targetBackendSvc, targetHost, ingressClass)
 	ingress, err := r.reconcileIngress(ctx, dm, desired)
 	if err != nil {
 		return err
@@ -132,6 +138,45 @@ func (r *Reconciler) reconcileIngress(ctx context.Context, dm *v1alpha1.DomainMa
 	return ingress, err
 }
 
+func (r *Reconciler) resolveRef(ctx context.Context, dm *v1alpha1.DomainMapping) (host, backendSvc string, err error) {
+	resolved, err := r.resolver.URIFromKReference(ctx, &dm.Spec.Ref, dm)
+	if err != nil {
+		dm.Status.MarkReferenceNotResolved(err.Error())
+		return "", "", fmt.Errorf("resolving reference: %w", err)
+	}
+
+	// Since we do not support path-based routing in domain mappings, we cannot
+	// support target references that contain a path.
+	if resolved.Path != "" {
+		dm.Status.MarkReferenceNotResolved(fmt.Sprintf("resolved URI %q contains a path", resolved))
+		return "", "", fmt.Errorf("resolved URI %q contains a path", resolved)
+	}
+
+	// The resolved hostname must be of the form {name}.{namespace}.svc.{suffix},
+	// which is the standard DNS address given by kubernetes to services. We will
+	// use `name` from this resolved hostname to determine the backend service
+	// name for the KIngress.
+	// TODO(julz) in the future we may support addressables that are not created
+	// from Services, in which case we would need to dynamically create the
+	// an ExternalName Service for the KIngress to use.
+	requiredSuffix := ".svc." + network.GetClusterDomainName()
+	parts := strings.Split(strings.TrimSuffix(resolved.Host, requiredSuffix), ".")
+	if !strings.HasSuffix(resolved.Host, requiredSuffix) || len(parts) != 2 {
+		dm.Status.MarkReferenceNotResolved(fmt.Sprintf("resolved URI %q must be of the form {name}.{namespace}%s", resolved, requiredSuffix))
+		return "", "", fmt.Errorf("resolved URI %q must be of the form {name}.{namespace}%s", resolved, requiredSuffix)
+	}
+
+	// If the namespace part of the target isn't the same as the DomainMapping
+	// we'd need to create a cross-namespace KIngress, which isn't supported.
+	if parts[1] != dm.Namespace {
+		dm.Status.MarkReferenceNotResolved(fmt.Sprintf("resolved URI %q must be in same namespace as DomainMapping", resolved))
+		return "", "", fmt.Errorf("resolved URI %q must be in same namespace as DomainMapping", resolved)
+	}
+
+	dm.Status.MarkReferenceResolved()
+	return resolved.Host, parts[0], nil
+}
+
 func (r *Reconciler) reconcileDomainClaim(ctx context.Context, dm *v1alpha1.DomainMapping) error {
 	dc, err := r.netclient.NetworkingV1alpha1().ClusterDomainClaims().Get(ctx, dm.Name, metav1.GetOptions{})
 	if apierrs.IsNotFound(err) {
diff --git a/pkg/reconciler/domainmapping/resources/ingress.go b/pkg/reconciler/domainmapping/resources/ingress.go
index 0bc99491e..99411dc59 100644
--- a/pkg/reconciler/domainmapping/resources/ingress.go
+++ b/pkg/reconciler/domainmapping/resources/ingress.go
@@ -25,22 +25,15 @@ import (
 	"knative.dev/networking/pkg/apis/networking"
 	netv1alpha1 "knative.dev/networking/pkg/apis/networking/v1alpha1"
 	"knative.dev/pkg/kmeta"
-	pkgnetwork "knative.dev/pkg/network"
 	servingv1alpha1 "knative.dev/serving/pkg/apis/serving/v1alpha1"
 )
 
-// MakeIngress creates an Ingress object for a DomainMapping.
-func MakeIngress(dm *servingv1alpha1.DomainMapping, ingressClass string) *netv1alpha1.Ingress {
-	var (
-		targetServiceName      = dm.Spec.Ref.Name
-		targetServiceNamespace = dm.Spec.Ref.Namespace
-	)
-
-	// This assumes the target is a KSvc. To support arbitrary addressables
-	// we will need to resolve the reference to a URL in the same way that
-	// eventing does.
-	targetHostName := pkgnetwork.GetServiceHostname(targetServiceName, targetServiceNamespace)
-
+// MakeIngress creates an Ingress object for a DomainMapping.  The Ingress is
+// always created in the same namespace as the DomainMapping, and the ingress
+// backend is always in the same namespace also (as this is required by
+// KIngress).  The created ingress will contain a RewriteHost rule to cause the
+// given hostName to be used as the host.
+func MakeIngress(dm *servingv1alpha1.DomainMapping, backendServiceName, hostName, ingressClass string) *netv1alpha1.Ingress {
 	return &netv1alpha1.Ingress{
 		ObjectMeta: metav1.ObjectMeta{
 			Name:      kmeta.ChildName(dm.GetName(), ""),
@@ -58,15 +51,15 @@ func MakeIngress(dm *servingv1alpha1.DomainMapping, ingressClass string) *netv1a
 				Visibility: netv1alpha1.IngressVisibilityExternalIP,
 				HTTP: &netv1alpha1.HTTPIngressRuleValue{
 					Paths: []netv1alpha1.HTTPIngressPath{{
-						RewriteHost: targetHostName,
+						RewriteHost: hostName,
 						Splits: []netv1alpha1.IngressBackendSplit{{
 							Percent: 100,
 							AppendHeaders: map[string]string{
 								network.OriginalHostHeader: dm.Name,
 							},
 							IngressBackend: netv1alpha1.IngressBackend{
-								ServiceName:      targetServiceName,
-								ServiceNamespace: targetServiceNamespace,
+								ServiceNamespace: dm.Namespace,
+								ServiceName:      backendServiceName,
 								ServicePort:      intstr.FromInt(80),
 							},
 						}},
diff --git a/pkg/reconciler/route/traffic/rollout.go b/pkg/reconciler/route/traffic/rollout.go
index 2d9450c99..1c790481e 100644
--- a/pkg/reconciler/route/traffic/rollout.go
+++ b/pkg/reconciler/route/traffic/rollout.go
@@ -60,6 +60,11 @@ type ConfigurationRollout struct {
 	// the Rollout shoud be complete.
 	Deadline int `json:"deadline,omitempty"`
 
+	// StartTime is the Unix timestamp by when (+/- reconcile precision)
+	// the Rollout has started.
+	// This is required to compute step time and deadline.
+	StartTime int `json:"starttime,omitempty"`
+
 	// LastStepTimeStamp is the Unix timestamp when the last
 	// rollout step was performed.
 	LastStepTime int `json:"lastStep,omitempty"`
@@ -80,6 +85,13 @@ type RevisionRollout struct {
 	Percent int `json:"percent"`
 }
 
+// Done returns true if there is no active rollout going on
+// for the configuration.
+func (cr *ConfigurationRollout) Done() bool {
+	// Zero or just one revision.
+	return len(cr.Revisions) < 2
+}
+
 // Validate validates current rollout for inconsistencies.
 // This is expected to be invoked after annotation deserialization.
 // If it returns false — the deserialized object should be discarded.
@@ -185,6 +197,8 @@ func (cur *Rollout) Step(prev *Rollout) *Rollout {
 // the older revisions.
 func adjustPercentage(goal int, cr *ConfigurationRollout) {
 	switch diff := goal - cr.Percent; {
+	case goal == 0:
+		cr.Revisions = nil // No traffic, no rollout.
 	case diff > 0:
 		cr.Revisions[len(cr.Revisions)-1].Percent += diff
 	case diff < 0:
@@ -213,6 +227,9 @@ func stepConfig(goal, prev *ConfigurationRollout) *ConfigurationRollout {
 		Tag:               goal.Tag,
 		Percent:           goal.Percent,
 		Revisions:         goal.Revisions,
+
+		// If there is a new revision, then timing information should be reset.
+		// So leave them empty here and populate below, if necessary.
 	}
 
 	if len(prev.Revisions) > 0 {
@@ -222,10 +239,17 @@ func stepConfig(goal, prev *ConfigurationRollout) *ConfigurationRollout {
 	// If it matches the last revision of the previous rollout state (or there were no revisions)
 	// then no new rollout has begun for this configuration.
 	if len(prev.Revisions) == 0 || goal.Revisions[0].RevisionName == prev.Revisions[pc-1].RevisionName {
-		// TODO(vagababov): here would go the logic to compute new percentages for the rollout,
-		// i.e step function, so return value will change, depending on that.
 		if len(prev.Revisions) > 0 {
 			ret.Revisions = prev.Revisions
+
+			// TODO(vagababov): here would go the logic to compute new percentages for the rollout,
+			// i.e step function, so return value will change, depending on that.
+			// Copy the duration info from the previous when no new revision
+			// has been created.
+			ret.Deadline = prev.Deadline
+			ret.LastStepTime = prev.LastStepTime
+			ret.StepDuration = prev.StepDuration
+			ret.StartTime = prev.StartTime
 		}
 		return ret
 	}
diff --git a/pkg/reconciler/service/resources/configuration.go b/pkg/reconciler/service/resources/configuration.go
index 6e5920765..ba9d8864f 100644
--- a/pkg/reconciler/service/resources/configuration.go
+++ b/pkg/reconciler/service/resources/configuration.go
@@ -30,12 +30,12 @@ import (
 )
 
 // MakeConfiguration creates a Configuration from a Service object.
-func MakeConfiguration(service *v1.Service) (*v1.Configuration, error) {
+func MakeConfiguration(service *v1.Service) *v1.Configuration {
 	return MakeConfigurationFromExisting(service, &v1.Configuration{})
 }
 
 // MakeConfigurationFromExisting creates a Configuration from a Service object given an existing Configuration.
-func MakeConfigurationFromExisting(service *v1.Service, existing *v1.Configuration) (*v1.Configuration, error) {
+func MakeConfigurationFromExisting(service *v1.Service, existing *v1.Configuration) *v1.Configuration {
 	labels := map[string]string{serving.ServiceLabelKey: service.Name}
 	anns := kmeta.FilterMap(service.GetAnnotations(), func(key string) bool {
 		return key == corev1.LastAppliedConfigAnnotation
@@ -43,9 +43,7 @@ func MakeConfigurationFromExisting(service *v1.Service, existing *v1.Configurati
 
 	routeName := names.Route(service)
 	set := labelerv2.GetListAnnValue(existing.Annotations, serving.RoutesAnnotationKey)
-	if !set.Has(routeName) {
-		set.Insert(routeName)
-	}
+	set.Insert(routeName)
 	anns[serving.RoutesAnnotationKey] = strings.Join(set.UnsortedList(), ",")
 
 	return &v1.Configuration{
@@ -59,5 +57,5 @@ func MakeConfigurationFromExisting(service *v1.Service, existing *v1.Configurati
 			Annotations: anns,
 		},
 		Spec: service.Spec.ConfigurationSpec,
-	}, nil
+	}
 }
diff --git a/pkg/reconciler/service/resources/route.go b/pkg/reconciler/service/resources/route.go
index c6f764fa1..0d67f3576 100644
--- a/pkg/reconciler/service/resources/route.go
+++ b/pkg/reconciler/service/resources/route.go
@@ -27,7 +27,7 @@ import (
 )
 
 // MakeRoute creates a Route from a Service object.
-func MakeRoute(service *v1.Service) (*v1.Route, error) {
+func MakeRoute(service *v1.Service) *v1.Route {
 	c := &v1.Route{
 		ObjectMeta: metav1.ObjectMeta{
 			Name:      names.Route(service),
@@ -54,5 +54,5 @@ func MakeRoute(service *v1.Service) (*v1.Route, error) {
 		}
 	}
 
-	return c, nil
+	return c
 }
diff --git a/pkg/reconciler/service/service.go b/pkg/reconciler/service/service.go
index ca360ce91..e03e3e826 100644
--- a/pkg/reconciler/service/service.go
+++ b/pkg/reconciler/service/service.go
@@ -184,18 +184,15 @@ func (c *Reconciler) checkRoutesNotReady(config *v1.Configuration, logger *zap.S
 }
 
 func (c *Reconciler) createConfiguration(ctx context.Context, service *v1.Service) (*v1.Configuration, error) {
-	cfg, err := resources.MakeConfiguration(service)
-	if err != nil {
-		return nil, err
-	}
-	return c.client.ServingV1().Configurations(service.Namespace).Create(ctx, cfg, metav1.CreateOptions{})
+	return c.client.ServingV1().Configurations(service.Namespace).Create(
+		ctx, resources.MakeConfiguration(service), metav1.CreateOptions{})
 }
 
 func configSemanticEquals(ctx context.Context, desiredConfig, config *v1.Configuration) (bool, error) {
 	logger := logging.FromContext(ctx)
 	specDiff, err := kmp.SafeDiff(desiredConfig.Spec, config.Spec)
 	if err != nil {
-		logger.Errorw("Error diffing config spec", zap.Error(err))
+		logger.Warnw("Error diffing config spec", zap.Error(err))
 		return false, fmt.Errorf("failed to diff Configuration: %w", err)
 	} else if specDiff != "" {
 		logger.Info("Reconciling configuration diff (-desired, +observed):\n", specDiff)
@@ -212,14 +209,13 @@ func (c *Reconciler) reconcileConfiguration(ctx context.Context, service *v1.Ser
 	// We are setting the up-to-date default values here so an update won't be triggered if the only
 	// diff is the new default values.
 	existing.SetDefaults(ctx)
-	desiredConfig, err := resources.MakeConfigurationFromExisting(service, existing)
+
+	desiredConfig := resources.MakeConfigurationFromExisting(service, existing)
+	equals, err := configSemanticEquals(ctx, desiredConfig, existing)
 	if err != nil {
 		return nil, err
 	}
-
-	if equals, err := configSemanticEquals(ctx, desiredConfig, existing); err != nil {
-		return nil, err
-	} else if equals {
+	if equals {
 		return config, nil
 	}
 
@@ -234,14 +230,8 @@ func (c *Reconciler) reconcileConfiguration(ctx context.Context, service *v1.Ser
 }
 
 func (c *Reconciler) createRoute(ctx context.Context, service *v1.Service) (*v1.Route, error) {
-	route, err := resources.MakeRoute(service)
-	if err != nil {
-		// This should be unreachable as configuration creation
-		// happens first in `reconcile()` and it verifies the edge cases
-		// that would make `MakeRoute` fail as well.
-		return nil, err
-	}
-	return c.client.ServingV1().Routes(service.Namespace).Create(ctx, route, metav1.CreateOptions{})
+	return c.client.ServingV1().Routes(service.Namespace).Create(
+		ctx, resources.MakeRoute(service), metav1.CreateOptions{})
 }
 
 func routeSemanticEquals(ctx context.Context, desiredRoute, route *v1.Route) (bool, error) {
@@ -265,17 +255,12 @@ func (c *Reconciler) reconcileRoute(ctx context.Context, service *v1.Service, ro
 	// We are setting the up-to-date default values here so an update won't be triggered if the only
 	// diff is the new default values.
 	existing.SetDefaults(ctx)
-	desiredRoute, err := resources.MakeRoute(service)
+	desiredRoute := resources.MakeRoute(service)
+	equals, err := routeSemanticEquals(ctx, desiredRoute, existing)
 	if err != nil {
-		// This should be unreachable as configuration creation
-		// happens first in `reconcile()` and it verifies the edge cases
-		// that would make `MakeRoute` fail as well.
 		return nil, err
 	}
-
-	if equals, err := routeSemanticEquals(ctx, desiredRoute, existing); err != nil {
-		return nil, err
-	} else if equals {
+	if equals {
 		return route, nil
 	}
 
diff --git a/vendor/knative.dev/caching/pkg/client/injection/client/client.go b/vendor/knative.dev/caching/pkg/client/injection/client/client.go
index 96d0def9b..964b92eaf 100644
--- a/vendor/knative.dev/caching/pkg/client/injection/client/client.go
+++ b/vendor/knative.dev/caching/pkg/client/injection/client/client.go
@@ -42,8 +42,13 @@ func withClient(ctx context.Context, cfg *rest.Config) context.Context {
 func Get(ctx context.Context) versioned.Interface {
 	untyped := ctx.Value(Key{})
 	if untyped == nil {
-		logging.FromContext(ctx).Panic(
-			"Unable to fetch knative.dev/caching/pkg/client/clientset/versioned.Interface from context.")
+		if injection.GetConfig(ctx) == nil {
+			logging.FromContext(ctx).Panic(
+				"Unable to fetch knative.dev/caching/pkg/client/clientset/versioned.Interface from context. This context is not the application context (which is typically given to constructors via sharedmain).")
+		} else {
+			logging.FromContext(ctx).Panic(
+				"Unable to fetch knative.dev/caching/pkg/client/clientset/versioned.Interface from context.")
+		}
 	}
 	return untyped.(versioned.Interface)
 }
diff --git a/vendor/knative.dev/hack/library.sh b/vendor/knative.dev/hack/library.sh
index c2f9081ef..9b90b0025 100644
--- a/vendor/knative.dev/hack/library.sh
+++ b/vendor/knative.dev/hack/library.sh
@@ -410,28 +410,26 @@ function start_latest_knative_serving() {
 }
 
 # Install Knative Eventing in the current cluster.
-# Parameters: $1 - Knative Eventing crds manifest.
-#             $2 - Knative Eventing core manifest.
+# Parameters: $1 - Knative Eventing manifest.
 function start_knative_eventing() {
   header "Starting Knative Eventing"
   subheader "Installing Knative Eventing"
   echo "Installing Eventing CRDs from $1"
+  kubectl apply --selector knative.dev/crd-install=true -f "$1"
+  echo "Installing the rest of eventing components from $1"
   kubectl apply -f "$1"
-  echo "Installing Eventing core components from $2"
-  kubectl apply -f "$2"
   wait_until_pods_running knative-eventing || return 1
 }
 
 # Install the stable release Knative/eventing in the current cluster.
 # Parameters: $1 - Knative Eventing version number, e.g. 0.6.0.
 function start_release_knative_eventing() {
-  start_knative_eventing "https://storage.googleapis.com/knative-releases/eventing/previous/v$1/eventing-crds.yaml" \
-    "https://storage.googleapis.com/knative-releases/eventing/previous/v$1/eventing-core.yaml"
+  start_knative_eventing "https://storage.googleapis.com/knative-releases/eventing/previous/v$1/eventing.yaml"
 }
 
 # Install the latest stable Knative Eventing in the current cluster.
 function start_latest_knative_eventing() {
-  start_knative_eventing "${KNATIVE_EVENTING_RELEASE_CRDS}" "${KNATIVE_EVENTING_RELEASE_CORE}"
+  start_knative_eventing "${KNATIVE_EVENTING_RELEASE}"
 }
 
 # Install Knative Eventing extension in the current cluster.
@@ -764,6 +762,5 @@ readonly REPO_NAME_FORMATTED="Knative $(capitalize "${REPO_NAME//-/ }")"
 readonly KNATIVE_SERVING_RELEASE_CRDS="$(get_latest_knative_yaml_source "serving" "serving-crds")"
 readonly KNATIVE_SERVING_RELEASE_CORE="$(get_latest_knative_yaml_source "serving" "serving-core")"
 readonly KNATIVE_NET_ISTIO_RELEASE="$(get_latest_knative_yaml_source "net-istio" "net-istio")"
-readonly KNATIVE_EVENTING_RELEASE_CRDS="$(get_latest_knative_yaml_source "eventing" "eventing-crds")"
-readonly KNATIVE_EVENTING_RELEASE_CORE="$(get_latest_knative_yaml_source "eventing" "eventing-core")"
+readonly KNATIVE_EVENTING_RELEASE="$(get_latest_knative_yaml_source "eventing" "eventing")"
 readonly KNATIVE_EVENTING_SUGAR_CONTROLLER_RELEASE="$(get_latest_knative_yaml_source "eventing" "eventing-sugar-controller")"
diff --git a/vendor/knative.dev/hack/microbenchmarks.sh b/vendor/knative.dev/hack/microbenchmarks.sh
new file mode 100644
index 000000000..440af2e14
--- /dev/null
+++ b/vendor/knative.dev/hack/microbenchmarks.sh
@@ -0,0 +1,59 @@
+#!/usr/bin/env bash
+
+# Copyright 2019 The Knative Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+function microbenchmarks_run() {
+  if [ "$1" != "" ]; then
+    OUTPUT_FILE="$1"
+  else
+    OUTPUT_FILE="${ARTIFACTS:-$(mktemp -d)}/bench-result.txt"
+  fi
+
+  echo "Output will be at $OUTPUT_FILE"
+
+  # Run all microbenchmarks
+  go clean
+  go test -bench=. -benchmem -run="^$" -v ./...   >> "$OUTPUT_FILE" || exit
+}
+
+function microbenchmarks_run_and_compare() {
+  if [ "$1" == "" ] || [ $# -gt 1 ]; then
+    echo "Error: Expecting an argument" >&2
+    echo "usage: $(basename $0) revision_to_compare" >&2
+    exit 1
+  fi
+
+  # Benchstat is required to compare the bench results
+  GO111MODULE=off go get golang.org/x/perf/cmd/benchstat
+
+  # Revision to use to compare with actual
+  REVISION="$1"
+  OUTPUT_DIR=${ARTIFACTS:-$(mktemp -d)}
+
+  echo "Outputs will be at $OUTPUT_DIR"
+
+  # Run this revision benchmarks
+  microbenchmarks_run "$OUTPUT_DIR/new.txt"
+
+  # Run other revision benchmarks
+  git checkout "$REVISION"
+  microbenchmarks_run "$OUTPUT_DIR/old.txt"
+
+  # Print results in console
+  benchstat "$OUTPUT_DIR/old.txt" "$OUTPUT_DIR/new.txt"
+
+  # Generate html results
+  benchstat -html "$OUTPUT_DIR/old.txt" "$OUTPUT_DIR/new.txt" >> "$OUTPUT_DIR/results.html"
+}
diff --git a/vendor/knative.dev/hack/release.sh b/vendor/knative.dev/hack/release.sh
index 4dcfa9158..bd0fdda7d 100644
--- a/vendor/knative.dev/hack/release.sh
+++ b/vendor/knative.dev/hack/release.sh
@@ -468,7 +468,6 @@ function parse_flags() {
   readonly RELEASE_BRANCH
   readonly RELEASE_GCS_BUCKET
   readonly RELEASE_DIR
-  readonly KO_DOCKER_REPO
   readonly VALIDATION_TESTS
   readonly FROM_NIGHTLY_RELEASE
 }
@@ -478,11 +477,16 @@ function parse_flags() {
 function run_validation_tests() {
   (( SKIP_TESTS )) && return
   banner "Running release validation tests"
+  # Unset KO_DOCKER_REPO and restore it after the tests are finished.
+  # This will allow the tests to define their own KO_DOCKER_REPO.
+  local old_docker_repo="${KO_DOCKER_REPO}"
+  unset KO_DOCKER_REPO
   # Run tests.
   if ! $1; then
     banner "Release validation tests failed, aborting"
     abort "release validation tests failed"
   fi
+  export KO_DOCKER_REPO="${old_docker_repo}"
 }
 
 # Publishes the generated artifacts to directory, GCS, GitHub, etc.
diff --git a/vendor/knative.dev/networking/pkg/client/injection/client/client.go b/vendor/knative.dev/networking/pkg/client/injection/client/client.go
index 36318912e..c30cdb421 100644
--- a/vendor/knative.dev/networking/pkg/client/injection/client/client.go
+++ b/vendor/knative.dev/networking/pkg/client/injection/client/client.go
@@ -42,8 +42,13 @@ func withClient(ctx context.Context, cfg *rest.Config) context.Context {
 func Get(ctx context.Context) versioned.Interface {
 	untyped := ctx.Value(Key{})
 	if untyped == nil {
-		logging.FromContext(ctx).Panic(
-			"Unable to fetch knative.dev/networking/pkg/client/clientset/versioned.Interface from context.")
+		if injection.GetConfig(ctx) == nil {
+			logging.FromContext(ctx).Panic(
+				"Unable to fetch knative.dev/networking/pkg/client/clientset/versioned.Interface from context. This context is not the application context (which is typically given to constructors via sharedmain).")
+		} else {
+			logging.FromContext(ctx).Panic(
+				"Unable to fetch knative.dev/networking/pkg/client/clientset/versioned.Interface from context.")
+		}
 	}
 	return untyped.(versioned.Interface)
 }
diff --git a/vendor/knative.dev/pkg/apis/duck/v1beta1/addressable_types.go b/vendor/knative.dev/pkg/apis/duck/v1beta1/addressable_types.go
new file mode 100644
index 000000000..ba7bbc85d
--- /dev/null
+++ b/vendor/knative.dev/pkg/apis/duck/v1beta1/addressable_types.go
@@ -0,0 +1,129 @@
+/*
+Copyright 2019 The Knative Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package v1beta1
+
+import (
+	"context"
+	"fmt"
+
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/runtime"
+
+	"knative.dev/pkg/apis"
+	"knative.dev/pkg/apis/duck/ducktypes"
+	v1 "knative.dev/pkg/apis/duck/v1"
+)
+
+// +genduck
+
+// Addressable provides a generic mechanism for a custom resource
+// definition to indicate a destination for message delivery.
+//
+// Addressable is the schema for the destination information. This is
+// typically stored in the object's `status`, as this information may
+// be generated by the controller.
+type Addressable struct {
+	URL *apis.URL `json:"url,omitempty"`
+}
+
+var (
+	// Addressable is a Convertible type.
+	_ apis.Convertible = (*Addressable)(nil)
+
+	// Addressable is an Implementable "duck type".
+	_ ducktypes.Implementable = (*Addressable)(nil)
+)
+
+// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
+
+// AddressableType is a skeleton type wrapping Addressable in the manner we expect
+// resource writers defining compatible resources to embed it.  We will
+// typically use this type to deserialize Addressable ObjectReferences and
+// access the Addressable data.  This is not a real resource.
+type AddressableType struct {
+	metav1.TypeMeta   `json:",inline"`
+	metav1.ObjectMeta `json:"metadata,omitempty"`
+
+	Status AddressStatus `json:"status"`
+}
+
+// AddressStatus shows how we expect folks to embed Addressable in
+// their Status field.
+type AddressStatus struct {
+	Address *Addressable `json:"address,omitempty"`
+}
+
+// Verify AddressableType resources meet duck contracts.
+var (
+	_ apis.Listable         = (*AddressableType)(nil)
+	_ ducktypes.Populatable = (*AddressableType)(nil)
+)
+
+// GetFullType implements duck.Implementable
+func (*Addressable) GetFullType() ducktypes.Populatable {
+	return &AddressableType{}
+}
+
+// ConvertTo implements apis.Convertible
+func (a *Addressable) ConvertTo(ctx context.Context, to apis.Convertible) error {
+	switch sink := to.(type) {
+	case *v1.Addressable:
+		sink.URL = a.URL.DeepCopy()
+		return nil
+	default:
+		return fmt.Errorf("unknown version, got: %T", to)
+	}
+}
+
+// ConvertFrom implements apis.Convertible
+func (a *Addressable) ConvertFrom(ctx context.Context, from apis.Convertible) error {
+	switch source := from.(type) {
+	case *v1.Addressable:
+		a.URL = source.URL.DeepCopy()
+		return nil
+	default:
+		return fmt.Errorf("unknown version, got: %T", from)
+	}
+}
+
+// Populate implements duck.Populatable
+func (t *AddressableType) Populate() {
+	t.Status = AddressStatus{
+		&Addressable{
+			// Populate ALL fields
+			URL: &apis.URL{
+				Scheme: "http",
+				Host:   "foo.com",
+			},
+		},
+	}
+}
+
+// GetListType implements apis.Listable
+func (*AddressableType) GetListType() runtime.Object {
+	return &AddressableTypeList{}
+}
+
+// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
+
+// AddressableTypeList is a list of AddressableType resources
+type AddressableTypeList struct {
+	metav1.TypeMeta `json:",inline"`
+	metav1.ListMeta `json:"metadata"`
+
+	Items []AddressableType `json:"items"`
+}
diff --git a/vendor/knative.dev/pkg/apis/duck/v1beta1/binding_types.go b/vendor/knative.dev/pkg/apis/duck/v1beta1/binding_types.go
new file mode 100644
index 000000000..b9e970b3a
--- /dev/null
+++ b/vendor/knative.dev/pkg/apis/duck/v1beta1/binding_types.go
@@ -0,0 +1,92 @@
+/*
+Copyright 2020 The Knative Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package v1beta1
+
+import (
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/runtime"
+
+	"knative.dev/pkg/apis"
+	"knative.dev/pkg/apis/duck"
+	"knative.dev/pkg/tracker"
+)
+
+// +genduck
+// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
+
+// Binding is a duck type that specifies the partial schema to which all
+// Binding implementations should adhere.
+type Binding struct {
+	metav1.TypeMeta   `json:",inline"`
+	metav1.ObjectMeta `json:"metadata,omitempty"`
+
+	Spec BindingSpec `json:"spec"`
+}
+
+// Verify that Binding implements the appropriate interfaces.
+var (
+	_ duck.Implementable = (*Binding)(nil)
+	_ duck.Populatable   = (*Binding)(nil)
+	_ apis.Listable      = (*Binding)(nil)
+)
+
+// BindingSpec specifies the spec portion of the Binding partial-schema.
+type BindingSpec struct {
+	// Subject references the resource(s) whose "runtime contract" should be
+	// augmented by Binding implementations.
+	Subject tracker.Reference `json:"subject"`
+}
+
+// GetFullType implements duck.Implementable
+func (*Binding) GetFullType() duck.Populatable {
+	return &Binding{}
+}
+
+// Populate implements duck.Populatable
+func (t *Binding) Populate() {
+	t.Spec = BindingSpec{
+		Subject: tracker.Reference{
+			APIVersion: "apps/v1",
+			Kind:       "Deployment",
+			Namespace:  "default",
+			// Name and Selector are mutually exclusive,
+			// but we fill them both in for this test.
+			Name: "bazinga",
+			Selector: &metav1.LabelSelector{
+				MatchLabels: map[string]string{
+					"foo": "bar",
+					"baz": "blah",
+				},
+			},
+		},
+	}
+}
+
+// GetListType implements apis.Listable
+func (*Binding) GetListType() runtime.Object {
+	return &BindingList{}
+}
+
+// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
+
+// BindingList is a list of Binding resources
+type BindingList struct {
+	metav1.TypeMeta `json:",inline"`
+	metav1.ListMeta `json:"metadata"`
+
+	Items []Binding `json:"items"`
+}
diff --git a/vendor/knative.dev/pkg/apis/duck/v1beta1/destination.go b/vendor/knative.dev/pkg/apis/duck/v1beta1/destination.go
new file mode 100644
index 000000000..fe0f5d171
--- /dev/null
+++ b/vendor/knative.dev/pkg/apis/duck/v1beta1/destination.go
@@ -0,0 +1,160 @@
+/*
+Copyright 2019 The Knative Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package v1beta1
+
+import (
+	"context"
+
+	corev1 "k8s.io/api/core/v1"
+	"knative.dev/pkg/apis"
+)
+
+// Destination represents a target of an invocation over HTTP.
+type Destination struct {
+	// Ref points to an Addressable.
+	// +optional
+	Ref *corev1.ObjectReference `json:"ref,omitempty"`
+
+	// +optional
+	DeprecatedAPIVersion string `json:"apiVersion,omitempty"`
+
+	// +optional
+	DeprecatedKind string `json:"kind,omitempty"`
+
+	// +optional
+	DeprecatedName string `json:"name,omitempty"`
+
+	// +optional
+	DeprecatedNamespace string `json:"namespace,omitempty"`
+
+	// URI can be an absolute URL(non-empty scheme and non-empty host) pointing to the target or a relative URI. Relative URIs will be resolved using the base URI retrieved from Ref.
+	// +optional
+	URI *apis.URL `json:"uri,omitempty"`
+}
+
+func (dest *Destination) Validate(ctx context.Context) *apis.FieldError {
+	if dest == nil {
+		return nil
+	}
+	return ValidateDestination(*dest, true).ViaField(apis.CurrentField)
+}
+
+func (dest *Destination) ValidateDisallowDeprecated(ctx context.Context) *apis.FieldError {
+	if dest == nil {
+		return nil
+	}
+	return ValidateDestination(*dest, false).ViaField(apis.CurrentField)
+}
+
+// ValidateDestination validates Destination and either allows or disallows
+// Deprecated* fields depending on the flag.
+func ValidateDestination(dest Destination, allowDeprecatedFields bool) *apis.FieldError {
+	if !allowDeprecatedFields {
+		var errs *apis.FieldError
+		if dest.DeprecatedAPIVersion != "" {
+			errs = errs.Also(apis.ErrInvalidValue("apiVersion is not allowed here, it's a deprecated value", "apiVersion"))
+		}
+		if dest.DeprecatedKind != "" {
+			errs = errs.Also(apis.ErrInvalidValue("kind is not allowed here, it's a deprecated value", "kind"))
+		}
+		if dest.DeprecatedName != "" {
+			errs = errs.Also(apis.ErrInvalidValue("name is not allowed here, it's a deprecated value", "name"))
+		}
+		if dest.DeprecatedNamespace != "" {
+			errs = errs.Also(apis.ErrInvalidValue("namespace is not allowed here, it's a deprecated value", "namespace"))
+		}
+		if errs != nil {
+			return errs
+		}
+	}
+
+	deprecatedObjectReference := dest.deprecatedObjectReference()
+	if dest.Ref != nil && deprecatedObjectReference != nil {
+		return apis.ErrGeneric("Ref and [apiVersion, kind, name] can't be both present", "[apiVersion, kind, name]", "ref")
+	}
+
+	var ref *corev1.ObjectReference
+	if dest.Ref != nil {
+		ref = dest.Ref
+	} else {
+		ref = deprecatedObjectReference
+	}
+	if ref == nil && dest.URI == nil {
+		return apis.ErrGeneric("expected at least one, got none", "[apiVersion, kind, name]", "ref", "uri")
+	}
+
+	if ref != nil && dest.URI != nil && dest.URI.URL().IsAbs() {
+		return apis.ErrGeneric("Absolute URI is not allowed when Ref or [apiVersion, kind, name] is present", "[apiVersion, kind, name]", "ref", "uri")
+	}
+	// IsAbs() check whether the URL has a non-empty scheme. Besides the non-empty scheme, we also require dest.URI has a non-empty host
+	if ref == nil && dest.URI != nil && (!dest.URI.URL().IsAbs() || dest.URI.Host == "") {
+		return apis.ErrInvalidValue("Relative URI is not allowed when Ref and [apiVersion, kind, name] is absent", "uri")
+	}
+	if ref != nil && dest.URI == nil {
+		if dest.Ref != nil {
+			return validateDestinationRef(*ref).ViaField("ref")
+		}
+		return validateDestinationRef(*ref)
+	}
+	return nil
+}
+
+func (dest Destination) deprecatedObjectReference() *corev1.ObjectReference {
+	if dest.DeprecatedAPIVersion == "" && dest.DeprecatedKind == "" && dest.DeprecatedName == "" && dest.DeprecatedNamespace == "" {
+		return nil
+	}
+	return &corev1.ObjectReference{
+		Kind:       dest.DeprecatedKind,
+		APIVersion: dest.DeprecatedAPIVersion,
+		Name:       dest.DeprecatedName,
+		Namespace:  dest.DeprecatedNamespace,
+	}
+}
+
+// GetRef gets the ObjectReference from this Destination, if one is present. If no ref is present,
+// then nil is returned.
+// Note: this mostly exists to abstract away the deprecated ObjectReference fields. Once they are
+// removed, then this method should probably be removed too.
+func (dest *Destination) GetRef() *corev1.ObjectReference {
+	if dest == nil {
+		return nil
+	}
+	if dest.Ref != nil {
+		return dest.Ref
+	}
+	if ref := dest.deprecatedObjectReference(); ref != nil {
+		return ref
+	}
+	return nil
+}
+
+func validateDestinationRef(ref corev1.ObjectReference) *apis.FieldError {
+	// Check the object.
+	var errs *apis.FieldError
+	// Required Fields
+	if ref.Name == "" {
+		errs = errs.Also(apis.ErrMissingField("name"))
+	}
+	if ref.APIVersion == "" {
+		errs = errs.Also(apis.ErrMissingField("apiVersion"))
+	}
+	if ref.Kind == "" {
+		errs = errs.Also(apis.ErrMissingField("kind"))
+	}
+
+	return errs
+}
diff --git a/vendor/knative.dev/pkg/apis/duck/v1beta1/doc.go b/vendor/knative.dev/pkg/apis/duck/v1beta1/doc.go
new file mode 100644
index 000000000..6dbd7ff8a
--- /dev/null
+++ b/vendor/knative.dev/pkg/apis/duck/v1beta1/doc.go
@@ -0,0 +1,23 @@
+/*
+Copyright 2019 The Knative Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Api versions allow the api contract for a resource to be changed while keeping
+// backward compatibility by support multiple concurrent versions
+// of the same resource
+
+// +k8s:deepcopy-gen=package
+// +groupName=duck.knative.dev
+package v1beta1
diff --git a/vendor/knative.dev/pkg/apis/duck/v1beta1/register.go b/vendor/knative.dev/pkg/apis/duck/v1beta1/register.go
new file mode 100644
index 000000000..160eff56b
--- /dev/null
+++ b/vendor/knative.dev/pkg/apis/duck/v1beta1/register.go
@@ -0,0 +1,58 @@
+/*
+Copyright 2019 The Knative Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package v1beta1
+
+import (
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/runtime"
+	"k8s.io/apimachinery/pkg/runtime/schema"
+
+	"knative.dev/pkg/apis/duck/ducktypes"
+)
+
+// SchemeGroupVersion is group version used to register these objects
+var SchemeGroupVersion = schema.GroupVersion{Group: ducktypes.GroupName, Version: "v1beta1"}
+
+// Kind takes an unqualified kind and returns back a Group qualified GroupKind
+func Kind(kind string) schema.GroupKind {
+	return SchemeGroupVersion.WithKind(kind).GroupKind()
+}
+
+// Resource takes an unqualified resource and returns a Group qualified GroupResource
+func Resource(resource string) schema.GroupResource {
+	return SchemeGroupVersion.WithResource(resource).GroupResource()
+}
+
+var (
+	SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
+	AddToScheme   = SchemeBuilder.AddToScheme
+)
+
+// Adds the list of known types to Scheme.
+func addKnownTypes(scheme *runtime.Scheme) error {
+	scheme.AddKnownTypes(
+		SchemeGroupVersion,
+		&KResource{},
+		(&KResource{}).GetListType(),
+		&AddressableType{},
+		(&AddressableType{}).GetListType(),
+		&Binding{},
+		(&Binding{}).GetListType(),
+	)
+	metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
+	return nil
+}
diff --git a/vendor/knative.dev/pkg/apis/duck/v1beta1/source_types.go b/vendor/knative.dev/pkg/apis/duck/v1beta1/source_types.go
new file mode 100644
index 000000000..60a502041
--- /dev/null
+++ b/vendor/knative.dev/pkg/apis/duck/v1beta1/source_types.go
@@ -0,0 +1,154 @@
+/*
+Copyright 2019 The Knative Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package v1beta1
+
+import (
+	"time"
+
+	corev1 "k8s.io/api/core/v1"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/runtime"
+
+	"knative.dev/pkg/apis"
+	"knative.dev/pkg/apis/duck/ducktypes"
+)
+
+// +genduck
+// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
+
+// Source is the minimum resource shape to adhere to the Source Specification.
+// This duck type is intended to allow implementors of Sources and
+// Importers to verify their own resources meet the expectations.
+// This is not a real resource.
+// NOTE: The Source Specification is in progress and the shape and names could
+// be modified until it has been accepted.
+type Source struct {
+	metav1.TypeMeta   `json:",inline"`
+	metav1.ObjectMeta `json:"metadata,omitempty"`
+
+	Spec   SourceSpec   `json:"spec"`
+	Status SourceStatus `json:"status"`
+}
+
+type SourceSpec struct {
+	// Sink is a reference to an object that will resolve to a domain name or a
+	// URI directly to use as the sink.
+	Sink Destination `json:"sink,omitempty"`
+
+	// CloudEventOverrides defines overrides to control the output format and
+	// modifications of the event sent to the sink.
+	// +optional
+	CloudEventOverrides *CloudEventOverrides `json:"ceOverrides,omitempty"`
+}
+
+// CloudEventOverrides defines arguments for a Source that control the output
+// format of the CloudEvents produced by the Source.
+type CloudEventOverrides struct {
+	// Extensions specify what attribute are added or overridden on the
+	// outbound event. Each `Extensions` key-value pair are set on the event as
+	// an attribute extension independently.
+	// +optional
+	Extensions map[string]string `json:"extensions,omitempty"`
+}
+
+// SourceStatus shows how we expect folks to embed Addressable in
+// their Status field.
+type SourceStatus struct {
+	// inherits duck/v1beta1 Status, which currently provides:
+	// * ObservedGeneration - the 'Generation' of the Service that was last
+	//   processed by the controller.
+	// * Conditions - the latest available observations of a resource's current
+	//   state.
+	Status `json:",inline"`
+
+	// SinkURI is the current active sink URI that has been configured for the
+	// Source.
+	// +optional
+	SinkURI *apis.URL `json:"sinkUri,omitempty"`
+}
+
+// IsReady returns true if the resource is ready overall.
+func (ss *SourceStatus) IsReady() bool {
+	for _, c := range ss.Conditions {
+		switch c.Type {
+		// Look for the "happy" condition, which is the only condition that
+		// we can reliably understand to be the overall state of the resource.
+		case apis.ConditionReady, apis.ConditionSucceeded:
+			return c.IsTrue()
+		}
+	}
+	return false
+}
+
+// Verify Source resources meet duck contracts.
+var (
+	_ apis.Listable           = (*Source)(nil)
+	_ ducktypes.Implementable = (*Source)(nil)
+	_ ducktypes.Populatable   = (*Source)(nil)
+)
+
+const (
+	// SourceConditionSinkProvided has status True when the Source
+	// has been configured with a sink target that is resolvable.
+	SourceConditionSinkProvided apis.ConditionType = "SinkProvided"
+)
+
+// GetFullType implements duck.Implementable
+func (*Source) GetFullType() ducktypes.Populatable {
+	return &Source{}
+}
+
+// Populate implements duck.Populatable
+func (s *Source) Populate() {
+	s.Spec.Sink = Destination{
+		URI: &apis.URL{
+			Scheme:   "https",
+			Host:     "tableflip.dev",
+			RawQuery: "flip=mattmoor",
+		},
+	}
+	s.Spec.CloudEventOverrides = &CloudEventOverrides{
+		Extensions: map[string]string{"boosh": "kakow"},
+	}
+	s.Status.ObservedGeneration = 42
+	s.Status.Conditions = Conditions{{
+		// Populate ALL fields
+		Type:               SourceConditionSinkProvided,
+		Status:             corev1.ConditionTrue,
+		LastTransitionTime: apis.VolatileTime{Inner: metav1.NewTime(time.Date(1984, 02, 28, 18, 52, 00, 00, time.UTC))},
+	}}
+	s.Status.SinkURI = &apis.URL{
+		Scheme:   "https",
+		Host:     "tableflip.dev",
+		RawQuery: "flip=mattmoor",
+	}
+}
+
+// GetListType implements apis.Listable
+func (*Source) GetListType() runtime.Object {
+	return &SourceList{}
+}
+
+// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
+
+// SourceList is a list of Source resources
+type SourceList struct {
+	metav1.TypeMeta `json:",inline"`
+	metav1.ListMeta `json:"metadata"`
+
+	Items []Source `json:"items"`
+}
diff --git a/vendor/knative.dev/pkg/apis/duck/v1beta1/status_types.go b/vendor/knative.dev/pkg/apis/duck/v1beta1/status_types.go
new file mode 100644
index 000000000..722902676
--- /dev/null
+++ b/vendor/knative.dev/pkg/apis/duck/v1beta1/status_types.go
@@ -0,0 +1,152 @@
+/*
+Copyright 2019 The Knative Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package v1beta1
+
+import (
+	"context"
+	"time"
+
+	corev1 "k8s.io/api/core/v1"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/runtime"
+
+	"knative.dev/pkg/apis"
+	"knative.dev/pkg/apis/duck/ducktypes"
+	"knative.dev/pkg/kmeta"
+)
+
+// +genduck
+
+// Conditions is a simple wrapper around apis.Conditions to implement duck.Implementable.
+type Conditions apis.Conditions
+
+// Conditions is an Implementable duck type.
+var _ ducktypes.Implementable = (*Conditions)(nil)
+
+// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
+
+// KResource is a skeleton type wrapping Conditions in the manner we expect
+// resource writers defining compatible resources to embed it.  We will
+// typically use this type to deserialize Conditions ObjectReferences and
+// access the Conditions data.  This is not a real resource.
+type KResource struct {
+	metav1.TypeMeta   `json:",inline"`
+	metav1.ObjectMeta `json:"metadata,omitempty"`
+
+	Status Status `json:"status"`
+}
+
+// Status shows how we expect folks to embed Conditions in
+// their Status field.
+// WARNING: Adding fields to this struct will add them to all Knative resources.
+type Status struct {
+	// ObservedGeneration is the 'Generation' of the Service that
+	// was last processed by the controller.
+	// +optional
+	ObservedGeneration int64 `json:"observedGeneration,omitempty"`
+
+	// Conditions the latest available observations of a resource's current state.
+	// +optional
+	// +patchMergeKey=type
+	// +patchStrategy=merge
+	Conditions Conditions `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"`
+
+	// Annotations is additional Status fields for the Resource to save some
+	// additional State as well as convey more information to the user. This is
+	// roughly akin to Annotations on any k8s resource, just the reconciler conveying
+	// richer information outwards.
+	Annotations map[string]string `json:"annotations,omitempty"`
+}
+
+var _ apis.ConditionsAccessor = (*Status)(nil)
+
+// GetConditions implements apis.ConditionsAccessor
+func (s *Status) GetConditions() apis.Conditions {
+	return apis.Conditions(s.Conditions)
+}
+
+// SetConditions implements apis.ConditionsAccessor
+func (s *Status) SetConditions(c apis.Conditions) {
+	s.Conditions = Conditions(c)
+}
+
+// Verify KResource resources meet duck contracts.
+var (
+	_ apis.Listable         = (*KResource)(nil)
+	_ ducktypes.Populatable = (*KResource)(nil)
+)
+
+// GetFullType implements duck.Implementable
+func (*Conditions) GetFullType() ducktypes.Populatable {
+	return &KResource{}
+}
+
+// GetCondition fetches the condition of the specified type.
+func (s *Status) GetCondition(t apis.ConditionType) *apis.Condition {
+	for _, cond := range s.Conditions {
+		if cond.Type == t {
+			return &cond
+		}
+	}
+	return nil
+}
+
+// ConvertTo helps implement apis.Convertible for types embedding this Status.
+func (s *Status) ConvertTo(ctx context.Context, sink *Status) {
+	sink.ObservedGeneration = s.ObservedGeneration
+	if s.Annotations != nil {
+		// This will deep copy the map.
+		sink.Annotations = kmeta.UnionMaps(s.Annotations)
+	}
+	for _, c := range s.Conditions {
+		switch c.Type {
+		// Copy over the "happy" condition, which is the only condition that
+		// we can reliably transfer.
+		case apis.ConditionReady, apis.ConditionSucceeded:
+			sink.SetConditions(apis.Conditions{c})
+			return
+		}
+	}
+}
+
+// Populate implements duck.Populatable
+func (t *KResource) Populate() {
+	t.Status.ObservedGeneration = 42
+	t.Status.Conditions = Conditions{{
+		// Populate ALL fields
+		Type:               "Birthday",
+		Status:             corev1.ConditionTrue,
+		LastTransitionTime: apis.VolatileTime{Inner: metav1.NewTime(time.Date(1984, 02, 28, 18, 52, 00, 00, time.UTC))},
+		Reason:             "Celebrate",
+		Message:            "n3wScott, find your party hat :tada:",
+	}}
+}
+
+// GetListType implements apis.Listable
+func (*KResource) GetListType() runtime.Object {
+	return &KResourceList{}
+}
+
+// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
+
+// KResourceList is a list of KResource resources
+type KResourceList struct {
+	metav1.TypeMeta `json:",inline"`
+	metav1.ListMeta `json:"metadata"`
+
+	Items []KResource `json:"items"`
+}
diff --git a/vendor/knative.dev/pkg/apis/duck/v1beta1/zz_generated.deepcopy.go b/vendor/knative.dev/pkg/apis/duck/v1beta1/zz_generated.deepcopy.go
new file mode 100644
index 000000000..d22c6724a
--- /dev/null
+++ b/vendor/knative.dev/pkg/apis/duck/v1beta1/zz_generated.deepcopy.go
@@ -0,0 +1,472 @@
+// +build !ignore_autogenerated
+
+/*
+Copyright 2020 The Knative Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Code generated by deepcopy-gen. DO NOT EDIT.
+
+package v1beta1
+
+import (
+	v1 "k8s.io/api/core/v1"
+	runtime "k8s.io/apimachinery/pkg/runtime"
+	apis "knative.dev/pkg/apis"
+)
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *AddressStatus) DeepCopyInto(out *AddressStatus) {
+	*out = *in
+	if in.Address != nil {
+		in, out := &in.Address, &out.Address
+		*out = new(Addressable)
+		(*in).DeepCopyInto(*out)
+	}
+	return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AddressStatus.
+func (in *AddressStatus) DeepCopy() *AddressStatus {
+	if in == nil {
+		return nil
+	}
+	out := new(AddressStatus)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *Addressable) DeepCopyInto(out *Addressable) {
+	*out = *in
+	if in.URL != nil {
+		in, out := &in.URL, &out.URL
+		*out = new(apis.URL)
+		(*in).DeepCopyInto(*out)
+	}
+	return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Addressable.
+func (in *Addressable) DeepCopy() *Addressable {
+	if in == nil {
+		return nil
+	}
+	out := new(Addressable)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *AddressableType) DeepCopyInto(out *AddressableType) {
+	*out = *in
+	out.TypeMeta = in.TypeMeta
+	in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+	in.Status.DeepCopyInto(&out.Status)
+	return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AddressableType.
+func (in *AddressableType) DeepCopy() *AddressableType {
+	if in == nil {
+		return nil
+	}
+	out := new(AddressableType)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *AddressableType) DeepCopyObject() runtime.Object {
+	if c := in.DeepCopy(); c != nil {
+		return c
+	}
+	return nil
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *AddressableTypeList) DeepCopyInto(out *AddressableTypeList) {
+	*out = *in
+	out.TypeMeta = in.TypeMeta
+	in.ListMeta.DeepCopyInto(&out.ListMeta)
+	if in.Items != nil {
+		in, out := &in.Items, &out.Items
+		*out = make([]AddressableType, len(*in))
+		for i := range *in {
+			(*in)[i].DeepCopyInto(&(*out)[i])
+		}
+	}
+	return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AddressableTypeList.
+func (in *AddressableTypeList) DeepCopy() *AddressableTypeList {
+	if in == nil {
+		return nil
+	}
+	out := new(AddressableTypeList)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *AddressableTypeList) DeepCopyObject() runtime.Object {
+	if c := in.DeepCopy(); c != nil {
+		return c
+	}
+	return nil
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *Binding) DeepCopyInto(out *Binding) {
+	*out = *in
+	out.TypeMeta = in.TypeMeta
+	in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+	in.Spec.DeepCopyInto(&out.Spec)
+	return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Binding.
+func (in *Binding) DeepCopy() *Binding {
+	if in == nil {
+		return nil
+	}
+	out := new(Binding)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *Binding) DeepCopyObject() runtime.Object {
+	if c := in.DeepCopy(); c != nil {
+		return c
+	}
+	return nil
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *BindingList) DeepCopyInto(out *BindingList) {
+	*out = *in
+	out.TypeMeta = in.TypeMeta
+	in.ListMeta.DeepCopyInto(&out.ListMeta)
+	if in.Items != nil {
+		in, out := &in.Items, &out.Items
+		*out = make([]Binding, len(*in))
+		for i := range *in {
+			(*in)[i].DeepCopyInto(&(*out)[i])
+		}
+	}
+	return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BindingList.
+func (in *BindingList) DeepCopy() *BindingList {
+	if in == nil {
+		return nil
+	}
+	out := new(BindingList)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *BindingList) DeepCopyObject() runtime.Object {
+	if c := in.DeepCopy(); c != nil {
+		return c
+	}
+	return nil
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *BindingSpec) DeepCopyInto(out *BindingSpec) {
+	*out = *in
+	in.Subject.DeepCopyInto(&out.Subject)
+	return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BindingSpec.
+func (in *BindingSpec) DeepCopy() *BindingSpec {
+	if in == nil {
+		return nil
+	}
+	out := new(BindingSpec)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *CloudEventOverrides) DeepCopyInto(out *CloudEventOverrides) {
+	*out = *in
+	if in.Extensions != nil {
+		in, out := &in.Extensions, &out.Extensions
+		*out = make(map[string]string, len(*in))
+		for key, val := range *in {
+			(*out)[key] = val
+		}
+	}
+	return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CloudEventOverrides.
+func (in *CloudEventOverrides) DeepCopy() *CloudEventOverrides {
+	if in == nil {
+		return nil
+	}
+	out := new(CloudEventOverrides)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in Conditions) DeepCopyInto(out *Conditions) {
+	{
+		in := &in
+		*out = make(Conditions, len(*in))
+		for i := range *in {
+			(*in)[i].DeepCopyInto(&(*out)[i])
+		}
+		return
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Conditions.
+func (in Conditions) DeepCopy() Conditions {
+	if in == nil {
+		return nil
+	}
+	out := new(Conditions)
+	in.DeepCopyInto(out)
+	return *out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *Destination) DeepCopyInto(out *Destination) {
+	*out = *in
+	if in.Ref != nil {
+		in, out := &in.Ref, &out.Ref
+		*out = new(v1.ObjectReference)
+		**out = **in
+	}
+	if in.URI != nil {
+		in, out := &in.URI, &out.URI
+		*out = new(apis.URL)
+		(*in).DeepCopyInto(*out)
+	}
+	return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Destination.
+func (in *Destination) DeepCopy() *Destination {
+	if in == nil {
+		return nil
+	}
+	out := new(Destination)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *KResource) DeepCopyInto(out *KResource) {
+	*out = *in
+	out.TypeMeta = in.TypeMeta
+	in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+	in.Status.DeepCopyInto(&out.Status)
+	return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KResource.
+func (in *KResource) DeepCopy() *KResource {
+	if in == nil {
+		return nil
+	}
+	out := new(KResource)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *KResource) DeepCopyObject() runtime.Object {
+	if c := in.DeepCopy(); c != nil {
+		return c
+	}
+	return nil
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *KResourceList) DeepCopyInto(out *KResourceList) {
+	*out = *in
+	out.TypeMeta = in.TypeMeta
+	in.ListMeta.DeepCopyInto(&out.ListMeta)
+	if in.Items != nil {
+		in, out := &in.Items, &out.Items
+		*out = make([]KResource, len(*in))
+		for i := range *in {
+			(*in)[i].DeepCopyInto(&(*out)[i])
+		}
+	}
+	return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KResourceList.
+func (in *KResourceList) DeepCopy() *KResourceList {
+	if in == nil {
+		return nil
+	}
+	out := new(KResourceList)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *KResourceList) DeepCopyObject() runtime.Object {
+	if c := in.DeepCopy(); c != nil {
+		return c
+	}
+	return nil
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *Source) DeepCopyInto(out *Source) {
+	*out = *in
+	out.TypeMeta = in.TypeMeta
+	in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+	in.Spec.DeepCopyInto(&out.Spec)
+	in.Status.DeepCopyInto(&out.Status)
+	return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Source.
+func (in *Source) DeepCopy() *Source {
+	if in == nil {
+		return nil
+	}
+	out := new(Source)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *Source) DeepCopyObject() runtime.Object {
+	if c := in.DeepCopy(); c != nil {
+		return c
+	}
+	return nil
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *SourceList) DeepCopyInto(out *SourceList) {
+	*out = *in
+	out.TypeMeta = in.TypeMeta
+	in.ListMeta.DeepCopyInto(&out.ListMeta)
+	if in.Items != nil {
+		in, out := &in.Items, &out.Items
+		*out = make([]Source, len(*in))
+		for i := range *in {
+			(*in)[i].DeepCopyInto(&(*out)[i])
+		}
+	}
+	return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SourceList.
+func (in *SourceList) DeepCopy() *SourceList {
+	if in == nil {
+		return nil
+	}
+	out := new(SourceList)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *SourceList) DeepCopyObject() runtime.Object {
+	if c := in.DeepCopy(); c != nil {
+		return c
+	}
+	return nil
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *SourceSpec) DeepCopyInto(out *SourceSpec) {
+	*out = *in
+	in.Sink.DeepCopyInto(&out.Sink)
+	if in.CloudEventOverrides != nil {
+		in, out := &in.CloudEventOverrides, &out.CloudEventOverrides
+		*out = new(CloudEventOverrides)
+		(*in).DeepCopyInto(*out)
+	}
+	return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SourceSpec.
+func (in *SourceSpec) DeepCopy() *SourceSpec {
+	if in == nil {
+		return nil
+	}
+	out := new(SourceSpec)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *SourceStatus) DeepCopyInto(out *SourceStatus) {
+	*out = *in
+	in.Status.DeepCopyInto(&out.Status)
+	if in.SinkURI != nil {
+		in, out := &in.SinkURI, &out.SinkURI
+		*out = new(apis.URL)
+		(*in).DeepCopyInto(*out)
+	}
+	return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SourceStatus.
+func (in *SourceStatus) DeepCopy() *SourceStatus {
+	if in == nil {
+		return nil
+	}
+	out := new(SourceStatus)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *Status) DeepCopyInto(out *Status) {
+	*out = *in
+	if in.Conditions != nil {
+		in, out := &in.Conditions, &out.Conditions
+		*out = make(Conditions, len(*in))
+		for i := range *in {
+			(*in)[i].DeepCopyInto(&(*out)[i])
+		}
+	}
+	if in.Annotations != nil {
+		in, out := &in.Annotations, &out.Annotations
+		*out = make(map[string]string, len(*in))
+		for key, val := range *in {
+			(*out)[key] = val
+		}
+	}
+	return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Status.
+func (in *Status) DeepCopy() *Status {
+	if in == nil {
+		return nil
+	}
+	out := new(Status)
+	in.DeepCopyInto(out)
+	return out
+}
diff --git a/vendor/knative.dev/pkg/client/injection/ducks/duck/v1/addressable/addressable.go b/vendor/knative.dev/pkg/client/injection/ducks/duck/v1/addressable/addressable.go
new file mode 100644
index 000000000..09a21e06e
--- /dev/null
+++ b/vendor/knative.dev/pkg/client/injection/ducks/duck/v1/addressable/addressable.go
@@ -0,0 +1,60 @@
+/*
+Copyright 2020 The Knative Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Code generated by injection-gen. DO NOT EDIT.
+
+package addressable
+
+import (
+	context "context"
+
+	duck "knative.dev/pkg/apis/duck"
+	v1 "knative.dev/pkg/apis/duck/v1"
+	controller "knative.dev/pkg/controller"
+	injection "knative.dev/pkg/injection"
+	dynamicclient "knative.dev/pkg/injection/clients/dynamicclient"
+	logging "knative.dev/pkg/logging"
+)
+
+func init() {
+	injection.Default.RegisterDuck(WithDuck)
+}
+
+// Key is used for associating the Informer inside the context.Context.
+type Key struct{}
+
+func WithDuck(ctx context.Context) context.Context {
+	dc := dynamicclient.Get(ctx)
+	dif := &duck.CachedInformerFactory{
+		Delegate: &duck.TypedInformerFactory{
+			Client:       dc,
+			Type:         (&v1.Addressable{}).GetFullType(),
+			ResyncPeriod: controller.GetResyncPeriod(ctx),
+			StopChannel:  ctx.Done(),
+		},
+	}
+	return context.WithValue(ctx, Key{}, dif)
+}
+
+// Get extracts the typed informer from the context.
+func Get(ctx context.Context) duck.InformerFactory {
+	untyped := ctx.Value(Key{})
+	if untyped == nil {
+		logging.FromContext(ctx).Panic(
+			"Unable to fetch knative.dev/pkg/apis/duck.InformerFactory from context.")
+	}
+	return untyped.(duck.InformerFactory)
+}
diff --git a/vendor/knative.dev/pkg/client/injection/kube/client/client.go b/vendor/knative.dev/pkg/client/injection/kube/client/client.go
index fb62015cb..00591ff57 100644
--- a/vendor/knative.dev/pkg/client/injection/kube/client/client.go
+++ b/vendor/knative.dev/pkg/client/injection/kube/client/client.go
@@ -42,8 +42,13 @@ func withClient(ctx context.Context, cfg *rest.Config) context.Context {
 func Get(ctx context.Context) kubernetes.Interface {
 	untyped := ctx.Value(Key{})
 	if untyped == nil {
-		logging.FromContext(ctx).Panic(
-			"Unable to fetch k8s.io/client-go/kubernetes.Interface from context.")
+		if injection.GetConfig(ctx) == nil {
+			logging.FromContext(ctx).Panic(
+				"Unable to fetch k8s.io/client-go/kubernetes.Interface from context. This context is not the application context (which is typically given to constructors via sharedmain).")
+		} else {
+			logging.FromContext(ctx).Panic(
+				"Unable to fetch k8s.io/client-go/kubernetes.Interface from context.")
+		}
 	}
 	return untyped.(kubernetes.Interface)
 }
diff --git a/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/client.go b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/client.go
index 9add17e93..317e12a44 100644
--- a/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/client.go
+++ b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/client.go
@@ -98,8 +98,13 @@ func withClient(ctx {{.contextContext|raw}}, cfg *{{.restConfig|raw}}) context.C
 func Get(ctx {{.contextContext|raw}}) {{.clientSetInterface|raw}} {
 	untyped := ctx.Value(Key{})
 	if untyped == nil {
-		{{.loggingFromContext|raw}}(ctx).Panic(
-			"Unable to fetch {{.clientSetInterface}} from context.")
+		if injection.GetConfig(ctx) == nil {
+		    {{.loggingFromContext|raw}}(ctx).Panic(
+		    	    "Unable to fetch {{.clientSetInterface}} from context. This context is not the application context (which is typically given to constructors via sharedmain).")
+		} else {
+		    {{.loggingFromContext|raw}}(ctx).Panic(
+		    	    "Unable to fetch {{.clientSetInterface}} from context.")
+		}
 	}
 	return untyped.({{.clientSetInterface|raw}})
 }
diff --git a/vendor/knative.dev/pkg/controller/controller.go b/vendor/knative.dev/pkg/controller/controller.go
index b0ecb2e9b..941117c71 100644
--- a/vendor/knative.dev/pkg/controller/controller.go
+++ b/vendor/knative.dev/pkg/controller/controller.go
@@ -493,7 +493,7 @@ func (c *Impl) processNextWorkItem() bool {
 		if err != nil {
 			status = falseString
 		}
-		c.statsReporter.ReportReconcile(time.Since(startTime), status)
+		c.statsReporter.ReportReconcile(time.Since(startTime), status, key)
 
 		// We call Done here so the workqueue knows we have finished
 		// processing this item. We also must remember to call Forget if
diff --git a/vendor/knative.dev/pkg/controller/stats_reporter.go b/vendor/knative.dev/pkg/controller/stats_reporter.go
index 7ffa80d7b..92a5848a1 100644
--- a/vendor/knative.dev/pkg/controller/stats_reporter.go
+++ b/vendor/knative.dev/pkg/controller/stats_reporter.go
@@ -25,10 +25,12 @@ import (
 	"go.opencensus.io/stats/view"
 	"go.opencensus.io/tag"
 	"go.uber.org/zap"
+	"k8s.io/apimachinery/pkg/types"
 	"k8s.io/client-go/tools/cache"
 	kubemetrics "k8s.io/client-go/tools/metrics"
 	"k8s.io/client-go/util/workqueue"
 	"knative.dev/pkg/metrics"
+	"knative.dev/pkg/metrics/metricskey"
 )
 
 var (
@@ -47,6 +49,7 @@ var (
 	// - characters are printable US-ASCII
 	reconcilerTagKey = tag.MustNewKey("reconciler")
 	successTagKey    = tag.MustNewKey("success")
+	NamespaceTagKey  = tag.MustNewKey(metricskey.LabelNamespaceName)
 )
 
 func init() {
@@ -170,12 +173,12 @@ func init() {
 		Description: "Number of reconcile operations",
 		Measure:     reconcileCountStat,
 		Aggregation: view.Count(),
-		TagKeys:     []tag.Key{reconcilerTagKey, successTagKey},
+		TagKeys:     []tag.Key{reconcilerTagKey, successTagKey, NamespaceTagKey},
 	}, {
 		Description: "Latency of reconcile operations",
 		Measure:     reconcileLatencyStat,
 		Aggregation: reconcileDistribution,
-		TagKeys:     []tag.Key{reconcilerTagKey, successTagKey},
+		TagKeys:     []tag.Key{reconcilerTagKey, successTagKey, NamespaceTagKey},
 	}}
 	views = append(views, wp.DefaultViews()...)
 	views = append(views, rp.DefaultViews()...)
@@ -195,7 +198,7 @@ type StatsReporter interface {
 	ReportQueueDepth(v int64) error
 
 	// ReportReconcile reports the count and latency metrics for a reconcile operation
-	ReportReconcile(duration time.Duration, success string) error
+	ReportReconcile(duration time.Duration, success string, key types.NamespacedName) error
 }
 
 // Reporter holds cached metric objects to report metrics
@@ -237,11 +240,14 @@ func (r *reporter) ReportQueueDepth(v int64) error {
 }
 
 // ReportReconcile reports the count and latency metrics for a reconcile operation
-func (r *reporter) ReportReconcile(duration time.Duration, success string) error {
+func (r *reporter) ReportReconcile(duration time.Duration, success string, key types.NamespacedName) error {
 	ctx, err := tag.New(
 		context.Background(),
 		tag.Insert(reconcilerTagKey, r.reconciler),
-		tag.Insert(successTagKey, success))
+		tag.Insert(successTagKey, success),
+		tag.Insert(NamespaceTagKey, key.Namespace),
+	)
+
 	if err != nil {
 		return err
 	}
diff --git a/vendor/knative.dev/pkg/metrics/prometheus_exporter.go b/vendor/knative.dev/pkg/metrics/prometheus_exporter.go
index 784eab2e8..7c177b129 100644
--- a/vendor/knative.dev/pkg/metrics/prometheus_exporter.go
+++ b/vendor/knative.dev/pkg/metrics/prometheus_exporter.go
@@ -48,7 +48,7 @@ func newPrometheusExporter(config *metricsConfig, logger *zap.SugaredLogger) (vi
 		logger.Errorw("Failed to create the Prometheus exporter.", zap.Error(err))
 		return nil, nil, err
 	}
-	logger.Infof("Created Opencensus Prometheus exporter with config: %v. Start the server for Prometheus exporter.", config)
+	logger.Infof("Created Prometheus exporter with config: %v. Start the server for Prometheus exporter.", config)
 	// Start the server for Prometheus scraping
 	go func() {
 		srv := startNewPromSrv(e, config.prometheusHost, config.prometheusPort)
diff --git a/vendor/knative.dev/pkg/resolver/addressable_resolver.go b/vendor/knative.dev/pkg/resolver/addressable_resolver.go
new file mode 100644
index 000000000..4407f80be
--- /dev/null
+++ b/vendor/knative.dev/pkg/resolver/addressable_resolver.go
@@ -0,0 +1,191 @@
+/*
+Copyright 2019 The Knative Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package resolver
+
+import (
+	"context"
+	"errors"
+	"fmt"
+
+	corev1 "k8s.io/api/core/v1"
+	apierrs "k8s.io/apimachinery/pkg/api/errors"
+	"k8s.io/apimachinery/pkg/api/meta"
+	"k8s.io/apimachinery/pkg/types"
+
+	"knative.dev/pkg/apis"
+	pkgapisduck "knative.dev/pkg/apis/duck"
+	duckv1 "knative.dev/pkg/apis/duck/v1"
+	duckv1beta1 "knative.dev/pkg/apis/duck/v1beta1"
+	"knative.dev/pkg/controller"
+	"knative.dev/pkg/network"
+	"knative.dev/pkg/tracker"
+
+	"knative.dev/pkg/client/injection/ducks/duck/v1/addressable"
+)
+
+// URIResolver resolves Destinations and ObjectReferences into a URI.
+type URIResolver struct {
+	tracker         tracker.Interface
+	informerFactory pkgapisduck.InformerFactory
+}
+
+// NewURIResolver constructs a new URIResolver with context and a callback
+// for a given listableType (Listable) passed to the URIResolver's tracker.
+func NewURIResolver(ctx context.Context, callback func(types.NamespacedName)) *URIResolver {
+	ret := &URIResolver{}
+
+	ret.tracker = tracker.New(callback, controller.GetTrackerLease(ctx))
+	ret.informerFactory = &pkgapisduck.CachedInformerFactory{
+		Delegate: &pkgapisduck.EnqueueInformerFactory{
+			Delegate:     addressable.Get(ctx),
+			EventHandler: controller.HandleAll(ret.tracker.OnChanged),
+		},
+	}
+
+	return ret
+}
+
+// URIFromDestination resolves a v1beta1.Destination into a URI string.
+func (r *URIResolver) URIFromDestination(ctx context.Context, dest duckv1beta1.Destination, parent interface{}) (string, error) {
+	var deprecatedObjectReference *corev1.ObjectReference
+	if !(dest.DeprecatedAPIVersion == "" && dest.DeprecatedKind == "" && dest.DeprecatedName == "" && dest.DeprecatedNamespace == "") {
+		deprecatedObjectReference = &corev1.ObjectReference{
+			Kind:       dest.DeprecatedKind,
+			APIVersion: dest.DeprecatedAPIVersion,
+			Name:       dest.DeprecatedName,
+			Namespace:  dest.DeprecatedNamespace,
+		}
+	}
+	if dest.Ref != nil && deprecatedObjectReference != nil {
+		return "", errors.New("ref and [apiVersion, kind, name] can't be both present")
+	}
+	var ref *corev1.ObjectReference
+	if dest.Ref != nil {
+		ref = dest.Ref
+	} else {
+		ref = deprecatedObjectReference
+	}
+	if ref != nil {
+		url, err := r.URIFromObjectReference(ctx, ref, parent)
+		if err != nil {
+			return "", err
+		}
+		if dest.URI != nil {
+			if dest.URI.URL().IsAbs() {
+				return "", errors.New("absolute URI is not allowed when Ref or [apiVersion, kind, name] exists")
+			}
+			return url.ResolveReference(dest.URI).String(), nil
+		}
+		return url.URL().String(), nil
+	}
+
+	if dest.URI != nil {
+		// IsAbs check whether the URL has a non-empty scheme. Besides the non non-empty scheme, we also require dest.URI has a non-empty host
+		if !dest.URI.URL().IsAbs() || dest.URI.Host == "" {
+			return "", fmt.Errorf("URI is not absolute (both scheme and host should be non-empty): %q", dest.URI.String())
+		}
+		return dest.URI.String(), nil
+	}
+
+	return "", errors.New("destination missing Ref, [apiVersion, kind, name] and URI, expected at least one")
+}
+
+// URIFromDestinationV1 resolves a v1.Destination into a URL.
+func (r *URIResolver) URIFromDestinationV1(ctx context.Context, dest duckv1.Destination, parent interface{}) (*apis.URL, error) {
+	if dest.Ref != nil {
+		url, err := r.URIFromKReference(ctx, dest.Ref, parent)
+		if err != nil {
+			return nil, err
+		}
+		if dest.URI != nil {
+			if dest.URI.URL().IsAbs() {
+				return nil, errors.New("absolute URI is not allowed when Ref or [apiVersion, kind, name] exists")
+			}
+			return url.ResolveReference(dest.URI), nil
+		}
+		return url, nil
+	}
+
+	if dest.URI != nil {
+		// IsAbs check whether the URL has a non-empty scheme. Besides the non non-empty scheme, we also require dest.URI has a non-empty host
+		if !dest.URI.URL().IsAbs() || dest.URI.Host == "" {
+			return nil, fmt.Errorf("URI is not absolute(both scheme and host should be non-empty): %q", dest.URI.String())
+		}
+		return dest.URI, nil
+	}
+
+	return nil, errors.New("destination missing Ref and URI, expected at least one")
+}
+
+func (r *URIResolver) URIFromKReference(ctx context.Context, ref *duckv1.KReference, parent interface{}) (*apis.URL, error) {
+	return r.URIFromObjectReference(ctx, &corev1.ObjectReference{Name: ref.Name, Namespace: ref.Namespace, APIVersion: ref.APIVersion, Kind: ref.Kind}, parent)
+}
+
+// URIFromObjectReference resolves an ObjectReference to a URI string.
+func (r *URIResolver) URIFromObjectReference(ctx context.Context, ref *corev1.ObjectReference, parent interface{}) (*apis.URL, error) {
+	if ref == nil {
+		return nil, apierrs.NewBadRequest("ref is nil")
+	}
+
+	gvr, _ := meta.UnsafeGuessKindToResource(ref.GroupVersionKind())
+	if err := r.tracker.TrackReference(tracker.Reference{
+		APIVersion: ref.APIVersion,
+		Kind:       ref.Kind,
+		Namespace:  ref.Namespace,
+		Name:       ref.Name,
+	}, parent); err != nil {
+		return nil, apierrs.NewNotFound(gvr.GroupResource(), ref.Name)
+	}
+
+	// K8s Services are special cased. They can be called, even though they do not satisfy the
+	// Callable interface.
+	// TODO(spencer-p,n3wscott) Verify that the service actually exists in K8s.
+	if ref.APIVersion == "v1" && ref.Kind == "Service" {
+		url := &apis.URL{
+			Scheme: "http",
+			Host:   network.GetServiceHostname(ref.Name, ref.Namespace),
+			Path:   "/",
+		}
+		return url, nil
+	}
+
+	_, lister, err := r.informerFactory.Get(ctx, gvr)
+	if err != nil {
+		return nil, apierrs.NewNotFound(gvr.GroupResource(), "Lister")
+	}
+
+	obj, err := lister.ByNamespace(ref.Namespace).Get(ref.Name)
+	if err != nil {
+		return nil, apierrs.NewNotFound(gvr.GroupResource(), ref.Name)
+	}
+
+	addressable, ok := obj.(*duckv1.AddressableType)
+	if !ok {
+		return nil, apierrs.NewBadRequest(fmt.Sprintf("%+v (%T) is not an AddressableType", ref, ref))
+	}
+	if addressable.Status.Address == nil {
+		return nil, apierrs.NewBadRequest(fmt.Sprintf("address not set for %+v", ref))
+	}
+	url := addressable.Status.Address.URL
+	if url == nil {
+		return nil, apierrs.NewBadRequest(fmt.Sprintf("URL missing in address of %+v", ref))
+	}
+	if url.Host == "" {
+		return nil, apierrs.NewBadRequest(fmt.Sprintf("hostname missing in address of %+v", ref))
+	}
+	return url, nil
+}
diff --git a/vendor/knative.dev/pkg/resolver/doc.go b/vendor/knative.dev/pkg/resolver/doc.go
new file mode 100644
index 000000000..565821272
--- /dev/null
+++ b/vendor/knative.dev/pkg/resolver/doc.go
@@ -0,0 +1,18 @@
+/*
+Copyright 2019 The Knative Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Package resolver implements resolvers for resolving k8s references and URIs.
+package resolver
diff --git a/vendor/knative.dev/pkg/webhook/env.go b/vendor/knative.dev/pkg/webhook/env.go
index 9e59f7cfd..cd038b40e 100644
--- a/vendor/knative.dev/pkg/webhook/env.go
+++ b/vendor/knative.dev/pkg/webhook/env.go
@@ -24,6 +24,9 @@ import (
 
 const portEnvKey = "WEBHOOK_PORT"
 
+// Webhook is the name of the override key used inside of the logging config for Webhook Controller.
+const webhookNameEnv = "WEBHOOK_NAME"
+
 // PortFromEnv returns the webhook port set by portEnvKey, or default port if env var is not set.
 func PortFromEnv(defaultPort int) int {
 	if os.Getenv(portEnvKey) == "" {
@@ -37,3 +40,17 @@ func PortFromEnv(defaultPort int) int {
 	}
 	return port
 }
+
+func NameFromEnv() string {
+	if webhook := os.Getenv(webhookNameEnv); webhook != "" {
+		return webhook
+	}
+
+	panic(fmt.Sprintf(`The environment variable %q is not set.
+This should be unique for the webhooks in a namespace
+If this is a process running on Kubernetes, then initialize this variable via:
+  env:
+  - name: WEBHOOK_NAME
+    value: webhook
+`, webhookNameEnv))
+}
diff --git a/vendor/knative.dev/pkg/websocket/connection.go b/vendor/knative.dev/pkg/websocket/connection.go
index 00feceb50..7493d5712 100644
--- a/vendor/knative.dev/pkg/websocket/connection.go
+++ b/vendor/knative.dev/pkg/websocket/connection.go
@@ -22,6 +22,7 @@ import (
 	"errors"
 	"io"
 	"io/ioutil"
+	"net/http/httputil"
 	"sync"
 	"time"
 
@@ -133,9 +134,15 @@ func NewDurableConnection(target string, messageChan chan []byte, logger *zap.Su
 			// by restarting the serving side of the connection behind a Kubernetes Service.
 			HandshakeTimeout: 3 * time.Second,
 		}
-		conn, _, err := dialer.Dial(target, nil)
+		conn, resp, err := dialer.Dial(target, nil)
 		if err != nil {
-			logger.Errorw("Websocket connection could not be established", zap.Error(err))
+			if resp != nil {
+				dresp, _ := httputil.DumpResponse(resp, true /*body*/) // This is for logging so don't care if it fails.
+				logger.Errorw("Websocket connection could not be established", zap.Error(err),
+					zap.String("request", string(dresp)))
+			} else {
+				logger.Errorw("Websocket connection could not be established", zap.Error(err))
+			}
 		}
 		return conn, err
 	}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 62c9f3339..02c85e5d5 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -952,7 +952,7 @@ k8s.io/utils/buffer
 k8s.io/utils/integer
 k8s.io/utils/pointer
 k8s.io/utils/trace
-# knative.dev/caching v0.0.0-20201119021451-514d4f69f7bc
+# knative.dev/caching v0.0.0-20201125150135-91fb5833c3c6
 ## explicit
 knative.dev/caching/config
 knative.dev/caching/pkg/apis/caching
@@ -973,10 +973,10 @@ knative.dev/caching/pkg/client/injection/informers/caching/v1alpha1/image/fake
 knative.dev/caching/pkg/client/injection/informers/factory
 knative.dev/caching/pkg/client/injection/informers/factory/fake
 knative.dev/caching/pkg/client/listers/caching/v1alpha1
-# knative.dev/hack v0.0.0-20201119025252-d3cb354f49ff
+# knative.dev/hack v0.0.0-20201125230335-c46a6498e9ed
 ## explicit
 knative.dev/hack
-# knative.dev/networking v0.0.0-20201119023952-faeea4d06427
+# knative.dev/networking v0.0.0-20201125133435-4b21f11ccfa7
 ## explicit
 knative.dev/networking/config
 knative.dev/networking/pkg
@@ -1009,7 +1009,7 @@ knative.dev/networking/test/conformance/ingress
 knative.dev/networking/test/defaultsystem
 knative.dev/networking/test/test_images/grpc-ping/proto
 knative.dev/networking/test/types
-# knative.dev/pkg v0.0.0-20201119021551-260026d54739
+# knative.dev/pkg v0.0.0-20201125095035-9bf616d2f46a
 ## explicit
 knative.dev/pkg/apiextensions/storageversion
 knative.dev/pkg/apiextensions/storageversion/cmd/migrate
@@ -1017,10 +1017,12 @@ knative.dev/pkg/apis
 knative.dev/pkg/apis/duck
 knative.dev/pkg/apis/duck/ducktypes
 knative.dev/pkg/apis/duck/v1
+knative.dev/pkg/apis/duck/v1beta1
 knative.dev/pkg/apis/testing
 knative.dev/pkg/apis/testing/fuzzer
 knative.dev/pkg/apis/testing/roundtrip
 knative.dev/pkg/changeset
+knative.dev/pkg/client/injection/ducks/duck/v1/addressable
 knative.dev/pkg/client/injection/kube/client
 knative.dev/pkg/client/injection/kube/client/fake
 knative.dev/pkg/client/injection/kube/informers/admissionregistration/v1/mutatingwebhookconfiguration
@@ -1082,6 +1084,7 @@ knative.dev/pkg/profiling
 knative.dev/pkg/ptr
 knative.dev/pkg/reconciler
 knative.dev/pkg/reconciler/testing
+knative.dev/pkg/resolver
 knative.dev/pkg/signals
 knative.dev/pkg/system
 knative.dev/pkg/system/testing


Test patch:
diff --git a/pkg/autoscaler/statserver/server_test.go b/pkg/autoscaler/statserver/server_test.go
index 5ea4d5339..1846c5d07 100644
--- a/pkg/autoscaler/statserver/server_test.go
+++ b/pkg/autoscaler/statserver/server_test.go
@@ -17,8 +17,6 @@ limitations under the License.
 package statserver
 
 import (
-	"bytes"
-	"encoding/json"
 	"errors"
 	"fmt"
 	"net"
@@ -107,10 +105,6 @@ func TestStatsReceived(t *testing.T) {
 	// protobuf
 	assertReceivedProto(t, both, statSink, statsCh)
 
-	// json encoding
-	assertReceivedJSON(t, msg1, statSink, statsCh)
-	assertReceivedJSON(t, msg2, statSink, statsCh)
-
 	closeSink(t, statSink)
 }
 
@@ -242,20 +236,6 @@ func BenchmarkStatServer(b *testing.B) {
 			msgs = append(msgs, msg1)
 		}
 
-		b.Run(fmt.Sprintf("json-encoding-%d-msgs", len(msgs)), func(b *testing.B) {
-			for i := 0; i < b.N; i++ {
-				for _, msg := range msgs {
-					if err := sendJSON(statSink, msg); err != nil {
-						b.Fatal("Expected send to succeed, but got:", err)
-					}
-				}
-
-				for range msgs {
-					<-statsCh
-				}
-			}
-		})
-
 		b.Run(fmt.Sprintf("proto-encoding-%d-msgs", len(msgs)), func(b *testing.B) {
 			for i := 0; i < b.N; i++ {
 				if err := sendProto(statSink, msgs); err != nil {
@@ -270,19 +250,6 @@ func BenchmarkStatServer(b *testing.B) {
 	}
 }
 
-func assertReceivedJSON(t *testing.T, sm metrics.StatMessage, statSink *websocket.Conn, statsCh <-chan metrics.StatMessage) {
-	t.Helper()
-
-	if err := sendJSON(statSink, sm); err != nil {
-		t.Fatal("Expected send to succeed, got:", err)
-	}
-
-	recv := <-statsCh
-	if !cmp.Equal(sm, recv) {
-		t.Fatal("StatMessage mismatch: diff (-got, +want)", cmp.Diff(recv, sm))
-	}
-}
-
 func assertReceivedProto(t *testing.T, sms []metrics.StatMessage, statSink *websocket.Conn, statsCh <-chan metrics.StatMessage) {
 	t.Helper()
 
@@ -323,19 +290,6 @@ func dial(serverURL string) (*websocket.Conn, error) {
 	return statSink, err
 }
 
-func sendJSON(statSink *websocket.Conn, sm metrics.StatMessage) error {
-	var b bytes.Buffer
-	enc := json.NewEncoder(&b)
-	if err := enc.Encode(sm); err != nil {
-		return fmt.Errorf("failed to encode StatMessage: %w", err)
-	}
-
-	if err := statSink.WriteMessage(websocket.TextMessage, b.Bytes()); err != nil {
-		return fmt.Errorf("failed to write to stat sink: %w", err)
-	}
-	return nil
-}
-
 func sendProto(statSink *websocket.Conn, sms []metrics.StatMessage) error {
 	wsms := metrics.ToWireStatMessages(sms)
 	msg, err := wsms.Marshal()
diff --git a/pkg/logging/config_test.go b/pkg/logging/config_test.go
index 27a8adc31..c50e64319 100644
--- a/pkg/logging/config_test.go
+++ b/pkg/logging/config_test.go
@@ -50,9 +50,7 @@ func TestNewConfigNoEntry(t *testing.T) {
 	if diff := cmp.Diff(cm, c); diff != "" {
 		t.Fatalf("Config mismatch: diff(-want,+got):\n%s", diff)
 	}
-	if got := c.LoggingConfig; got == "" {
-		t.Error("LoggingConfig = empty, want not empty")
-	}
+	// TODO: assert that c.LoggingConfig is empty.
 	if got, want := len(c.LoggingLevel), 0; got != want {
 		t.Errorf("len(LoggingLevel) = %d, want %d", got, want)
 	}
diff --git a/pkg/queue/breaker_test.go b/pkg/queue/breaker_test.go
index ce8ead764..5a6539fce 100644
--- a/pkg/queue/breaker_test.go
+++ b/pkg/queue/breaker_test.go
@@ -18,7 +18,6 @@ package queue
 
 import (
 	"context"
-	"errors"
 	"fmt"
 	"testing"
 	"time"
@@ -275,12 +274,22 @@ func TestSemaphoreAcquireHasCapacity(t *testing.T) {
 func TestSemaphoreRelease(t *testing.T) {
 	sem := newSemaphore(1, 1)
 	sem.acquire(context.Background())
-	if err := sem.release(); err != nil {
-		t.Errorf("release = %v; want: %v", err, nil)
-	}
-	if err := sem.release(); !errors.Is(err, ErrRelease) {
-		t.Errorf("release = %v; want: %v", err, ErrRelease)
-	}
+	func() {
+		defer func() {
+			if e := recover(); e != nil {
+				t.Error("Expected no panic, got message:", e)
+			}
+			sem.release()
+		}()
+	}()
+	func() {
+		defer func() {
+			if e := recover(); e == nil {
+				t.Error("Expected panic, but got none")
+			}
+		}()
+		sem.release()
+	}()
 }
 
 func TestSemaphoreUpdateCapacity(t *testing.T) {
diff --git a/pkg/reconciler/domainmapping/resources/ingress_test.go b/pkg/reconciler/domainmapping/resources/ingress_test.go
index f371cec90..c3120d451 100644
--- a/pkg/reconciler/domainmapping/resources/ingress_test.go
+++ b/pkg/reconciler/domainmapping/resources/ingress_test.go
@@ -27,7 +27,6 @@ import (
 	netv1alpha1 "knative.dev/networking/pkg/apis/networking/v1alpha1"
 	duckv1 "knative.dev/pkg/apis/duck/v1"
 	"knative.dev/pkg/kmeta"
-	pkgnetwork "knative.dev/pkg/network"
 	"knative.dev/serving/pkg/apis/serving/v1alpha1"
 )
 
@@ -49,7 +48,7 @@ func TestMakeIngress(t *testing.T) {
 		},
 	}
 
-	got := MakeIngress(dm, "the-ingress-class")
+	got := MakeIngress(dm, "the-target-svc", "the-rewrite-host", "the-ingress-class")
 
 	want := &netv1alpha1.Ingress{
 		ObjectMeta: metav1.ObjectMeta{
@@ -67,14 +66,14 @@ func TestMakeIngress(t *testing.T) {
 				Visibility: netv1alpha1.IngressVisibilityExternalIP,
 				HTTP: &netv1alpha1.HTTPIngressRuleValue{
 					Paths: []netv1alpha1.HTTPIngressPath{{
-						RewriteHost: pkgnetwork.GetServiceHostname("the-name", "the-namespace"),
+						RewriteHost: "the-rewrite-host",
 						Splits: []netv1alpha1.IngressBackendSplit{{
 							Percent: 100,
 							AppendHeaders: map[string]string{
 								network.OriginalHostHeader: "mapping.com",
 							},
 							IngressBackend: netv1alpha1.IngressBackend{
-								ServiceName:      "the-name",
+								ServiceName:      "the-target-svc",
 								ServiceNamespace: "the-namespace",
 								ServicePort:      intstr.FromInt(80),
 							},
diff --git a/pkg/reconciler/domainmapping/table_test.go b/pkg/reconciler/domainmapping/table_test.go
index cff041d2e..37d5bf42c 100644
--- a/pkg/reconciler/domainmapping/table_test.go
+++ b/pkg/reconciler/domainmapping/table_test.go
@@ -37,12 +37,15 @@ import (
 	"knative.dev/pkg/logging"
 	pkgnetwork "knative.dev/pkg/network"
 	pkgreconciler "knative.dev/pkg/reconciler"
+	"knative.dev/pkg/resolver"
+	servingv1 "knative.dev/serving/pkg/apis/serving/v1"
 	"knative.dev/serving/pkg/apis/serving/v1alpha1"
 	servingclient "knative.dev/serving/pkg/client/injection/client/fake"
 	domainmappingreconciler "knative.dev/serving/pkg/client/injection/reconciler/serving/v1alpha1/domainmapping"
 	"knative.dev/serving/pkg/reconciler/domainmapping/config"
 	"knative.dev/serving/pkg/reconciler/domainmapping/resources"
 
+	"knative.dev/pkg/client/injection/ducks/duck/v1/addressable"
 	. "knative.dev/pkg/reconciler/testing"
 	. "knative.dev/serving/pkg/reconciler/testing/v1"
 	. "knative.dev/serving/pkg/testing"
@@ -61,6 +64,7 @@ func TestReconcile(t *testing.T) {
 		Name: "first reconcile",
 		Key:  "default/first-reconcile.com",
 		Objects: []runtime.Object{
+			ksvc("default", "target", "the-target-svc.default.svc.cluster.local", ""),
 			domainMapping("default", "first-reconcile.com", withRef("default", "target")),
 		},
 		WantStatusUpdates: []clientgotesting.UpdateActionImpl{{
@@ -77,15 +81,115 @@ func TestReconcile(t *testing.T) {
 		SkipNamespaceValidation: true, // allow creation of ClusterDomainClaim.
 		WantCreates: []runtime.Object{
 			resources.MakeDomainClaim(domainMapping("default", "first-reconcile.com", withRef("default", "target"))),
-			resources.MakeIngress(domainMapping("default", "first-reconcile.com", withRef("default", "target")), "the-ingress-class"),
+			resources.MakeIngress(domainMapping("default", "first-reconcile.com", withRef("default", "target")), "the-target-svc", "the-target-svc.default.svc.cluster.local", "the-ingress-class"),
 		},
 		WantEvents: []string{
 			Eventf(corev1.EventTypeNormal, "Created", "Created Ingress %q", "first-reconcile.com"),
 		},
+	}, {
+		Name: "first reconcile, ref does not exist",
+		Key:  "default/first-reconcile.com",
+		Objects: []runtime.Object{
+			domainMapping("default", "first-reconcile.com", withRef("default", "target")),
+		},
+		WantErr: true,
+		WantStatusUpdates: []clientgotesting.UpdateActionImpl{{
+			Object: domainMapping("default", "first-reconcile.com",
+				withRef("default", "target"),
+				withURL("http", "first-reconcile.com"),
+				withAddress("http", "first-reconcile.com"),
+				withInitDomainMappingConditions,
+				withDomainClaimed,
+				withReferenceNotResolved(`services.serving.knative.dev "target" not found`),
+			),
+		}},
+		SkipNamespaceValidation: true, // allow creation of ClusterDomainClaim.
+		WantCreates: []runtime.Object{
+			resources.MakeDomainClaim(domainMapping("default", "first-reconcile.com", withRef("default", "target"))),
+		},
+		WantEvents: []string{
+			Eventf(corev1.EventTypeWarning, "InternalError", `resolving reference: services.serving.knative.dev "target" not found`),
+		},
+	}, {
+		Name: "first reconcile, ref has a path",
+		Key:  "default/first-reconcile.com",
+		Objects: []runtime.Object{
+			ksvc("default", "target", "the-target-svc.svc.cluster.local", "path"),
+			domainMapping("default", "first-reconcile.com", withRef("default", "target")),
+		},
+		WantErr: true,
+		WantStatusUpdates: []clientgotesting.UpdateActionImpl{{
+			Object: domainMapping("default", "first-reconcile.com",
+				withRef("default", "target"),
+				withURL("http", "first-reconcile.com"),
+				withAddress("http", "first-reconcile.com"),
+				withInitDomainMappingConditions,
+				withDomainClaimed,
+				withReferenceNotResolved(`resolved URI "http://the-target-svc.svc.cluster.local/path" contains a path`),
+			),
+		}},
+		SkipNamespaceValidation: true, // allow creation of ClusterDomainClaim.
+		WantCreates: []runtime.Object{
+			resources.MakeDomainClaim(domainMapping("default", "first-reconcile.com", withRef("default", "target"))),
+		},
+		WantEvents: []string{
+			Eventf(corev1.EventTypeWarning, "InternalError", `resolved URI "http://the-target-svc.svc.cluster.local/path" contains a path`),
+		},
+	}, {
+		Name: "first reconcile, ref doesn't end in cluster suffix",
+		Key:  "default/first-reconcile.com",
+		Objects: []runtime.Object{
+			ksvc("default", "target", "notasvc.cluster.local", ""),
+			domainMapping("default", "first-reconcile.com", withRef("default", "target")),
+		},
+		WantErr: true,
+		WantStatusUpdates: []clientgotesting.UpdateActionImpl{{
+			Object: domainMapping("default", "first-reconcile.com",
+				withRef("default", "target"),
+				withURL("http", "first-reconcile.com"),
+				withAddress("http", "first-reconcile.com"),
+				withInitDomainMappingConditions,
+				withDomainClaimed,
+				withReferenceNotResolved(`resolved URI "http://notasvc.cluster.local" must be of the form {name}.{namespace}.svc.cluster.local`),
+			),
+		}},
+		SkipNamespaceValidation: true, // allow creation of ClusterDomainClaim.
+		WantCreates: []runtime.Object{
+			resources.MakeDomainClaim(domainMapping("default", "first-reconcile.com", withRef("default", "target"))),
+		},
+		WantEvents: []string{
+			Eventf(corev1.EventTypeWarning, "InternalError", `resolved URI "http://notasvc.cluster.local" must be of the form {name}.{namespace}.svc.cluster.local`),
+		},
+	}, {
+		Name: "first reconcile, resolved URL in wrong namespace",
+		Key:  "default/first-reconcile.com",
+		Objects: []runtime.Object{
+			ksvc("default", "target", "name.anothernamespace.svc.cluster.local", ""),
+			domainMapping("default", "first-reconcile.com", withRef("default", "target")),
+		},
+		WantErr: true,
+		WantStatusUpdates: []clientgotesting.UpdateActionImpl{{
+			Object: domainMapping("default", "first-reconcile.com",
+				withRef("default", "target"),
+				withURL("http", "first-reconcile.com"),
+				withAddress("http", "first-reconcile.com"),
+				withInitDomainMappingConditions,
+				withDomainClaimed,
+				withReferenceNotResolved(`resolved URI "http://name.anothernamespace.svc.cluster.local" must be in same namespace as DomainMapping`),
+			),
+		}},
+		SkipNamespaceValidation: true, // allow creation of ClusterDomainClaim.
+		WantCreates: []runtime.Object{
+			resources.MakeDomainClaim(domainMapping("default", "first-reconcile.com", withRef("default", "target"))),
+		},
+		WantEvents: []string{
+			Eventf(corev1.EventTypeWarning, "InternalError", `resolved URI "http://name.anothernamespace.svc.cluster.local" must be in same namespace as DomainMapping`),
+		},
 	}, {
 		Name: "first reconcile, pre-owned domain claim",
 		Key:  "default/first-reconcile.com",
 		Objects: []runtime.Object{
+			ksvc("default", "target", "the-target-svc.default.svc.cluster.local", ""),
 			domainMapping("default", "first-reconcile.com", withRef("default", "target")),
 			resources.MakeDomainClaim(domainMapping("default", "first-reconcile.com", withRef("default", "target"))),
 		},
@@ -101,7 +205,7 @@ func TestReconcile(t *testing.T) {
 			),
 		}},
 		WantCreates: []runtime.Object{
-			resources.MakeIngress(domainMapping("default", "first-reconcile.com", withRef("default", "target")), "the-ingress-class"),
+			resources.MakeIngress(domainMapping("default", "first-reconcile.com", withRef("default", "target")), "the-target-svc", "the-target-svc.default.svc.cluster.local", "the-ingress-class"),
 		},
 		WantEvents: []string{
 			Eventf(corev1.EventTypeNormal, "Created", "Created Ingress %q", "first-reconcile.com"),
@@ -160,6 +264,7 @@ func TestReconcile(t *testing.T) {
 		Name: "reconcile with ingressClass annotation",
 		Key:  "default/ingressclass.first-reconcile.com",
 		Objects: []runtime.Object{
+			ksvc("default", "target", "the-target-svc.default.svc.cluster.local", ""),
 			domainMapping("default", "ingressclass.first-reconcile.com", withRef("default", "target"),
 				withAnnotations(map[string]string{
 					networking.IngressClassAnnotationKey: "overridden-ingress-class",
@@ -184,7 +289,7 @@ func TestReconcile(t *testing.T) {
 		WantCreates: []runtime.Object{
 			resources.MakeDomainClaim(domainMapping("default", "ingressclass.first-reconcile.com", withRef("default", "target"))),
 			resources.MakeIngress(domainMapping("default", "ingressclass.first-reconcile.com", withRef("default", "target")),
-				"overridden-ingress-class"),
+				"the-target-svc", "the-target-svc.default.svc.cluster.local", "overridden-ingress-class"),
 		},
 		WantEvents: []string{
 			Eventf(corev1.EventTypeNormal, "Created", "Created Ingress %q", "ingressclass.first-reconcile.com"),
@@ -193,9 +298,10 @@ func TestReconcile(t *testing.T) {
 		Name: "reconcile changed ref",
 		Key:  "default/ingress-exists.org",
 		Objects: []runtime.Object{
+			ksvc("default", "changed", "changed.default.svc.cluster.local", ""),
 			domainMapping("default", "ingress-exists.org", withRef("default", "changed")),
-			resources.MakeIngress(domainMapping("default", "ingress-exists.org", withRef("default", "target")), "the-ingress-class"),
-			resources.MakeDomainClaim(domainMapping("default", "ingress-exists.org", withRef("default", "target"))),
+			resources.MakeIngress(domainMapping("default", "ingress-exists.org", withRef("default", "changed")), "previous", "previous.default.svc.cluster.local", "the-ingress-class"),
+			resources.MakeDomainClaim(domainMapping("default", "ingress-exists.org", withRef("default", "changed"))),
 		},
 		WantStatusUpdates: []clientgotesting.UpdateActionImpl{{
 			Object: domainMapping("default", "ingress-exists.org",
@@ -215,6 +321,7 @@ func TestReconcile(t *testing.T) {
 		Name: "reconcile failed ingress",
 		Key:  "default/ingress-failed.me",
 		Objects: []runtime.Object{
+			ksvc("default", "failed", "failed.default.svc.cluster.local", ""),
 			domainMapping("default", "ingress-failed.me",
 				withRef("default", "failed"),
 				withURL("http", "ingress-failed.me"),
@@ -223,7 +330,7 @@ func TestReconcile(t *testing.T) {
 			ingress(domainMapping("default", "ingress-failed.me", withRef("default", "failed")), "the-ingress-class",
 				WithLoadbalancerFailed("fell over", "hurt myself"),
 			),
-			resources.MakeDomainClaim(domainMapping("default", "ingress-failed.me", withRef("default", "target"))),
+			resources.MakeDomainClaim(domainMapping("default", "ingress-failed.me", withRef("default", "failed"))),
 		},
 		WantStatusUpdates: []clientgotesting.UpdateActionImpl{{
 			Object: domainMapping("default", "ingress-failed.me",
@@ -233,13 +340,14 @@ func TestReconcile(t *testing.T) {
 				withInitDomainMappingConditions,
 				withDomainClaimed,
 				withReferenceResolved,
-				withPropagatedStatus(ingress(domainMapping("default", "ingress-failed.me"), "", WithLoadbalancerFailed("fell over", "hurt myself")).Status),
+				withPropagatedStatus(ingress(domainMapping("default", "failed.default.svc.cluster.local"), "", WithLoadbalancerFailed("fell over", "hurt myself")).Status),
 			),
 		}},
 	}, {
 		Name: "reconcile unknown ingress",
 		Key:  "default/ingress-unknown.me",
 		Objects: []runtime.Object{
+			ksvc("default", "unknown", "unknown.default.svc.cluster.local", ""),
 			domainMapping("default", "ingress-unknown.me", withRef("default", "unknown"),
 				withRef("default", "unknown"),
 				withURL("http", "ingress-unknown.me"),
@@ -265,6 +373,7 @@ func TestReconcile(t *testing.T) {
 		Name: "reconcile ready ingress",
 		Key:  "default/ingress-ready.me",
 		Objects: []runtime.Object{
+			ksvc("default", "ready", "ready.default.svc.cluster.local", ""),
 			domainMapping("default", "ingress-ready.me",
 				withRef("default", "ready"),
 				withURL("http", "ingress-ready.me"),
@@ -293,6 +402,7 @@ func TestReconcile(t *testing.T) {
 			InduceFailure("create", "ingresses"),
 		},
 		Objects: []runtime.Object{
+			ksvc("default", "cantcreate", "cantcreate.default.svc.cluster.local", ""),
 			domainMapping("default", "cantcreate.this",
 				withRef("default", "cantcreate"),
 				withURL("http", "cantcreate.this"),
@@ -333,6 +443,7 @@ func TestReconcile(t *testing.T) {
 			InduceFailure("update", "ingresses"),
 		},
 		Objects: []runtime.Object{
+			ksvc("default", "cantupdate", "cantupdate.default.svc.cluster.local", ""),
 			domainMapping("default", "cantupdate.this",
 				withRef("default", "cantupdate"),
 				withURL("http", "cantupdate.this"),
@@ -369,9 +480,11 @@ func TestReconcile(t *testing.T) {
 	}}
 
 	table.Test(t, MakeFactory(func(ctx context.Context, listers *Listers, cmw configmap.Watcher) controller.Reconciler {
+		ctx = addressable.WithDuck(ctx)
 		r := &Reconciler{
 			netclient:     networkingclient.Get(ctx),
 			ingressLister: listers.GetIngressLister(),
+			resolver:      resolver.NewURIResolver(ctx, func(types.NamespacedName) {}),
 		}
 
 		return domainmappingreconciler.NewReconciler(ctx, logging.FromContext(ctx),
@@ -464,6 +577,12 @@ func withReferenceResolved(dm *v1alpha1.DomainMapping) {
 	dm.Status.MarkReferenceResolved()
 }
 
+func withReferenceNotResolved(message string) domainMappingOption {
+	return func(dm *v1alpha1.DomainMapping) {
+		dm.Status.MarkReferenceNotResolved(message)
+	}
+}
+
 func withGeneration(generation int64) domainMappingOption {
 	return func(dm *v1alpha1.DomainMapping) {
 		dm.Generation = generation
@@ -475,7 +594,7 @@ func withObservedGeneration(dm *v1alpha1.DomainMapping) {
 }
 
 func ingress(dm *v1alpha1.DomainMapping, ingressClass string, opt ...IngressOption) *netv1alpha1.Ingress {
-	ing := resources.MakeIngress(dm, ingressClass)
+	ing := resources.MakeIngress(dm, dm.Spec.Ref.Name, dm.Spec.Ref.Name+"."+dm.Spec.Ref.Namespace+".svc.cluster.local", ingressClass)
 	for _, o := range opt {
 		o(ing)
 	}
@@ -499,6 +618,26 @@ func withIngressReady(ing *netv1alpha1.Ingress) {
 	ing.Status = status
 }
 
+func ksvc(ns, name, host, path string) *servingv1.Service {
+	return &servingv1.Service{
+		ObjectMeta: metav1.ObjectMeta{
+			Name:      name,
+			Namespace: ns,
+		},
+		Status: servingv1.ServiceStatus{
+			RouteStatusFields: servingv1.RouteStatusFields{
+				Address: &duckv1.Addressable{
+					URL: &apis.URL{
+						Scheme: "http",
+						Host:   host,
+						Path:   path,
+					},
+				},
+			},
+		},
+	}
+}
+
 func withIngressNotReady(ing *netv1alpha1.Ingress) {
 	ing.Status.MarkIngressNotReady("progressing", "hold your horses")
 }
diff --git a/pkg/reconciler/route/traffic/rollout_test.go b/pkg/reconciler/route/traffic/rollout_test.go
index 6a7e51d4e..447e97aad 100644
--- a/pkg/reconciler/route/traffic/rollout_test.go
+++ b/pkg/reconciler/route/traffic/rollout_test.go
@@ -22,9 +22,11 @@ limitations under the License.
 package traffic
 
 import (
+	"encoding/json"
 	"testing"
 
 	"github.com/google/go-cmp/cmp"
+	"github.com/google/go-cmp/cmp/cmpopts"
 )
 
 func TestStep(t *testing.T) {
@@ -74,6 +76,10 @@ func TestStep(t *testing.T) {
 					RevisionName: "let-it-bleed",
 					Percent:      100,
 				}},
+				Deadline:     2006, // <- Those should be ignored.
+				LastStepTime: 2009,
+				StepDuration: 2020,
+				StartTime:    2004,
 			}},
 		},
 		prev: &Rollout{
@@ -84,6 +90,10 @@ func TestStep(t *testing.T) {
 					RevisionName: "let-it-bleed",
 					Percent:      100,
 				}},
+				Deadline:     1982, // <- Those should be copied.
+				LastStepTime: 1984,
+				StepDuration: 1988,
+				StartTime:    1955,
 			}},
 		},
 		want: &Rollout{
@@ -94,6 +104,10 @@ func TestStep(t *testing.T) {
 					RevisionName: "let-it-bleed",
 					Percent:      100,
 				}},
+				Deadline:     1982,
+				LastStepTime: 1984,
+				StepDuration: 1988,
+				StartTime:    1955,
 			}},
 		},
 	}, {
@@ -178,6 +192,9 @@ func TestStep(t *testing.T) {
 					RevisionName: "goat-head-soup",
 					Percent:      100,
 				}},
+				Deadline:     1982, // <- Those should be thrown out.
+				LastStepTime: 1984,
+				StepDuration: 1988,
 			}},
 		},
 		want: &Rollout{
@@ -661,7 +678,7 @@ func TestStep(t *testing.T) {
 	for _, tc := range tests {
 		t.Run(tc.name, func(t *testing.T) {
 			got := tc.cur.Step(tc.prev)
-			if want := tc.want; !cmp.Equal(got, want) {
+			if want := tc.want; !cmp.Equal(got, want, cmpopts.EquateEmpty()) {
 				t.Errorf("Wrong rolled rollout, diff(-want,+got):\n%s", cmp.Diff(want, got))
 			}
 			if !got.Validate() {
@@ -786,12 +803,11 @@ func TestAdjustPercentage(t *testing.T) {
 				Percent: 60,
 			}},
 		},
-		want: []RevisionRollout{},
 	}}
 	for _, tc := range tests {
 		t.Run(tc.name, func(t *testing.T) {
 			adjustPercentage(tc.goal, tc.prev)
-			if got, want := tc.prev.Revisions, tc.want; !cmp.Equal(got, want) {
+			if got, want := tc.prev.Revisions, tc.want; !cmp.Equal(got, want, cmpopts.EquateEmpty()) {
 				t.Errorf("Rollout Mistmatch(-want,+got):\n%s", cmp.Diff(want, got))
 			}
 		})
@@ -872,3 +888,84 @@ func TestValidateFailures(t *testing.T) {
 	}
 
 }
+
+func TestConfigDone(t *testing.T) {
+	r := &Rollout{
+		Configurations: []ConfigurationRollout{{
+			ConfigurationName: "one",
+			Percent:           100,
+			Revisions: []RevisionRollout{{
+				RevisionName: "roy",
+				Percent:      100,
+			}},
+		}, {
+			ConfigurationName: "no",
+			Percent:           0,
+			Revisions:         []RevisionRollout{},
+		}, {
+			ConfigurationName: "many",
+			Percent:           100,
+			Revisions: []RevisionRollout{{
+				RevisionName: "black-on-blue",
+				Percent:      83,
+			}, {
+				RevisionName: "flowers",
+				Percent:      17,
+			}},
+		}},
+	}
+	if !r.Configurations[0].Done() {
+		t.Error("Single revision rollout is not `Done`")
+	}
+	if !r.Configurations[1].Done() {
+		t.Error("Zero revisions rollout is not `Done`")
+	}
+	if r.Configurations[2].Done() {
+		t.Error("Many revisions rollout is `Done`")
+	}
+}
+
+func TestJSONRoundtrip(t *testing.T) {
+	orig := &Rollout{
+		Configurations: []ConfigurationRollout{{
+			ConfigurationName: "one",
+			Percent:           100,
+			Revisions: []RevisionRollout{{
+				RevisionName: "roy",
+				Percent:      100,
+			}},
+			StartTime:    1955,
+			Deadline:     2006,
+			LastStepTime: 1988,
+			StepDuration: 1984,
+		}, {
+			ConfigurationName: "no",
+			Percent:           0,
+			Revisions:         []RevisionRollout{},
+		}, {
+			ConfigurationName: "many",
+			Percent:           100,
+			Revisions: []RevisionRollout{{
+				RevisionName: "black-on-blue",
+				Percent:      83,
+			}, {
+				RevisionName: "flowers",
+				Percent:      17,
+			}},
+		}},
+	}
+
+	ss, err := json.Marshal(orig)
+	if err != nil {
+		t.Fatal("Error serializing the rollout:", err)
+	}
+	deserialized := &Rollout{}
+	err = json.Unmarshal(ss, deserialized)
+	if err != nil {
+		t.Fatal("Error deserializing proper JSON:", err)
+	}
+	if !cmp.Equal(deserialized, orig, cmpopts.EquateEmpty()) {
+		t.Errorf("JSON roundtrip mismatch:(-want,+got)\n%s",
+			cmp.Diff(orig, deserialized, cmpopts.EquateEmpty()))
+	}
+}
diff --git a/pkg/reconciler/service/resources/configuration_test.go b/pkg/reconciler/service/resources/configuration_test.go
index 00ff26b1e..52634a8c8 100644
--- a/pkg/reconciler/service/resources/configuration_test.go
+++ b/pkg/reconciler/service/resources/configuration_test.go
@@ -21,6 +21,7 @@ import (
 	"strings"
 	"testing"
 
+	"github.com/google/go-cmp/cmp"
 	corev1 "k8s.io/api/core/v1"
 
 	"knative.dev/serving/pkg/apis/serving"
@@ -28,56 +29,57 @@ import (
 
 func TestConfigurationSpec(t *testing.T) {
 	s := createService()
-	c, _ := MakeConfiguration(s)
+	c := MakeConfiguration(s)
 	if got, want := c.Name, testServiceName; got != want {
-		t.Errorf("expected %q for service name got %q", want, got)
+		t.Errorf("Service name = %q; want: %q", got, want)
 	}
 	if got, want := c.Namespace, testServiceNamespace; got != want {
-		t.Errorf("expected %q for service namespace got %q", want, got)
+		t.Errorf("Service namespace = %q; want: %q", got, want)
 	}
 	if got, want := c.Spec.GetTemplate().Spec.GetContainer().Name, testContainerName; got != want {
-		t.Errorf("expected %q for container name got %q", want, got)
+		t.Errorf("Container name = %q; want: %q", got, want)
 	}
 	expectOwnerReferencesSetCorrectly(t, c.OwnerReferences)
 
-	if got, want := len(c.Labels), 1; got != want {
-		t.Errorf("expected %d labels got %d", want, got)
+	if got, want := c.Labels, map[string]string{serving.ServiceLabelKey: testServiceName}; !cmp.Equal(got, want) {
+		t.Errorf("Labels mismatch: diff(-want,+got):\n%s", cmp.Diff(want, got))
 	}
-	if got, want := c.Labels[serving.ServiceLabelKey], testServiceName; got != want {
-		t.Errorf("expected %q labels got %q", want, got)
-	}
-	if got, want := c.Annotations[serving.RoutesAnnotationKey], testServiceName; got != want {
-		t.Errorf("expected %q annotations got %q", want, got)
+	if got, want := c.Annotations, map[string]string{
+		serving.RoutesAnnotationKey: testServiceName,
+	}; !cmp.Equal(got, want) {
+		t.Errorf("Annotations mismatch: diff(-want,+got):\n%s", cmp.Diff(want, got))
 	}
 
 	// Create the configuration based on the same existing configuration.
-	c, _ = MakeConfigurationFromExisting(s, c)
-	if got, want := c.Annotations[serving.RoutesAnnotationKey], testServiceName; got != want {
-		t.Errorf("expected %q annotations got %q", want, got)
+	c = MakeConfigurationFromExisting(s, c)
+	if got, want := c.Annotations, map[string]string{
+		serving.RoutesAnnotationKey: testServiceName,
+	}; !cmp.Equal(got, want) {
+		t.Errorf("Annotations mismatch: diff(-want,+got):\n%s", cmp.Diff(want, got))
 	}
 
 	// Create the configuration based on the configuration with a different value for the
 	// annotation key serving.RoutesAnnotationKey.
-	secTestServiceName := "second-test-service"
-	secondSer := createServiceWithName(secTestServiceName)
-	secondConfig, _ := MakeConfigurationFromExisting(secondSer, c)
+	const secTestServiceName = "second-test-service"
+	secondConfig := MakeConfigurationFromExisting(
+		createServiceWithName(secTestServiceName), c)
+
+	// MakeConfigurationFromExisting employs maps in process, so order is
+	// not guaranteed.
 	annoValue := secondConfig.Annotations[serving.RoutesAnnotationKey]
-	annoArray := strings.Split(annoValue, ",")
-	sort.Strings(annoArray)
-	expectedAnnoArray := []string{secTestServiceName, testServiceName}
-	sort.Strings(expectedAnnoArray)
-	if got, want := strings.Join(annoArray, ","), strings.Join(expectedAnnoArray, ","); got != want {
-		t.Errorf("expected %q annotations got %q", want, got)
+	got := strings.Split(annoValue, ",")
+	sort.Strings(got)
+
+	want := []string{secTestServiceName, testServiceName}
+	if !cmp.Equal(got, want) {
+		t.Errorf("Annotations = %v, want: %v", got, want)
 	}
 }
 
 func TestConfigurationHasNoKubectlAnnotation(t *testing.T) {
 	s := createServiceWithKubectlAnnotation()
-	c, err := MakeConfiguration(s)
-	if err != nil {
-		t.Fatal("Unexpected error:", err)
-	}
+	c := MakeConfiguration(s)
 	if v, ok := c.Annotations[corev1.LastAppliedConfigAnnotation]; ok {
-		t.Errorf("Annotation %s = %q, want empty", corev1.LastAppliedConfigAnnotation, v)
+		t.Errorf(`Annotation[%s] = %q, want: ""`, corev1.LastAppliedConfigAnnotation, v)
 	}
 }
diff --git a/pkg/reconciler/service/resources/route_test.go b/pkg/reconciler/service/resources/route_test.go
index f153e9211..5a73b6ecb 100644
--- a/pkg/reconciler/service/resources/route_test.go
+++ b/pkg/reconciler/service/resources/route_test.go
@@ -31,10 +31,7 @@ import (
 func TestRouteSpec(t *testing.T) {
 	s := createService()
 	testConfigName := names.Configuration(s)
-	r, err := MakeRoute(s)
-	if err != nil {
-		t.Fatal("Unexpected error:", err)
-	}
+	r := MakeRoute(s)
 	if got, want := r.Name, testServiceName; got != want {
 		t.Errorf("Expected %q for service name got %q", want, got)
 	}
@@ -64,10 +61,7 @@ func TestRouteSpec(t *testing.T) {
 
 func TestRouteHasNoKubectlAnnotation(t *testing.T) {
 	s := createServiceWithKubectlAnnotation()
-	r, err := MakeRoute(s)
-	if err != nil {
-		t.Fatal("Unexpected error:", err)
-	}
+	r := MakeRoute(s)
 	if v, ok := r.Annotations[corev1.LastAppliedConfigAnnotation]; ok {
 		t.Errorf("Annotation %s = %q, want empty", corev1.LastAppliedConfigAnnotation, v)
 	}
diff --git a/pkg/reconciler/service/resources/shared_test.go b/pkg/reconciler/service/resources/shared_test.go
index 95af88ce1..c2e929095 100644
--- a/pkg/reconciler/service/resources/shared_test.go
+++ b/pkg/reconciler/service/resources/shared_test.go
@@ -40,7 +40,7 @@ const (
 func expectOwnerReferencesSetCorrectly(t *testing.T, ownerRefs []metav1.OwnerReference) {
 	t.Helper()
 	if got, want := len(ownerRefs), 1; got != want {
-		t.Errorf("expected %d owner refs got %d", want, got)
+		t.Errorf("|Owner refs| = %d, want: %d", got, want)
 		return
 	}
 
diff --git a/pkg/reconciler/service/service_test.go b/pkg/reconciler/service/service_test.go
index e2ba1b80a..91efb9e47 100644
--- a/pkg/reconciler/service/service_test.go
+++ b/pkg/reconciler/service/service_test.go
@@ -19,7 +19,6 @@ package service
 import (
 	"context"
 	"errors"
-	"fmt"
 	"testing"
 
 	// Install our fake informers
@@ -821,10 +820,7 @@ func TestNew(t *testing.T) {
 func config(name, namespace string, so ServiceOption, co ...ConfigOption) *v1.Configuration {
 	s := DefaultService(name, namespace, so)
 	s.SetDefaults(context.Background())
-	cfg, err := resources.MakeConfiguration(s)
-	if err != nil {
-		panic(fmt.Sprint("MakeConfiguration() = ", err))
-	}
+	cfg := resources.MakeConfiguration(s)
 	for _, opt := range co {
 		opt(cfg)
 	}
@@ -834,10 +830,7 @@ func config(name, namespace string, so ServiceOption, co ...ConfigOption) *v1.Co
 func route(name, namespace string, so ServiceOption, ro ...RouteOption) *v1.Route {
 	s := DefaultService(name, namespace, so)
 	s.SetDefaults(context.Background())
-	route, err := resources.MakeRoute(s)
-	if err != nil {
-		panic(fmt.Sprint("MakeRoute() = ", err))
-	}
+	route := resources.MakeRoute(s)
 	for _, opt := range ro {
 		opt(route)
 	}
diff --git a/test/config/chaosduck.yaml b/test/config/chaosduck.yaml
index eda81fa76..2c5d5a1f4 100644
--- a/test/config/chaosduck.yaml
+++ b/test/config/chaosduck.yaml
@@ -86,9 +86,6 @@ spec:
         # Disable chaos on webhooks until https://github.com/knative/pkg/issues/1509 is
         # sorted out.
         - "-disable=webhook"
-        # Currently the new owner of Autoscaler needs time to build the metrics status
-        # so some e2e tests are expected to fail if the owner pod crashes.
-        - "-disable=autoscaler"
         env:
         - name: SYSTEM_NAMESPACE
           valueFrom:
diff --git a/test/conformance/api/v1/blue_green_test.go b/test/conformance/api/v1/blue_green_test.go
index 452708255..9ab7efaff 100644
--- a/test/conformance/api/v1/blue_green_test.go
+++ b/test/conformance/api/v1/blue_green_test.go
@@ -30,6 +30,7 @@ import (
 
 	"knative.dev/pkg/ptr"
 	pkgTest "knative.dev/pkg/test"
+	"knative.dev/pkg/test/spoof"
 	v1 "knative.dev/serving/pkg/apis/serving/v1"
 	rtesting "knative.dev/serving/pkg/testing/v1"
 	"knative.dev/serving/test"
@@ -134,7 +135,7 @@ func TestBlueGreenRoute(t *testing.T) {
 		clients.KubeClient,
 		t.Logf,
 		greenURL,
-		v1test.RetryingRouteInconsistency(pkgTest.IsStatusOK),
+		v1test.RetryingRouteInconsistency(spoof.IsStatusOK),
 		"WaitForSuccessfulResponse",
 		test.ServingFlags.ResolvableDomain,
 		test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.HTTPS)); err != nil {
diff --git a/test/conformance/api/v1/generatename_test.go b/test/conformance/api/v1/generatename_test.go
index b98c7a0c8..468be7d40 100644
--- a/test/conformance/api/v1/generatename_test.go
+++ b/test/conformance/api/v1/generatename_test.go
@@ -26,6 +26,7 @@ import (
 	"testing"
 
 	pkgTest "knative.dev/pkg/test"
+	"knative.dev/pkg/test/spoof"
 	v1 "knative.dev/serving/pkg/apis/serving/v1"
 	rtesting "knative.dev/serving/pkg/testing/v1"
 	"knative.dev/serving/test"
@@ -98,7 +99,7 @@ func canServeRequests(t *testing.T, clients *test.Clients, route *v1.Route) erro
 		clients.KubeClient,
 		t.Logf,
 		url,
-		v1test.RetryingRouteInconsistency(pkgTest.MatchesAllOf(pkgTest.IsStatusOK, pkgTest.MatchesBody(test.HelloWorldText))),
+		v1test.RetryingRouteInconsistency(spoof.MatchesAllOf(spoof.IsStatusOK, spoof.MatchesBody(test.HelloWorldText))),
 		"WaitForEndpointToServeText",
 		test.ServingFlags.ResolvableDomain,
 		test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.HTTPS))
diff --git a/test/conformance/api/v1/resources_test.go b/test/conformance/api/v1/resources_test.go
index 9f86a74de..85ea0f533 100644
--- a/test/conformance/api/v1/resources_test.go
+++ b/test/conformance/api/v1/resources_test.go
@@ -68,7 +68,7 @@ func TestCustomResourcesLimits(t *testing.T) {
 		clients.KubeClient,
 		t.Logf,
 		endpoint,
-		v1test.RetryingRouteInconsistency(pkgTest.MatchesAllOf(pkgTest.IsStatusOK)),
+		v1test.RetryingRouteInconsistency(spoof.MatchesAllOf(spoof.IsStatusOK)),
 		"ResourceTestServesText",
 		test.ServingFlags.ResolvableDomain,
 		test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.HTTPS))
diff --git a/test/conformance/api/v1/revision_timeout_test.go b/test/conformance/api/v1/revision_timeout_test.go
index 211a64c91..0de473f1e 100644
--- a/test/conformance/api/v1/revision_timeout_test.go
+++ b/test/conformance/api/v1/revision_timeout_test.go
@@ -27,6 +27,7 @@ import (
 	"time"
 
 	pkgTest "knative.dev/pkg/test"
+	"knative.dev/pkg/test/spoof"
 	resourcenames "knative.dev/serving/pkg/reconciler/revision/resources/names"
 	"knative.dev/serving/test"
 	"knative.dev/serving/test/conformance/api/shared"
@@ -130,7 +131,7 @@ func TestRevisionTimeout(t *testing.T) {
 					clients.KubeClient,
 					t.Logf,
 					serviceURL,
-					v1test.RetryingRouteInconsistency(pkgTest.IsOneOfStatusCodes(http.StatusOK, http.StatusGatewayTimeout)),
+					v1test.RetryingRouteInconsistency(spoof.IsOneOfStatusCodes(http.StatusOK, http.StatusGatewayTimeout)),
 					"WaitForSuccessfulResponse",
 					test.ServingFlags.ResolvableDomain,
 					test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.HTTPS)); err != nil {
diff --git a/test/conformance/api/v1/route_test.go b/test/conformance/api/v1/route_test.go
index 6bf332a0d..a1eba289e 100644
--- a/test/conformance/api/v1/route_test.go
+++ b/test/conformance/api/v1/route_test.go
@@ -24,6 +24,7 @@ import (
 	"testing"
 
 	pkgTest "knative.dev/pkg/test"
+	"knative.dev/pkg/test/spoof"
 	v1 "knative.dev/serving/pkg/apis/serving/v1"
 	"knative.dev/serving/test"
 	v1test "knative.dev/serving/test/v1"
@@ -45,7 +46,7 @@ func assertResourcesUpdatedWhenRevisionIsReady(t *testing.T, clients *test.Clien
 		clients.KubeClient,
 		t.Logf,
 		url,
-		v1test.RetryingRouteInconsistency(pkgTest.MatchesAllOf(pkgTest.IsStatusOK, pkgTest.EventuallyMatchesBody(expectedText))),
+		v1test.RetryingRouteInconsistency(spoof.MatchesAllOf(spoof.IsStatusOK, pkgTest.EventuallyMatchesBody(expectedText))),
 		"WaitForEndpointToServeText",
 		test.ServingFlags.ResolvableDomain,
 		test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.HTTPS))
diff --git a/test/conformance/api/v1/single_threaded_test.go b/test/conformance/api/v1/single_threaded_test.go
index 7d58ba7e4..35093d8b3 100644
--- a/test/conformance/api/v1/single_threaded_test.go
+++ b/test/conformance/api/v1/single_threaded_test.go
@@ -29,6 +29,7 @@ import (
 	"golang.org/x/sync/errgroup"
 
 	pkgTest "knative.dev/pkg/test"
+	"knative.dev/pkg/test/spoof"
 	"knative.dev/serving/test"
 	v1test "knative.dev/serving/test/v1"
 
@@ -59,7 +60,7 @@ func TestSingleConcurrency(t *testing.T) {
 		clients.KubeClient,
 		t.Logf,
 		url,
-		v1test.RetryingRouteInconsistency(pkgTest.IsStatusOK),
+		v1test.RetryingRouteInconsistency(spoof.IsStatusOK),
 		"WaitForSuccessfulResponse",
 		test.ServingFlags.ResolvableDomain,
 		test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.HTTPS)); err != nil {
diff --git a/test/conformance/api/v1/util.go b/test/conformance/api/v1/util.go
index 5d5f9d6f0..cebae4ec1 100644
--- a/test/conformance/api/v1/util.go
+++ b/test/conformance/api/v1/util.go
@@ -27,6 +27,7 @@ import (
 	"golang.org/x/sync/errgroup"
 
 	pkgTest "knative.dev/pkg/test"
+	"knative.dev/pkg/test/spoof"
 	"knative.dev/serving/pkg/apis/serving"
 	v1 "knative.dev/serving/pkg/apis/serving/v1"
 	"knative.dev/serving/test"
@@ -43,7 +44,7 @@ func checkForExpectedResponses(ctx context.Context, t testing.TB, clients *test.
 	if err != nil {
 		return err
 	}
-	_, err = client.Poll(req, v1test.RetryingRouteInconsistency(pkgTest.MatchesAllOf(pkgTest.IsStatusOK, pkgTest.MatchesAllBodies(expectedResponses...))))
+	_, err = client.Poll(req, v1test.RetryingRouteInconsistency(spoof.MatchesAllOf(spoof.IsStatusOK, spoof.MatchesAllBodies(expectedResponses...))))
 	return err
 }
 
@@ -107,7 +108,7 @@ func validateDataPlane(t testing.TB, clients *test.Clients, names test.ResourceN
 		clients.KubeClient,
 		t.Logf,
 		names.URL,
-		v1test.RetryingRouteInconsistency(pkgTest.MatchesAllOf(pkgTest.IsStatusOK, pkgTest.EventuallyMatchesBody(expectedText))),
+		v1test.RetryingRouteInconsistency(spoof.MatchesAllOf(spoof.IsStatusOK, pkgTest.EventuallyMatchesBody(expectedText))),
 		"WaitForEndpointToServeText",
 		test.ServingFlags.ResolvableDomain,
 		test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.HTTPS))
diff --git a/test/conformance/api/v1/volumes_test.go b/test/conformance/api/v1/volumes_test.go
index 1d3e5b05e..c63a15066 100644
--- a/test/conformance/api/v1/volumes_test.go
+++ b/test/conformance/api/v1/volumes_test.go
@@ -470,7 +470,7 @@ func TestProjectedServiceAccountToken(t *testing.T) {
 		clients.KubeClient,
 		t.Logf,
 		names.URL,
-		v1test.RetryingRouteInconsistency(pkgTest.MatchesAllOf(pkgTest.IsStatusOK, parsesToken)),
+		v1test.RetryingRouteInconsistency(spoof.MatchesAllOf(spoof.IsStatusOK, parsesToken)),
 		"WaitForEndpointToServeTheToken",
 		test.ServingFlags.ResolvableDomain,
 		test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.HTTPS)); err != nil {
diff --git a/test/conformance/runtime/header_test.go b/test/conformance/runtime/header_test.go
index d5326116e..5b6aa0abc 100644
--- a/test/conformance/runtime/header_test.go
+++ b/test/conformance/runtime/header_test.go
@@ -25,7 +25,7 @@ import (
 	"strings"
 	"testing"
 
-	pkgTest "knative.dev/pkg/test"
+	"knative.dev/pkg/test/spoof"
 	"knative.dev/serving/test"
 )
 
@@ -95,7 +95,7 @@ func TestShouldHaveHeadersSet(t *testing.T) {
 		// required for tracing so we do not validate them.
 	}
 
-	_, ri, err := fetchRuntimeInfo(t, clients, pkgTest.WithHeader(userHeaders))
+	_, ri, err := fetchRuntimeInfo(t, clients, spoof.WithHeader(userHeaders))
 	if err != nil {
 		t.Fatal("Error fetching runtime info:", err)
 	}
diff --git a/test/conformance/runtime/util.go b/test/conformance/runtime/util.go
index ba7880674..65c503830 100644
--- a/test/conformance/runtime/util.go
+++ b/test/conformance/runtime/util.go
@@ -23,6 +23,7 @@ import (
 	"testing"
 
 	pkgTest "knative.dev/pkg/test"
+	"knative.dev/pkg/test/spoof"
 	"knative.dev/serving/test"
 	"knative.dev/serving/test/types"
 
@@ -59,7 +60,7 @@ func fetchRuntimeInfo(
 		clients.KubeClient,
 		t.Logf,
 		objects.Service.Status.URL.URL(),
-		v1test.RetryingRouteInconsistency(pkgTest.IsStatusOK),
+		v1test.RetryingRouteInconsistency(spoof.IsStatusOK),
 		"RuntimeInfo",
 		test.ServingFlags.ResolvableDomain,
 		append(reqOpts, test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.HTTPS))...)
diff --git a/test/e2e-tests.sh b/test/e2e-tests.sh
index 7feac7b0a..ee889153d 100755
--- a/test/e2e-tests.sh
+++ b/test/e2e-tests.sh
@@ -45,7 +45,7 @@ header "Running tests"
 
 failed=0
 
-# Run tests serially in the mesh and https scenarios
+# Run tests serially in the mesh and https scenarios.
 parallelism=""
 use_https=""
 if (( MESH )); then
@@ -59,7 +59,7 @@ if (( HTTPS )); then
   add_trap "kubectl delete -f ${TMP_DIR}/test/config/autotls/certmanager/caissuer/ --ignore-not-found" SIGKILL SIGTERM SIGQUIT
 fi
 
-# Keep the bucket count in sync with test/ha/ha.go
+# Keep the bucket count in sync with test/ha/ha.go.
 kubectl -n "${SYSTEM_NAMESPACE}" patch configmap/config-leader-election --type=merge \
   --patch='{"data":{"buckets": "'${BUCKETS}'"}}' || fail_test
 
@@ -74,7 +74,7 @@ scale_controlplane "${HA_COMPONENTS[@]}"
 # lease resources at the old sharding factor, so clean these up.
 kubectl -n ${SYSTEM_NAMESPACE} delete leases --all
 
-# Wait for a new leader Controller to prevent race conditions during service reconciliation
+# Wait for a new leader Controller to prevent race conditions during service reconciliation.
 wait_for_leader_controller || fail_test
 
 # Dump the leases post-setup.
@@ -116,7 +116,7 @@ toggle_feature multi-container Enabled
 go_test_e2e -timeout=2m ./test/e2e/multicontainer || failed=1
 toggle_feature multi-container Disabled
 
-# Enable allow-zero-initial-scale before running e2e tests (for test/e2e/initial_scale_test.go)
+# Enable allow-zero-initial-scale before running e2e tests (for test/e2e/initial_scale_test.go).
 toggle_feature allow-zero-initial-scale true config-autoscaler || fail_test
 go_test_e2e -timeout=2m ./test/e2e/initscale || failed=1
 toggle_feature allow-zero-initial-scale false config-autoscaler || fail_test
@@ -131,12 +131,12 @@ toggle_feature responsive-revision-gc Disabled
 
 # Run scale tests.
 # Note that we use a very high -parallel because each ksvc is run as its own
-# sub-test.  If this is not larger than the maximum scale tested then the test
+# sub-test. If this is not larger than the maximum scale tested then the test
 # simply cannot pass.
 go_test_e2e -timeout=20m -parallel=300 ./test/scale || failed=1
 
-# Run HA tests separately as they're stopping core Knative Serving pods
-# Define short -spoofinterval to ensure frequent probing while stopping pods
+# Run HA tests separately as they're stopping core Knative Serving pods.
+# Define short -spoofinterval to ensure frequent probing while stopping pods.
 go_test_e2e -timeout=25m -failfast -parallel=1 ./test/ha \
 	    -replicas="${REPLICAS:-1}" -buckets="${BUCKETS:-1}" -spoofinterval="10ms" || failed=1
 
diff --git a/test/e2e-upgrade-tests.sh b/test/e2e-upgrade-tests.sh
index c6d1d43ee..f4f25fba5 100755
--- a/test/e2e-upgrade-tests.sh
+++ b/test/e2e-upgrade-tests.sh
@@ -31,14 +31,6 @@
 
 source $(dirname $0)/e2e-common.sh
 
-latest_version() {
-  local semver=$(git describe --match "v[0-9]*" --abbrev=0)
-  local major_minor=$(echo "$semver" | cut -d. -f1-2)
-
-  # Get the latest patch release for the major minor
-  git tag -l "${major_minor}*" | sort -r --version-sort | head -n1
-}
-
 # Latest serving release. If user does not supply this as a flag, the latest
 # tagged release on the current branch will be used.
 LATEST_SERVING_RELEASE_VERSION=$(latest_version)
diff --git a/test/e2e/activator_test.go b/test/e2e/activator_test.go
index eed5ff3c1..bb8f17742 100644
--- a/test/e2e/activator_test.go
+++ b/test/e2e/activator_test.go
@@ -27,6 +27,7 @@ import (
 	"golang.org/x/sync/errgroup"
 	"knative.dev/pkg/ptr"
 	pkgTest "knative.dev/pkg/test"
+	"knative.dev/pkg/test/spoof"
 	v1 "knative.dev/serving/pkg/apis/serving/v1"
 	rnames "knative.dev/serving/pkg/reconciler/revision/resources/names"
 	"knative.dev/serving/test"
@@ -71,7 +72,7 @@ func TestActivatorOverload(t *testing.T) {
 		clients.KubeClient,
 		t.Logf,
 		resources.Route.Status.URL.URL(),
-		v1test.RetryingRouteInconsistency(pkgTest.IsStatusOK),
+		v1test.RetryingRouteInconsistency(spoof.IsStatusOK),
 		"WaitForSuccessfulResponse",
 		test.ServingFlags.ResolvableDomain,
 		test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.HTTPS),
diff --git a/test/e2e/autoscale.go b/test/e2e/autoscale.go
index 8170dafb7..7fc1c8b1f 100644
--- a/test/e2e/autoscale.go
+++ b/test/e2e/autoscale.go
@@ -36,6 +36,7 @@ import (
 
 	pkgTest "knative.dev/pkg/test"
 	"knative.dev/pkg/test/ingress"
+	"knative.dev/pkg/test/spoof"
 	"knative.dev/serving/pkg/apis/autoscaling"
 	resourcenames "knative.dev/serving/pkg/reconciler/revision/resources/names"
 	"knative.dev/serving/pkg/resources"
@@ -234,7 +235,7 @@ func SetupSvc(t *testing.T, class, metric string, target int, targetUtilization
 		clients.KubeClient,
 		t.Logf,
 		names.URL,
-		v1test.RetryingRouteInconsistency(pkgTest.MatchesAllOf(pkgTest.IsStatusOK)),
+		v1test.RetryingRouteInconsistency(spoof.MatchesAllOf(spoof.IsStatusOK)),
 		"CheckingEndpointAfterCreate",
 		test.ServingFlags.ResolvableDomain,
 		test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.HTTPS),
@@ -370,7 +371,7 @@ func AssertAutoscaleUpToNumPods(ctx *TestContext, curPods, targetPods float64, d
 	// Relax the bounds to reduce the flakiness caused by sampling in the autoscaling algorithm.
 	// Also adjust the values by the target utilization values.
 	minPods := math.Floor(curPods/ctx.targetUtilization) - 1
-	maxPods := math.Ceil(targetPods/ctx.targetUtilization) + 1
+	maxPods := math.Ceil(math.Ceil(targetPods/ctx.targetUtilization) * 1.1)
 
 	stopChan := make(chan struct{})
 	var grp errgroup.Group
diff --git a/test/e2e/destroypod_test.go b/test/e2e/destroypod_test.go
index b4d24c197..89a3d96b2 100644
--- a/test/e2e/destroypod_test.go
+++ b/test/e2e/destroypod_test.go
@@ -33,6 +33,7 @@ import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/util/wait"
 	pkgTest "knative.dev/pkg/test"
+	"knative.dev/pkg/test/spoof"
 	"knative.dev/serving/pkg/apis/serving"
 	v1 "knative.dev/serving/pkg/apis/serving/v1"
 	rtesting "knative.dev/serving/pkg/testing/v1"
@@ -94,7 +95,7 @@ func TestDestroyPodInflight(t *testing.T) {
 		clients.KubeClient,
 		t.Logf,
 		routeURL,
-		v1test.RetryingRouteInconsistency(pkgTest.MatchesAllOf(pkgTest.IsStatusOK, pkgTest.MatchesBody(timeoutExpectedOutput))),
+		v1test.RetryingRouteInconsistency(spoof.MatchesAllOf(spoof.IsStatusOK, spoof.MatchesBody(timeoutExpectedOutput))),
 		"TimeoutAppServesText",
 		test.ServingFlags.ResolvableDomain,
 		test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.HTTPS),
@@ -178,7 +179,7 @@ func TestDestroyPodTimely(t *testing.T) {
 		clients.KubeClient,
 		t.Logf,
 		routeURL,
-		v1test.RetryingRouteInconsistency(pkgTest.IsStatusOK),
+		v1test.RetryingRouteInconsistency(spoof.IsStatusOK),
 		"RouteServes",
 		test.ServingFlags.ResolvableDomain,
 		test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.HTTPS),
@@ -262,7 +263,7 @@ func TestDestroyPodWithRequests(t *testing.T) {
 		clients.KubeClient,
 		t.Logf,
 		routeURL,
-		v1test.RetryingRouteInconsistency(pkgTest.IsStatusOK),
+		v1test.RetryingRouteInconsistency(spoof.IsStatusOK),
 		"RouteServes",
 		test.ServingFlags.ResolvableDomain,
 		test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.HTTPS),
diff --git a/test/e2e/egress_traffic_test.go b/test/e2e/egress_traffic_test.go
index 1fb668828..a76c9dc07 100644
--- a/test/e2e/egress_traffic_test.go
+++ b/test/e2e/egress_traffic_test.go
@@ -24,6 +24,7 @@ import (
 
 	corev1 "k8s.io/api/core/v1"
 	pkgTest "knative.dev/pkg/test"
+	"knative.dev/pkg/test/spoof"
 	rtesting "knative.dev/serving/pkg/testing/v1"
 	"knative.dev/serving/test"
 	v1test "knative.dev/serving/test/v1"
@@ -64,7 +65,7 @@ func TestEgressTraffic(t *testing.T) {
 		clients.KubeClient,
 		t.Logf,
 		url,
-		v1test.RetryingRouteInconsistency(pkgTest.IsStatusOK),
+		v1test.RetryingRouteInconsistency(spoof.IsStatusOK),
 		"HTTPProxy",
 		test.ServingFlags.ResolvableDomain,
 		test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.HTTPS),
diff --git a/test/e2e/grpc_test.go b/test/e2e/grpc_test.go
index 099edd79e..cc15ea03f 100644
--- a/test/e2e/grpc_test.go
+++ b/test/e2e/grpc_test.go
@@ -38,6 +38,7 @@ import (
 
 	pkgTest "knative.dev/pkg/test"
 	"knative.dev/pkg/test/ingress"
+	"knative.dev/pkg/test/spoof"
 	"knative.dev/serving/pkg/apis/autoscaling"
 	rtesting "knative.dev/serving/pkg/testing/v1"
 	"knative.dev/serving/test"
@@ -342,7 +343,7 @@ func testGRPC(t *testing.T, f grpcTest, fopts ...rtesting.ServiceOption) {
 		clients.KubeClient,
 		t.Logf,
 		url,
-		v1test.RetryingRouteInconsistency(pkgTest.IsStatusOK),
+		v1test.RetryingRouteInconsistency(spoof.IsStatusOK),
 		"gRPCPingReadyToServe",
 		test.ServingFlags.ResolvableDomain,
 		test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.HTTPS),
diff --git a/test/e2e/helloworld_test.go b/test/e2e/helloworld_test.go
index eb8bcd074..f977851b1 100644
--- a/test/e2e/helloworld_test.go
+++ b/test/e2e/helloworld_test.go
@@ -28,6 +28,7 @@ import (
 	"k8s.io/apimachinery/pkg/api/resource"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	pkgTest "knative.dev/pkg/test"
+	"knative.dev/pkg/test/spoof"
 	"knative.dev/serving/pkg/apis/serving"
 	rtesting "knative.dev/serving/pkg/testing/v1"
 	"knative.dev/serving/test"
@@ -59,7 +60,7 @@ func TestHelloWorld(t *testing.T) {
 		clients.KubeClient,
 		t.Logf,
 		url,
-		v1test.RetryingRouteInconsistency(pkgTest.MatchesAllOf(pkgTest.IsStatusOK, pkgTest.MatchesBody(test.HelloWorldText))),
+		v1test.RetryingRouteInconsistency(spoof.MatchesAllOf(spoof.IsStatusOK, spoof.MatchesBody(test.HelloWorldText))),
 		"HelloWorldServesText",
 		test.ServingFlags.ResolvableDomain,
 		test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.HTTPS),
@@ -112,7 +113,7 @@ func TestQueueSideCarResourceLimit(t *testing.T) {
 		clients.KubeClient,
 		t.Logf,
 		url,
-		v1test.RetryingRouteInconsistency(pkgTest.MatchesAllOf(pkgTest.IsStatusOK, pkgTest.MatchesBody(test.HelloWorldText))),
+		v1test.RetryingRouteInconsistency(spoof.MatchesAllOf(spoof.IsStatusOK, spoof.MatchesBody(test.HelloWorldText))),
 		"HelloWorldServesText",
 		test.ServingFlags.ResolvableDomain,
 		test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.HTTPS),
diff --git a/test/e2e/http2_test.go b/test/e2e/http2_test.go
index 392840617..b4eab1cc9 100644
--- a/test/e2e/http2_test.go
+++ b/test/e2e/http2_test.go
@@ -24,6 +24,7 @@ import (
 	"testing"
 
 	pkgTest "knative.dev/pkg/test"
+	"knative.dev/pkg/test/spoof"
 	rtesting "knative.dev/serving/pkg/testing/v1"
 	"knative.dev/serving/test"
 	v1test "knative.dev/serving/test/v1"
@@ -58,7 +59,7 @@ func TestHelloHTTP2WithPortNameH2C(t *testing.T) {
 		clients.KubeClient,
 		t.Logf,
 		url,
-		v1test.RetryingRouteInconsistency(pkgTest.MatchesAllOf(pkgTest.IsStatusOK, pkgTest.MatchesBody(test.HelloHTTP2Text))),
+		v1test.RetryingRouteInconsistency(spoof.MatchesAllOf(spoof.IsStatusOK, spoof.MatchesBody(test.HelloHTTP2Text))),
 		"HelloHTTP2ServesTextOnH2C",
 		test.ServingFlags.ResolvableDomain,
 		test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.HTTPS),
@@ -98,7 +99,7 @@ func TestHelloHTTP2WithEmptyPortName(t *testing.T) {
 		clients.KubeClient,
 		t.Logf,
 		url,
-		v1test.RetryingRouteInconsistency(pkgTest.MatchesAllOf(pkgTest.IsOneOfStatusCodes(http.StatusUpgradeRequired))),
+		v1test.RetryingRouteInconsistency(spoof.MatchesAllOf(spoof.IsOneOfStatusCodes(http.StatusUpgradeRequired))),
 		"HelloHTTP2ServesTextWithEmptyPort",
 		test.ServingFlags.ResolvableDomain,
 		test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.HTTPS),
diff --git a/test/e2e/logging_test.go b/test/e2e/logging_test.go
index 74fa90905..ab795faec 100644
--- a/test/e2e/logging_test.go
+++ b/test/e2e/logging_test.go
@@ -37,6 +37,7 @@ import (
 	"knative.dev/pkg/metrics"
 	"knative.dev/pkg/system"
 	pkgtest "knative.dev/pkg/test"
+	"knative.dev/pkg/test/spoof"
 	"knative.dev/serving/pkg/apis/autoscaling"
 	rtesting "knative.dev/serving/pkg/testing/v1"
 	"knative.dev/serving/test"
@@ -89,7 +90,7 @@ func TestRequestLogs(t *testing.T) {
 		clients.KubeClient,
 		t.Logf,
 		resources.Route.Status.URL.URL(),
-		v1test.RetryingRouteInconsistency(pkgtest.MatchesAllOf(pkgtest.IsStatusOK, pkgtest.MatchesBody(test.HelloWorldText))),
+		v1test.RetryingRouteInconsistency(spoof.MatchesAllOf(spoof.IsStatusOK, spoof.MatchesBody(test.HelloWorldText))),
 		"WaitForEndpointToServeText",
 		test.ServingFlags.ResolvableDomain,
 		test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.HTTPS))
diff --git a/test/e2e/minscale_readiness_test.go b/test/e2e/minscale_readiness_test.go
index be3048821..f11ab56c4 100644
--- a/test/e2e/minscale_readiness_test.go
+++ b/test/e2e/minscale_readiness_test.go
@@ -61,10 +61,12 @@ func TestMinScale(t *testing.T) {
 
 	t.Log("Creating configuration")
 	cfg, err := v1test.CreateConfiguration(t, clients, names, withMinScale(minScale),
+		// Make sure we scale down quickly after panic, before the autoscaler get killed by chaosduck.
+		withWindow(autoscaling.WindowMin),
 		// Pass low resource requirements to avoid Pod scheduling problems
 		// on busy clusters.  This is adapted from ./test/e2e/scale.go
-		func(svc *v1.Configuration) {
-			svc.Spec.Template.Spec.Containers[0].Resources = corev1.ResourceRequirements{
+		func(cfg *v1.Configuration) {
+			cfg.Spec.Template.Spec.Containers[0].Resources = corev1.ResourceRequirements{
 				Limits: corev1.ResourceList{
 					corev1.ResourceCPU:    resource.MustParse("50m"),
 					corev1.ResourceMemory: resource.MustParse("50Mi"),
@@ -161,6 +163,15 @@ func withMinScale(minScale int) func(cfg *v1.Configuration) {
 	}
 }
 
+func withWindow(t time.Duration) func(cfg *v1.Configuration) {
+	return func(cfg *v1.Configuration) {
+		if cfg.Spec.Template.Annotations == nil {
+			cfg.Spec.Template.Annotations = make(map[string]string, 1)
+		}
+		cfg.Spec.Template.Annotations[autoscaling.WindowAnnotationKey] = t.String()
+	}
+}
+
 func latestRevisionName(t *testing.T, clients *test.Clients, configName, oldRevName string) string {
 	// Wait for the Config have a LatestCreatedRevisionName
 	if err := v1test.WaitForConfigurationState(
diff --git a/test/e2e/multicontainer/multicontainer_test.go b/test/e2e/multicontainer/multicontainer_test.go
index 1f1e735de..1e77d5fa8 100644
--- a/test/e2e/multicontainer/multicontainer_test.go
+++ b/test/e2e/multicontainer/multicontainer_test.go
@@ -25,6 +25,7 @@ import (
 	corev1 "k8s.io/api/core/v1"
 
 	pkgTest "knative.dev/pkg/test"
+	"knative.dev/pkg/test/spoof"
 	v1 "knative.dev/serving/pkg/apis/serving/v1"
 	"knative.dev/serving/test"
 	"knative.dev/serving/test/e2e"
@@ -69,7 +70,7 @@ func TestMultiContainer(t *testing.T) {
 		clients.KubeClient,
 		t.Logf,
 		url,
-		v1test.RetryingRouteInconsistency(pkgTest.MatchesAllOf(pkgTest.IsStatusOK, pkgTest.MatchesBody(test.MultiContainerResponse))),
+		v1test.RetryingRouteInconsistency(spoof.MatchesAllOf(spoof.IsStatusOK, spoof.MatchesBody(test.MultiContainerResponse))),
 		"MulticontainerServesExpectedText",
 		test.ServingFlags.ResolvableDomain,
 		test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.HTTPS),
diff --git a/test/e2e/namespace_test.go b/test/e2e/namespace_test.go
index 65bd7a22c..9c612e405 100644
--- a/test/e2e/namespace_test.go
+++ b/test/e2e/namespace_test.go
@@ -24,6 +24,7 @@ import (
 	"testing"
 
 	pkgTest "knative.dev/pkg/test"
+	"knative.dev/pkg/test/spoof"
 	"knative.dev/serving/pkg/apis/serving"
 	"knative.dev/serving/test"
 	v1test "knative.dev/serving/test/v1"
@@ -38,7 +39,7 @@ func checkResponse(t *testing.T, clients *test.Clients, names test.ResourceNames
 		clients.KubeClient,
 		t.Logf,
 		names.URL,
-		v1test.RetryingRouteInconsistency(pkgTest.MatchesAllOf(pkgTest.IsStatusOK, pkgTest.EventuallyMatchesBody(expectedText))),
+		v1test.RetryingRouteInconsistency(spoof.MatchesAllOf(spoof.IsStatusOK, pkgTest.EventuallyMatchesBody(expectedText))),
 		"WaitForEndpointToServeText",
 		test.ServingFlags.ResolvableDomain,
 		test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.HTTPS),
diff --git a/test/e2e/scale.go b/test/e2e/scale.go
index ef76ad1c3..dd3b3b947 100644
--- a/test/e2e/scale.go
+++ b/test/e2e/scale.go
@@ -187,7 +187,7 @@ func ScaleToWithin(t *testing.T, scale int, duration time.Duration, latencies La
 					clients.KubeClient,
 					t.Logf,
 					url,
-					v1test.RetryingRouteInconsistency(pkgTest.MatchesAllOf(pkgTest.IsStatusOK, pkgTest.MatchesBody(test.HelloWorldText), abortOnTimeout(ctx))),
+					v1test.RetryingRouteInconsistency(spoof.MatchesAllOf(spoof.IsStatusOK, spoof.MatchesBody(test.HelloWorldText), abortOnTimeout(ctx))),
 					"WaitForEndpointToServeText",
 					test.ServingFlags.ResolvableDomain)
 				if err != nil {
diff --git a/test/e2e/service_to_service_test.go b/test/e2e/service_to_service_test.go
index 617ad3fee..4e9bf49a0 100644
--- a/test/e2e/service_to_service_test.go
+++ b/test/e2e/service_to_service_test.go
@@ -132,7 +132,7 @@ func testProxyToHelloworld(t *testing.T, clients *test.Clients, helloworldURL *u
 		clients.KubeClient,
 		t.Logf,
 		url,
-		v1test.RetryingRouteInconsistency(pkgTest.Retrying(pkgTest.MatchesAllOf(pkgTest.IsStatusOK, pkgTest.EventuallyMatchesBody(helloworldResponse)), http.StatusBadGateway)),
+		v1test.RetryingRouteInconsistency(spoof.Retrying(spoof.MatchesAllOf(spoof.IsStatusOK, pkgTest.EventuallyMatchesBody(helloworldResponse)), http.StatusBadGateway)),
 		"HTTPProxy",
 		test.ServingFlags.ResolvableDomain,
 		test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.HTTPS),
diff --git a/test/e2e/tagheader/tag_header_based_routing_test.go b/test/e2e/tagheader/tag_header_based_routing_test.go
index 8ab3ebeb8..5216cc18c 100644
--- a/test/e2e/tagheader/tag_header_based_routing_test.go
+++ b/test/e2e/tagheader/tag_header_based_routing_test.go
@@ -26,6 +26,7 @@ import (
 	network "knative.dev/networking/pkg"
 	"knative.dev/pkg/ptr"
 	pkgTest "knative.dev/pkg/test"
+	"knative.dev/pkg/test/spoof"
 	v1 "knative.dev/serving/pkg/apis/serving/v1"
 	rtesting "knative.dev/serving/pkg/testing/v1"
 	"knative.dev/serving/test"
@@ -118,7 +119,7 @@ func TestTagHeaderBasedRouting(t *testing.T) {
 				clients.KubeClient,
 				t.Logf,
 				objects.Service.Status.URL.URL(),
-				v1test.RetryingRouteInconsistency(pkgTest.MatchesAllOf(pkgTest.IsStatusOK, pkgTest.MatchesBody(tt.wantResponse))),
+				v1test.RetryingRouteInconsistency(spoof.MatchesAllOf(spoof.IsStatusOK, spoof.MatchesBody(tt.wantResponse))),
 				"WaitForSuccessfulResponse",
 				test.ServingFlags.ResolvableDomain,
 				test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.HTTPS),
diff --git a/test/ha/ha.go b/test/ha/ha.go
index 217f3162b..bcd34f7ae 100644
--- a/test/ha/ha.go
+++ b/test/ha/ha.go
@@ -26,6 +26,7 @@ import (
 	"k8s.io/apimachinery/pkg/util/wait"
 
 	pkgTest "knative.dev/pkg/test"
+	"knative.dev/pkg/test/spoof"
 	rtesting "knative.dev/serving/pkg/testing/v1"
 	"knative.dev/serving/test"
 	"knative.dev/serving/test/e2e"
@@ -66,7 +67,7 @@ func assertServiceEventuallyWorks(t *testing.T, clients *test.Clients, names tes
 		clients.KubeClient,
 		t.Logf,
 		url,
-		v1test.RetryingRouteInconsistency(pkgTest.MatchesAllOf(pkgTest.IsStatusOK, pkgTest.EventuallyMatchesBody(expectedText))),
+		v1test.RetryingRouteInconsistency(spoof.MatchesAllOf(spoof.IsStatusOK, pkgTest.EventuallyMatchesBody(expectedText))),
 		"WaitForEndpointToServeText",
 		test.ServingFlags.ResolvableDomain); err != nil {
 		t.Fatalf("The endpoint for Route %s at %s didn't serve the expected text %q: %v", names.Route, url, expectedText, err)
diff --git a/test/performance/benchmarks/scale-from-zero/continuous/main.go b/test/performance/benchmarks/scale-from-zero/continuous/main.go
index f53806dab..c9deaa24b 100644
--- a/test/performance/benchmarks/scale-from-zero/continuous/main.go
+++ b/test/performance/benchmarks/scale-from-zero/continuous/main.go
@@ -34,6 +34,7 @@ import (
 	"k8s.io/apimachinery/pkg/labels"
 	"k8s.io/apimachinery/pkg/watch"
 	"knative.dev/pkg/test/mako"
+	"knative.dev/pkg/test/spoof"
 	"knative.dev/serving/pkg/apis/serving"
 	"knative.dev/serving/test/performance"
 
@@ -207,7 +208,7 @@ func runScaleFromZero(ctx context.Context, clients *test.Clients, idx int, ro *v
 			clients.KubeClient,
 			log.Printf,
 			url,
-			pkgTest.MatchesAllOf(pkgTest.IsStatusOK, pkgTest.MatchesBody(helloWorldExpectedOutput)),
+			spoof.MatchesAllOf(spoof.IsStatusOK, spoof.MatchesBody(helloWorldExpectedOutput)),
 			"HelloWorldServesText",
 			test.ServingFlags.ResolvableDomain, waitToServe,
 		)
diff --git a/test/upgrade/upgrade.go b/test/upgrade/upgrade.go
index 8c25a1765..edd135a3c 100644
--- a/test/upgrade/upgrade.go
+++ b/test/upgrade/upgrade.go
@@ -31,6 +31,7 @@ import (
 	_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
 
 	pkgTest "knative.dev/pkg/test"
+	"knative.dev/pkg/test/spoof"
 	"knative.dev/serving/test"
 	"knative.dev/serving/test/e2e"
 	v1test "knative.dev/serving/test/v1"
@@ -57,7 +58,7 @@ func assertServiceResourcesUpdated(t testing.TB, clients *test.Clients, names te
 		clients.KubeClient,
 		t.Logf,
 		url,
-		v1test.RetryingRouteInconsistency(pkgTest.MatchesAllOf(pkgTest.IsStatusOK, pkgTest.EventuallyMatchesBody(expectedText))),
+		v1test.RetryingRouteInconsistency(spoof.MatchesAllOf(spoof.IsStatusOK, pkgTest.EventuallyMatchesBody(expectedText))),
 		"WaitForEndpointToServeText",
 		test.ServingFlags.ResolvableDomain); err != nil {
 		t.Fatal(fmt.Sprintf("The endpoint for Route %s at %s didn't serve the expected text %q: %v", names.Route, url, expectedText, err))
diff --git a/third_party/cert-manager-latest/net-certmanager.yaml b/third_party/cert-manager-latest/net-certmanager.yaml
index 933dff1f5..70f3b92a4 100644
--- a/third_party/cert-manager-latest/net-certmanager.yaml
+++ b/third_party/cert-manager-latest/net-certmanager.yaml
@@ -18,7 +18,7 @@ metadata:
   # These are the permissions needed by the `cert-manager` `Certificate` implementation.
   name: knative-serving-certmanager
   labels:
-    serving.knative.dev/release: "v20201119-8b1a8dc"
+    serving.knative.dev/release: "v20201125-ee5fc18"
     serving.knative.dev/controller: "true"
     networking.knative.dev/certificate-provider: cert-manager
 rules:
@@ -49,7 +49,7 @@ kind: ValidatingWebhookConfiguration
 metadata:
   name: config.webhook.net-certmanager.networking.internal.knative.dev
   labels:
-    serving.knative.dev/release: "v20201119-8b1a8dc"
+    serving.knative.dev/release: "v20201125-ee5fc18"
 webhooks:
   - admissionReviewVersions:
       - v1beta1
@@ -86,7 +86,7 @@ metadata:
   name: net-certmanager-webhook-certs
   namespace: knative-serving
   labels:
-    serving.knative.dev/release: "v20201119-8b1a8dc"
+    serving.knative.dev/release: "v20201125-ee5fc18"
 
 ---
 # Copyright 2020 The Knative Authors
@@ -109,7 +109,7 @@ metadata:
   name: config-certmanager
   namespace: knative-serving
   labels:
-    serving.knative.dev/release: "v20201119-8b1a8dc"
+    serving.knative.dev/release: "v20201125-ee5fc18"
     networking.knative.dev/certificate-provider: cert-manager
 data:
   _example: |
@@ -156,7 +156,7 @@ metadata:
   name: networking-certmanager
   namespace: knative-serving
   labels:
-    serving.knative.dev/release: "v20201119-8b1a8dc"
+    serving.knative.dev/release: "v20201125-ee5fc18"
     networking.knative.dev/certificate-provider: cert-manager
 spec:
   selector:
@@ -168,14 +168,14 @@ spec:
         cluster-autoscaler.kubernetes.io/safe-to-evict: "true"
       labels:
         app: networking-certmanager
-        serving.knative.dev/release: "v20201119-8b1a8dc"
+        serving.knative.dev/release: "v20201125-ee5fc18"
     spec:
       serviceAccountName: controller
       containers:
         - name: networking-certmanager
           # This is the Go import path for the binary that is containerized
           # and substituted here.
-          image: gcr.io/knative-nightly/knative.dev/net-certmanager/cmd/controller@sha256:536f827f7283a75e0c7ba22f30c93d25aa1a23174e4e2b3c44cfa319fc2db6b5
+          image: gcr.io/knative-nightly/knative.dev/net-certmanager/cmd/controller@sha256:4ac5f96218fe6f9ae768d5986320be888657ae9410a0f5ca4d6078ba483187eb
           resources:
             requests:
               cpu: 30m
@@ -213,7 +213,7 @@ kind: Service
 metadata:
   labels:
     app: networking-certmanager
-    serving.knative.dev/release: "v20201119-8b1a8dc"
+    serving.knative.dev/release: "v20201125-ee5fc18"
     networking.knative.dev/certificate-provider: cert-manager
   name: networking-certmanager
   namespace: knative-serving
@@ -250,7 +250,7 @@ metadata:
   name: net-certmanager-webhook
   namespace: knative-serving
   labels:
-    serving.knative.dev/release: "v20201119-8b1a8dc"
+    serving.knative.dev/release: "v20201125-ee5fc18"
 spec:
   selector:
     matchLabels:
@@ -263,14 +263,14 @@ spec:
       labels:
         app: net-certmanager-webhook
         role: net-certmanager-webhook
-        serving.knative.dev/release: "v20201119-8b1a8dc"
+        serving.knative.dev/release: "v20201125-ee5fc18"
     spec:
       serviceAccountName: controller
       containers:
         - name: webhook
           # This is the Go import path for the binary that is containerized
           # and substituted here.
-          image: gcr.io/knative-nightly/knative.dev/net-certmanager/cmd/webhook@sha256:3c944b7c04ca09e6c24720f5acbc40756eeabdc21b777b6ace0a7e71ee487e74
+          image: gcr.io/knative-nightly/knative.dev/net-certmanager/cmd/webhook@sha256:60a35390498ecc84c7dc5a612c48cbe3ef3fa9f19c191b4f6068a4da23d5b5d1
           resources:
             requests:
               cpu: 20m
@@ -329,7 +329,7 @@ metadata:
   namespace: knative-serving
   labels:
     role: net-certmanager-webhook
-    serving.knative.dev/release: "v20201119-8b1a8dc"
+    serving.knative.dev/release: "v20201125-ee5fc18"
 spec:
   ports:
     # Define metrics and profiling for them to be accessible within service meshes.
diff --git a/third_party/contour-latest/contour.yaml b/third_party/contour-latest/contour.yaml
index cad2fcceb..66e8d819c 100644
--- a/third_party/contour-latest/contour.yaml
+++ b/third_party/contour-latest/contour.yaml
@@ -1482,7 +1482,7 @@ spec:
     spec:
       containers:
         - name: contour
-          image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:42fe396e303dc36eb0bf2fccc7734cc9e7768cea24283219f197062dc8b8fca1
+          image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:29131e3d5b3b2c89e327242501a107ad855444914530c47fd2ce29a900597d2f
           imagePullPolicy: Always
           command:
             - contour
@@ -1709,7 +1709,7 @@ spec:
             - --contour-key-file=/certs/tls.key
             - --config-path=/config/contour.yaml
           command: ["contour"]
-          image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:42fe396e303dc36eb0bf2fccc7734cc9e7768cea24283219f197062dc8b8fca1
+          image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:29131e3d5b3b2c89e327242501a107ad855444914530c47fd2ce29a900597d2f
           imagePullPolicy: IfNotPresent
           name: contour
           ports:
@@ -1798,7 +1798,7 @@ spec:
           args:
             - envoy
             - shutdown-manager
-          image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:42fe396e303dc36eb0bf2fccc7734cc9e7768cea24283219f197062dc8b8fca1
+          image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:29131e3d5b3b2c89e327242501a107ad855444914530c47fd2ce29a900597d2f
           imagePullPolicy: IfNotPresent
           lifecycle:
             preStop:
@@ -1875,7 +1875,7 @@ spec:
             - --envoy-key-file=/certs/tls.key
           command:
             - contour
-          image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:42fe396e303dc36eb0bf2fccc7734cc9e7768cea24283219f197062dc8b8fca1
+          image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:29131e3d5b3b2c89e327242501a107ad855444914530c47fd2ce29a900597d2f
           imagePullPolicy: IfNotPresent
           name: envoy-initconfig
           volumeMounts:
@@ -3385,7 +3385,7 @@ spec:
     spec:
       containers:
         - name: contour
-          image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:42fe396e303dc36eb0bf2fccc7734cc9e7768cea24283219f197062dc8b8fca1
+          image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:29131e3d5b3b2c89e327242501a107ad855444914530c47fd2ce29a900597d2f
           imagePullPolicy: Always
           command:
             - contour
@@ -3612,7 +3612,7 @@ spec:
             - --contour-key-file=/certs/tls.key
             - --config-path=/config/contour.yaml
           command: ["contour"]
-          image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:42fe396e303dc36eb0bf2fccc7734cc9e7768cea24283219f197062dc8b8fca1
+          image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:29131e3d5b3b2c89e327242501a107ad855444914530c47fd2ce29a900597d2f
           imagePullPolicy: IfNotPresent
           name: contour
           ports:
@@ -3701,7 +3701,7 @@ spec:
           args:
             - envoy
             - shutdown-manager
-          image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:42fe396e303dc36eb0bf2fccc7734cc9e7768cea24283219f197062dc8b8fca1
+          image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:29131e3d5b3b2c89e327242501a107ad855444914530c47fd2ce29a900597d2f
           imagePullPolicy: IfNotPresent
           lifecycle:
             preStop:
@@ -3778,7 +3778,7 @@ spec:
             - --envoy-key-file=/certs/tls.key
           command:
             - contour
-          image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:42fe396e303dc36eb0bf2fccc7734cc9e7768cea24283219f197062dc8b8fca1
+          image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:29131e3d5b3b2c89e327242501a107ad855444914530c47fd2ce29a900597d2f
           imagePullPolicy: IfNotPresent
           name: envoy-initconfig
           volumeMounts:
diff --git a/third_party/contour-latest/net-contour.yaml b/third_party/contour-latest/net-contour.yaml
index 3b1edbb76..9a29f2b5a 100644
--- a/third_party/contour-latest/net-contour.yaml
+++ b/third_party/contour-latest/net-contour.yaml
@@ -34,7 +34,7 @@ metadata:
   namespace: knative-serving
   labels:
     networking.knative.dev/ingress-provider: contour
-    serving.knative.dev/release: "v20201119-4f5827a2"
+    serving.knative.dev/release: "v20201125-32ec14e8"
 data:
   _example: |
     ################################
@@ -105,7 +105,7 @@ spec:
         - name: controller
           # This is the Go import path for the binary that is containerized
           # and substituted here.
-          image: gcr.io/knative-nightly/knative.dev/net-contour/cmd/controller@sha256:8b938a0d8fe1d9f6db484794ce73997946a07d89331fe441ece5c6559cff5159
+          image: gcr.io/knative-nightly/knative.dev/net-contour/cmd/controller@sha256:28b659320ffe4c17f6678e20f061145753cde045ec27bcf6c1b625de27650558
           resources:
             requests:
               cpu: 40m
diff --git a/third_party/istio-latest/net-istio.yaml b/third_party/istio-latest/net-istio.yaml
index 413862b81..83e34c0c9 100644
--- a/third_party/istio-latest/net-istio.yaml
+++ b/third_party/istio-latest/net-istio.yaml
@@ -1,4 +1,4 @@
-# Generated when HEAD was 7aaec1965f260b3106c02c8003717a9765ede0c9
+# Generated when HEAD was c693543b6b258c46922837b0f979d1e64967d37c
 #
 # Copyright 2019 The Knative Authors
 #
@@ -20,7 +20,7 @@ metadata:
   # These are the permissions needed by the Istio Ingress implementation.
   name: knative-serving-istio
   labels:
-    serving.knative.dev/release: "v20201119-7aaec196"
+    serving.knative.dev/release: "v20201125-c693543b"
     serving.knative.dev/controller: "true"
     networking.knative.dev/ingress-provider: istio
 rules:
@@ -50,7 +50,7 @@ metadata:
   name: knative-ingress-gateway
   namespace: knative-serving
   labels:
-    serving.knative.dev/release: "v20201119-7aaec196"
+    serving.knative.dev/release: "v20201125-c693543b"
     networking.knative.dev/ingress-provider: istio
 spec:
   selector:
@@ -87,7 +87,7 @@ metadata:
   name: knative-local-gateway
   namespace: knative-serving
   labels:
-    serving.knative.dev/release: "v20201119-7aaec196"
+    serving.knative.dev/release: "v20201125-c693543b"
     networking.knative.dev/ingress-provider: istio
 spec:
   selector:
@@ -106,7 +106,7 @@ metadata:
   name: knative-local-gateway
   namespace: istio-system
   labels:
-    serving.knative.dev/release: "v20201119-7aaec196"
+    serving.knative.dev/release: "v20201125-c693543b"
     networking.knative.dev/ingress-provider: istio
 spec:
   type: ClusterIP
@@ -119,14 +119,14 @@ spec:
 
 ---
 # Allows the Webhooks to be reached by kube-api with or without
-# sidecar injection and with mTLS PERMISSIVE and STRICT. 
+# sidecar injection and with mTLS PERMISSIVE and STRICT.
 apiVersion: "security.istio.io/v1beta1"
 kind: "PeerAuthentication"
 metadata:
   name: "webhook"
   namespace: "knative-serving"
   labels:
-    serving.knative.dev/release: "v20201119-7aaec196"
+    serving.knative.dev/release: "v20201125-c693543b"
     networking.knative.dev/ingress-provider: istio
 spec:
   selector:
@@ -141,7 +141,7 @@ metadata:
   name: "istio-webhook"
   namespace: "knative-serving"
   labels:
-    serving.knative.dev/release: "v20201119-7aaec196"
+    serving.knative.dev/release: "v20201125-c693543b"
     networking.knative.dev/ingress-provider: istio
 spec:
   selector:
@@ -170,7 +170,7 @@ kind: MutatingWebhookConfiguration
 metadata:
   name: webhook.istio.networking.internal.knative.dev
   labels:
-    serving.knative.dev/release: "v20201119-7aaec196"
+    serving.knative.dev/release: "v20201125-c693543b"
     networking.knative.dev/ingress-provider: istio
 webhooks:
   - admissionReviewVersions:
@@ -206,7 +206,7 @@ kind: ValidatingWebhookConfiguration
 metadata:
   name: config.webhook.istio.networking.internal.knative.dev
   labels:
-    serving.knative.dev/release: "v20201119-7aaec196"
+    serving.knative.dev/release: "v20201125-c693543b"
     networking.knative.dev/ingress-provider: istio
 webhooks:
   - admissionReviewVersions:
@@ -244,7 +244,7 @@ metadata:
   name: istio-webhook-certs
   namespace: knative-serving
   labels:
-    serving.knative.dev/release: "v20201119-7aaec196"
+    serving.knative.dev/release: "v20201125-c693543b"
     networking.knative.dev/ingress-provider: istio
 
 ---
@@ -268,7 +268,7 @@ metadata:
   name: config-istio
   namespace: knative-serving
   labels:
-    serving.knative.dev/release: "v20201119-7aaec196"
+    serving.knative.dev/release: "v20201125-c693543b"
     networking.knative.dev/ingress-provider: istio
 data:
   _example: |
@@ -338,7 +338,7 @@ metadata:
   name: networking-istio
   namespace: knative-serving
   labels:
-    serving.knative.dev/release: "v20201119-7aaec196"
+    serving.knative.dev/release: "v20201125-c693543b"
     networking.knative.dev/ingress-provider: istio
 spec:
   selector:
@@ -354,14 +354,14 @@ spec:
         sidecar.istio.io/inject: "false"
       labels:
         app: networking-istio
-        serving.knative.dev/release: "v20201119-7aaec196"
+        serving.knative.dev/release: "v20201125-c693543b"
     spec:
       serviceAccountName: controller
       containers:
         - name: networking-istio
           # This is the Go import path for the binary that is containerized
           # and substituted here.
-          image: gcr.io/knative-nightly/knative.dev/net-istio/cmd/controller@sha256:0f498897542fd3b41aa756ca6fd90d8b47e9b0b18a8ef29999fe987de05d3f4e
+          image: gcr.io/knative-nightly/knative.dev/net-istio/cmd/controller@sha256:9330b325c9ef8c861312ee2447ff2cdb05c53d66e1905debdc3eba2f6f7b4773
           resources:
             requests:
               cpu: 30m
@@ -418,7 +418,7 @@ metadata:
   name: istio-webhook
   namespace: knative-serving
   labels:
-    serving.knative.dev/release: "v20201119-7aaec196"
+    serving.knative.dev/release: "v20201125-c693543b"
     networking.knative.dev/ingress-provider: istio
 spec:
   selector:
@@ -432,14 +432,14 @@ spec:
       labels:
         app: istio-webhook
         role: istio-webhook
-        serving.knative.dev/release: "v20201119-7aaec196"
+        serving.knative.dev/release: "v20201125-c693543b"
     spec:
       serviceAccountName: controller
       containers:
         - name: webhook
           # This is the Go import path for the binary that is containerized
           # and substituted here.
-          image: gcr.io/knative-nightly/knative.dev/net-istio/cmd/webhook@sha256:dd4163dc8ea8c347e7897828d071c96c9e524411401bf05e19640b9e248f1c41
+          image: gcr.io/knative-nightly/knative.dev/net-istio/cmd/webhook@sha256:c11397c9ce1c050103e20564e6038395a4931e830274aa904eab587cd14b1d44
           resources:
             requests:
               cpu: 20m
@@ -493,7 +493,7 @@ metadata:
   namespace: knative-serving
   labels:
     role: istio-webhook
-    serving.knative.dev/release: "v20201119-7aaec196"
+    serving.knative.dev/release: "v20201125-c693543b"
     networking.knative.dev/ingress-provider: istio
 spec:
   ports:
diff --git a/third_party/kourier-latest/kourier.yaml b/third_party/kourier-latest/kourier.yaml
index e81eb5fa3..3efaf257a 100644
--- a/third_party/kourier-latest/kourier.yaml
+++ b/third_party/kourier-latest/kourier.yaml
@@ -18,6 +18,7 @@ metadata:
   name: kourier-system
   labels:
     networking.knative.dev/ingress-provider: kourier
+    serving.knative.dev/release: "v20201124-03300d56"
 
 ---
 # Copyright 2020 The Knative Authors
@@ -41,6 +42,7 @@ metadata:
   namespace: knative-serving
   labels:
     networking.knative.dev/ingress-provider: kourier
+    serving.knative.dev/release: "v20201124-03300d56"
 ---
 apiVersion: rbac.authorization.k8s.io/v1
 kind: ClusterRole
@@ -49,6 +51,7 @@ metadata:
   namespace: knative-serving
   labels:
     networking.knative.dev/ingress-provider: kourier
+    serving.knative.dev/release: "v20201124-03300d56"
 rules:
   - apiGroups: [""]
     resources: ["events"]
@@ -75,6 +78,7 @@ metadata:
   name: 3scale-kourier
   labels:
     networking.knative.dev/ingress-provider: kourier
+    serving.knative.dev/release: "v20201124-03300d56"
 roleRef:
   apiGroup: rbac.authorization.k8s.io
   kind: ClusterRole
@@ -106,6 +110,7 @@ metadata:
   namespace: knative-serving
   labels:
     networking.knative.dev/ingress-provider: kourier
+    serving.knative.dev/release: "v20201124-03300d56"
 spec:
   replicas: 1
   selector:
@@ -117,7 +122,7 @@ spec:
         app: 3scale-kourier-control
     spec:
       containers:
-        - image: gcr.io/knative-nightly/knative.dev/net-kourier/cmd/kourier@sha256:345af26968f1bb542130a93d7ad672e8cfbd52dcebf9a4f6c8ec67a23af14e72
+        - image: gcr.io/knative-nightly/knative.dev/net-kourier/cmd/kourier@sha256:ccd6b777f9cab64bac4e99257b60c73775acd7ec260b19314609374c40d8bd09
           name: kourier-control
           env:
             - name: CERTS_SECRET_NAMESPACE
@@ -153,6 +158,7 @@ metadata:
   namespace: knative-serving
   labels:
     networking.knative.dev/ingress-provider: kourier
+    serving.knative.dev/release: "v20201124-03300d56"
 spec:
   ports:
     - name: grpc-xds
@@ -185,6 +191,7 @@ metadata:
   namespace: kourier-system
   labels:
     networking.knative.dev/ingress-provider: kourier
+    serving.knative.dev/release: "v20201124-03300d56"
 spec:
   selector:
     matchLabels:
@@ -201,7 +208,7 @@ spec:
             - --log-level info
           command:
             - /usr/local/bin/envoy
-          image: docker.io/maistra/proxyv2-ubi8:1.1.5
+          image: docker.io/maistra/proxyv2-ubi8:2.0.0
           name: kourier-gateway
           ports:
             - name: http2-external
@@ -250,6 +257,7 @@ metadata:
   namespace: kourier-system
   labels:
     networking.knative.dev/ingress-provider: kourier
+    serving.knative.dev/release: "v20201124-03300d56"
 spec:
   ports:
     - name: http2
@@ -271,6 +279,7 @@ metadata:
   namespace: kourier-system
   labels:
     networking.knative.dev/ingress-provider: kourier
+    serving.knative.dev/release: "v20201124-03300d56"
 spec:
   ports:
     - name: http2
@@ -288,6 +297,7 @@ metadata:
   namespace: kourier-system
   labels:
     networking.knative.dev/ingress-provider: kourier
+    serving.knative.dev/release: "v20201124-03300d56"
 data:
   envoy-bootstrap.yaml: |
     dynamic_resources:
@@ -312,9 +322,12 @@ data:
               port_value: 9000
           filter_chains:
             - filters:
-                - name: envoy.http_connection_manager
-                  config:
+                - name: envoy.filters.network.http_connection_manager
+                  typed_config:
+                    "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
                     stat_prefix: stats_server
+                    http_filters:
+                      - name: envoy.filters.http.router
                     route_config:
                       virtual_hosts:
                         - name: admin_interface
@@ -322,15 +335,14 @@ data:
                             - "*"
                           routes:
                             - match:
-                                regex: '/(certs|stats(/prometheus)?|server_info|clusters|listeners|ready)?'
+                                safe_regex:
+                                  google_re2: {}
+                                  regex: '/(certs|stats(/prometheus)?|server_info|clusters|listeners|ready)?'
                                 headers:
                                   - name: ':method'
                                     exact_match: GET
                               route:
                                 cluster: service_stats
-                    http_filters:
-                      - name: envoy.router
-                        config: {}
       clusters:
         - name: service_stats
           connect_timeout: 0.250s
@@ -345,10 +357,16 @@ data:
                       path: /tmp/envoy.admin
         - name: xds_cluster
           connect_timeout: 1s
-          hosts:
-            - socket_address:
-                address: "kourier-control.knative-serving"
-                port_value: 18000
+          type: strict_dns
+          load_assignment:
+            cluster_name: xds_cluster
+            endpoints:
+              lb_endpoints:
+                endpoint:
+                  address:
+                    socket_address:
+                      address: "kourier-control.knative-serving"
+                      port_value: 18000
           http2_protocol_options: {}
           type: STRICT_DNS
     admin:
diff --git a/vendor/knative.dev/networking/test/conformance.go b/vendor/knative.dev/networking/test/conformance.go
deleted file mode 100644
index a094ccf1e..000000000
--- a/vendor/knative.dev/networking/test/conformance.go
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
-Copyright 2020 The Knative Authors
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package test
-
-import (
-	"testing"
-	// For our e2e testing, we want this linked first so that our
-	// systen namespace environment variable is defaulted prior to
-	// logstream initialization.
-	_ "knative.dev/networking/test/defaultsystem"
-
-	pkgTest "knative.dev/pkg/test"
-	"knative.dev/pkg/test/logstream"
-
-	// Mysteriously required to support GCP auth (required by k8s libs). Apparently just importing it is enough. @_@ side effects @_@. https://github.com/kubernetes/client-go/issues/242
-	_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
-)
-
-// Constants for test images located in test/test_images.
-const (
-	// Test image names
-	Autoscale           = "autoscale"
-	Failing             = "failing"
-	HelloVolume         = "hellovolume"
-	HelloWorld          = "helloworld"
-	HTTPProxy           = "httpproxy"
-	InvalidHelloWorld   = "invalidhelloworld" // Not a real image
-	PizzaPlanet1        = "pizzaplanetv1"
-	PizzaPlanet2        = "pizzaplanetv2"
-	Protocols           = "protocols"
-	Runtime             = "runtime"
-	SingleThreadedImage = "singlethreaded"
-	Timeout             = "timeout"
-	WorkingDir          = "workingdir"
-
-	// Constants for test image output.
-	PizzaPlanetText1 = "What a spaceport!"
-	PizzaPlanetText2 = "Re-energize yourself with a slice of pepperoni!"
-	HelloWorldText   = "Hello World! How about some tasty noodles?"
-
-	ConcurrentRequests = 200
-	// We expect to see 100% of requests succeed for traffic sent directly to revisions.
-	// This might be a bad assumption.
-	MinDirectPercentage = 1
-	// We expect to see at least 25% of either response since we're routing 50/50.
-	// The CDF of the binomial distribution tells us this will flake roughly
-	// 1 time out of 10^12 (roughly the number of galaxies in the observable universe).
-	MinSplitPercentage = 0.25
-)
-
-// Setup creates client to run Knative Service requests
-func Setup(t testing.TB) *Clients {
-	t.Helper()
-
-	cancel := logstream.Start(t)
-	t.Cleanup(cancel)
-
-	clients, err := NewClients(pkgTest.Flags.Kubeconfig, pkgTest.Flags.Cluster, ServingNamespace)
-	if err != nil {
-		t.Fatal("Couldn't initialize clients", "error", err.Error())
-	}
-	return clients
-}
diff --git a/vendor/knative.dev/networking/test/conformance/ingress/rule.go b/vendor/knative.dev/networking/test/conformance/ingress/rule.go
new file mode 100644
index 000000000..9a1ae81c3
--- /dev/null
+++ b/vendor/knative.dev/networking/test/conformance/ingress/rule.go
@@ -0,0 +1,71 @@
+/*
+Copyright 2020 The Knative Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package ingress
+
+import (
+	"context"
+	"testing"
+
+	"k8s.io/apimachinery/pkg/util/intstr"
+	"knative.dev/networking/pkg/apis/networking"
+	"knative.dev/networking/pkg/apis/networking/v1alpha1"
+	"knative.dev/networking/test"
+)
+
+// TestRule verifies that an Ingress properly dispatches to backends based on different rules.
+func TestRule(t *testing.T) {
+	t.Parallel()
+	ctx, clients := context.Background(), test.Setup(t)
+
+	fooName, fooPort, _ := CreateRuntimeService(ctx, t, clients, networking.ServicePortNameHTTP1)
+	barName, barPort, _ := CreateRuntimeService(ctx, t, clients, networking.ServicePortNameHTTP1)
+
+	_, client, _ := CreateIngressReady(ctx, t, clients, v1alpha1.IngressSpec{
+		Rules: []v1alpha1.IngressRule{{
+			Hosts:      []string{fooName + ".example.com"},
+			Visibility: v1alpha1.IngressVisibilityExternalIP,
+			HTTP: &v1alpha1.HTTPIngressRuleValue{
+				Paths: []v1alpha1.HTTPIngressPath{{
+					Splits: []v1alpha1.IngressBackendSplit{{
+						IngressBackend: v1alpha1.IngressBackend{
+							ServiceName:      fooName,
+							ServiceNamespace: test.ServingNamespace,
+							ServicePort:      intstr.FromInt(fooPort),
+						},
+					}},
+				}},
+			},
+		}, {
+			Hosts:      []string{barName + ".example.com"},
+			Visibility: v1alpha1.IngressVisibilityExternalIP,
+			HTTP: &v1alpha1.HTTPIngressRuleValue{
+				Paths: []v1alpha1.HTTPIngressPath{{
+					Splits: []v1alpha1.IngressBackendSplit{{
+						IngressBackend: v1alpha1.IngressBackend{
+							ServiceName:      barName,
+							ServiceNamespace: test.ServingNamespace,
+							ServicePort:      intstr.FromInt(barPort),
+						},
+					}},
+				}},
+			},
+		}},
+	})
+
+	RuntimeRequest(ctx, t, client, "http://"+fooName+".example.com")
+	RuntimeRequest(ctx, t, client, "http://"+barName+".example.com")
+}
diff --git a/vendor/knative.dev/networking/test/conformance/ingress/run.go b/vendor/knative.dev/networking/test/conformance/ingress/run.go
index 87df33edb..edcfc30de 100644
--- a/vendor/knative.dev/networking/test/conformance/ingress/run.go
+++ b/vendor/knative.dev/networking/test/conformance/ingress/run.go
@@ -34,6 +34,7 @@ var stableTests = map[string]func(t *testing.T){
 	"dispatch/path":                TestPath,
 	"dispatch/percentage":          TestPercentage,
 	"dispatch/path_and_percentage": TestPathAndPercentageSplit,
+	"dispatch/rule":                TestRule,
 	"timeout":                      TestTimeout,
 	"tls":                          TestIngressTLS,
 	"update":                       TestUpdate,
diff --git a/vendor/knative.dev/networking/test/crd.go b/vendor/knative.dev/networking/test/crd.go
deleted file mode 100644
index fdbb01b8a..000000000
--- a/vendor/knative.dev/networking/test/crd.go
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
-Copyright 2020 The Knative Authors
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package test
-
-// crd contains functions that construct boilerplate CRD definitions.
-
-import (
-	"net/url"
-
-	"knative.dev/pkg/test/helpers"
-)
-
-// ResourceNames holds names of various resources.
-type ResourceNames struct {
-	Config        string
-	Route         string
-	Revision      string
-	Service       string
-	TrafficTarget string
-	URL           *url.URL
-	Image         string
-}
-
-// AppendRandomString will generate a random string that begins with prefix. This is useful
-// if you want to make sure that your tests can run at the same time against the same
-// environment without conflicting. This method will seed rand with the current time when
-// called for the first time.
-var AppendRandomString = helpers.AppendRandomString
-
-// MakeK8sNamePrefix will convert each chunk of non-alphanumeric character into a single dash
-// and also convert camelcase tokens into dash-delimited lowercase tokens.
-var MakeK8sNamePrefix = helpers.MakeK8sNamePrefix
-
-// ObjectNameForTest generates a random object name based on the test name.
-var ObjectNameForTest = helpers.ObjectNameForTest
diff --git a/vendor/knative.dev/networking/test/e2e_constants.go b/vendor/knative.dev/networking/test/e2e_constants.go
index 98a22b596..44820133b 100644
--- a/vendor/knative.dev/networking/test/e2e_constants.go
+++ b/vendor/knative.dev/networking/test/e2e_constants.go
@@ -23,28 +23,4 @@ package test
 const (
 	// ServingNamespace is the default namespace for serving e2e tests
 	ServingNamespace = "serving-tests"
-
-	// AlternativeServingNamespace is a different namespace to run cross-
-	// namespace tests in.
-	AlternativeServingNamespace = "serving-tests-alt"
-
-	// ServingNamespaceforSecurityTesting is the namespace for security tests.
-	ServingNamespaceforSecurityTesting = "serving-tests-security"
-
-	// Environment propagation conformance test objects
-
-	// ConformanceConfigMap is the name of the configmap to propagate env variables from
-	ConformanceConfigMap = "conformance-test-configmap"
-
-	// ConformanceSecret is the name of the secret to propagate env variables from
-	ConformanceSecret = "conformance-test-secret"
-
-	// EnvKey is the configmap/secret key which contains test value
-	EnvKey = "testKey"
-
-	// EnvValue is the configmap/secret test value to match env variable with
-	EnvValue = "testValue"
-
-	// ContainerMemoryLimit is used in any test which needs a default memory resource limit
-	ContainerMemoryLimit = "350Mi"
 )
diff --git a/vendor/knative.dev/networking/test/util.go b/vendor/knative.dev/networking/test/util.go
index 370602d6d..709fa7502 100644
--- a/vendor/knative.dev/networking/test/util.go
+++ b/vendor/knative.dev/networking/test/util.go
@@ -18,17 +18,23 @@ package test
 
 import (
 	"context"
-	"crypto/tls"
-	"crypto/x509"
 	"net/http"
+	"testing"
 	"time"
 
-	corev1 "k8s.io/api/core/v1"
-	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	pkgnet "knative.dev/pkg/network"
 	"knative.dev/pkg/signals"
-	"knative.dev/pkg/test/logging"
-	"knative.dev/pkg/test/spoof"
+	pkgTest "knative.dev/pkg/test"
+	"knative.dev/pkg/test/helpers"
+	"knative.dev/pkg/test/logstream"
+
+	// For our e2e testing, we want this linked first so that our
+	// systen namespace environment variable is defaulted prior to
+	// logstream initialization.
+	_ "knative.dev/networking/test/defaultsystem"
+
+	// Mysteriously required to support GCP auth (required by k8s libs). Apparently just importing it is enough. @_@ side effects @_@. https://github.com/kubernetes/client-go/issues/242
+	_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
 )
 
 const (
@@ -36,16 +42,27 @@ const (
 	PollInterval = 1 * time.Second
 	// PollTimeout is how long e2e tests will wait for resource updates when polling.
 	PollTimeout = 10 * time.Minute
-
-	// HelloVolumePath is the path to the test volume.
-	HelloVolumePath = "/hello/world"
-
-	caSecretNamespace = "cert-manager"
-	caSecretName      = "ca-key-pair"
 )
 
 // util.go provides shared utilities methods across knative serving test
 
+// Setup creates client to run Knative Service requests
+func Setup(t testing.TB) *Clients {
+	t.Helper()
+
+	cancel := logstream.Start(t)
+	t.Cleanup(cancel)
+
+	clients, err := NewClients(pkgTest.Flags.Kubeconfig, pkgTest.Flags.Cluster, ServingNamespace)
+	if err != nil {
+		t.Fatal("Couldn't initialize clients", "error", err.Error())
+	}
+	return clients
+}
+
+// ObjectNameForTest generates a random object name based on the test name.
+var ObjectNameForTest = helpers.ObjectNameForTest
+
 // ListenAndServeGracefully calls into ListenAndServeGracefullyWithPattern
 // by passing handler to handle requests for "/"
 func ListenAndServeGracefully(addr string, handler func(w http.ResponseWriter, r *http.Request)) {
@@ -62,33 +79,3 @@ func ListenAndServeGracefullyWithHandler(addr string, handler http.Handler) {
 	<-signals.SetupSignalHandler()
 	server.Shutdown(context.Background())
 }
-
-// AddRootCAtoTransport returns TransportOption when HTTPS option is true. Otherwise it returns plain spoof.TransportOption.
-func AddRootCAtoTransport(ctx context.Context, logf logging.FormatLogger, clients *Clients, https bool) spoof.TransportOption {
-	if !https {
-		return func(transport *http.Transport) *http.Transport {
-			return transport
-		}
-	}
-	rootCAs, _ := x509.SystemCertPool()
-	if rootCAs == nil {
-		rootCAs = x509.NewCertPool()
-	}
-	if !rootCAs.AppendCertsFromPEM(PemDataFromSecret(ctx, logf, clients, caSecretNamespace, caSecretName)) {
-		logf("Failed to add the certificate to the root CA")
-	}
-	return func(transport *http.Transport) *http.Transport {
-		transport.TLSClientConfig = &tls.Config{RootCAs: rootCAs}
-		return transport
-	}
-}
-
-// PemDataFromSecret gets pem data from secret.
-func PemDataFromSecret(ctx context.Context, logf logging.FormatLogger, clients *Clients, ns, secretName string) []byte {
-	secret, err := clients.KubeClient.CoreV1().Secrets(ns).Get(ctx, secretName, metav1.GetOptions{})
-	if err != nil {
-		logf("Failed to get Secret %s: %v", secretName, err)
-		return []byte{}
-	}
-	return secret.Data[corev1.TLSCertKey]
-}
diff --git a/vendor/knative.dev/pkg/test/request.go b/vendor/knative.dev/pkg/test/request.go
index 8b546d970..ecaecd68f 100644
--- a/vendor/knative.dev/pkg/test/request.go
+++ b/vendor/knative.dev/pkg/test/request.go
@@ -20,16 +20,12 @@ package test
 
 import (
 	"context"
-	"fmt"
-	"net/http"
 	"net/url"
 	"strings"
-	"sync"
 	"time"
 
 	"knative.dev/pkg/test/flags"
 
-	"k8s.io/apimachinery/pkg/util/sets"
 	"k8s.io/client-go/kubernetes"
 	"knative.dev/pkg/test/logging"
 	"knative.dev/pkg/test/spoof"
@@ -37,107 +33,37 @@ import (
 
 // RequestOption enables configuration of requests
 // when polling for endpoint states.
-type RequestOption func(*http.Request)
+type RequestOption = spoof.RequestOption
 
 // WithHeader will add the provided headers to the request.
-func WithHeader(header http.Header) RequestOption {
-	return func(r *http.Request) {
-		if r.Header == nil {
-			r.Header = header
-			return
-		}
-		for key, values := range header {
-			for _, value := range values {
-				r.Header.Add(key, value)
-			}
-		}
-	}
-}
+//
+// Deprecated: Use the spoof package version
+var WithHeader = spoof.WithHeader
 
 // Retrying modifies a ResponseChecker to retry certain response codes.
-func Retrying(rc spoof.ResponseChecker, codes ...int) spoof.ResponseChecker {
-	return func(resp *spoof.Response) (bool, error) {
-		for _, code := range codes {
-			if resp.StatusCode == code {
-				// Returning (false, nil) causes SpoofingClient.Poll to retry.
-				// sc.logger.Info("Retrying for code ", resp.StatusCode)
-				return false, nil
-			}
-		}
-
-		// If we didn't match any retryable codes, invoke the ResponseChecker that we wrapped.
-		return rc(resp)
-	}
-}
+//
+// Deprecated: Use the spoof package version
+var Retrying = spoof.Retrying
 
 // IsOneOfStatusCodes checks that the response code is equal to the given one.
-func IsOneOfStatusCodes(codes ...int) spoof.ResponseChecker {
-	return func(resp *spoof.Response) (bool, error) {
-		for _, code := range codes {
-			if resp.StatusCode == code {
-				return true, nil
-			}
-		}
-
-		return true, fmt.Errorf("status = %d %s, want one of: %v", resp.StatusCode, resp.Status, codes)
-	}
-}
+//
+// Deprecated: Use the spoof package version
+var IsOneOfStatusCodes = spoof.IsOneOfStatusCodes
 
 // IsStatusOK checks that the response code is a 200.
-func IsStatusOK(resp *spoof.Response) (bool, error) {
-	return IsOneOfStatusCodes(http.StatusOK)(resp)
-}
+//
+// Deprecated: Use the spoof package version
+var IsStatusOK = spoof.IsStatusOK
 
 // MatchesAllBodies checks that the *first* response body matches the "expected" body, otherwise failing.
-func MatchesAllBodies(all ...string) spoof.ResponseChecker {
-	var m sync.Mutex
-	// This helps with two things:
-	// 1. we can use Equal on sets
-	// 2. it will collapse the duplicates
-	want := sets.NewString(all...)
-	seen := make(sets.String, len(all))
-
-	return func(resp *spoof.Response) (bool, error) {
-		bs := string(resp.Body)
-		for expected := range want {
-			if !strings.Contains(bs, expected) {
-				// See if the next one matches.
-				continue
-			}
-
-			m.Lock()
-			defer m.Unlock()
-			seen.Insert(expected)
-
-			// Stop once we've seen them all.
-			return want.Equal(seen), nil
-		}
-
-		// Returning (true, err) causes SpoofingClient.Poll to fail.
-		return true, fmt.Errorf("body = %s, want one of: %s", bs, all)
-	}
-}
+//
+// Deprecated: Use the spoof package version
+var MatchesAllBodies = spoof.MatchesAllBodies
 
 // MatchesBody checks that the *first* response body matches the "expected" body, otherwise failing.
-func MatchesBody(expected string) spoof.ResponseChecker {
-	return func(resp *spoof.Response) (bool, error) {
-		if !strings.Contains(string(resp.Body), expected) {
-			// Returning (true, err) causes SpoofingClient.Poll to fail.
-			return true, fmt.Errorf("body = %s, want: %s", string(resp.Body), expected)
-		}
-
-		return true, nil
-	}
-}
-
-// EventuallyMatchesBody checks that the response body *eventually* matches the expected body.
-// TODO(#1178): Delete me. We don't want to need this; we should be waiting for an appropriate Status instead.
-func EventuallyMatchesBody(expected string) spoof.ResponseChecker {
-	return func(resp *spoof.Response) (bool, error) {
-		// Returning (false, nil) causes SpoofingClient.Poll to retry.
-		return strings.Contains(string(resp.Body), expected), nil
-	}
-}
+//
+// Deprecated: Use the spoof package version
+var MatchesBody = spoof.MatchesBody
 
 // MatchesAllOf combines multiple ResponseCheckers to one ResponseChecker with a logical AND. The
 // checkers are executed in order. The first function to trigger an error or a retry will short-circuit
@@ -147,14 +73,16 @@ func EventuallyMatchesBody(expected string) spoof.ResponseChecker {
 // MatchesAllOf(IsStatusOK, MatchesBody("test"))
 //
 // The MatchesBody check will only be executed after the IsStatusOK has passed.
-func MatchesAllOf(checkers ...spoof.ResponseChecker) spoof.ResponseChecker {
+//
+// Deprecated: Use the spoof package version
+var MatchesAllOf = spoof.MatchesAllOf
+
+// EventuallyMatchesBody checks that the response body *eventually* matches the expected body.
+// TODO(#1178): Delete me. We don't want to need this; we should be waiting for an appropriate Status instead.
+func EventuallyMatchesBody(expected string) spoof.ResponseChecker {
 	return func(resp *spoof.Response) (bool, error) {
-		for _, checker := range checkers {
-			if done, err := checker(resp); err != nil || !done {
-				return done, err
-			}
-		}
-		return true, nil
+		// Returning (false, nil) causes SpoofingClient.Poll to retry.
+		return strings.Contains(string(resp.Body), expected), nil
 	}
 }
 
@@ -193,24 +121,16 @@ func WaitForEndpointStateWithTimeout(
 	resolvable bool,
 	timeout time.Duration,
 	opts ...interface{}) (*spoof.Response, error) {
-	defer logging.GetEmitableSpan(ctx, "WaitForEndpointState/"+desc).End()
-
-	if url.Scheme == "" || url.Host == "" {
-		return nil, fmt.Errorf("invalid URL: %q", url.String())
-	}
-
-	req, err := http.NewRequest(http.MethodGet, url.String(), nil)
-	if err != nil {
-		return nil, err
-	}
 
 	var tOpts []spoof.TransportOption
+	var rOpts []spoof.RequestOption
+
 	for _, opt := range opts {
-		rOpt, ok := opt.(RequestOption)
-		if ok {
-			rOpt(req)
-		} else if tOpt, ok := opt.(spoof.TransportOption); ok {
-			tOpts = append(tOpts, tOpt)
+		switch o := opt.(type) {
+		case spoof.RequestOption:
+			rOpts = append(rOpts, o)
+		case spoof.TransportOption:
+			tOpts = append(tOpts, o)
 		}
 	}
 
@@ -220,5 +140,5 @@ func WaitForEndpointStateWithTimeout(
 	}
 	client.RequestTimeout = timeout
 
-	return client.Poll(req, inState)
+	return client.WaitForEndpointState(ctx, url, inState, desc, rOpts...)
 }
diff --git a/vendor/knative.dev/pkg/test/spoof/request.go b/vendor/knative.dev/pkg/test/spoof/request.go
new file mode 100644
index 000000000..df26e8fae
--- /dev/null
+++ b/vendor/knative.dev/pkg/test/spoof/request.go
@@ -0,0 +1,38 @@
+/*
+Copyright 2020 The Knative Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package spoof
+
+import "net/http"
+
+// RequestOption enables configuration of requests
+// when polling for endpoint states.
+type RequestOption func(*http.Request)
+
+// WithHeader will add the provided headers to the request.
+func WithHeader(header http.Header) RequestOption {
+	return func(r *http.Request) {
+		if r.Header == nil {
+			r.Header = header
+			return
+		}
+		for key, values := range header {
+			for _, value := range values {
+				r.Header.Add(key, value)
+			}
+		}
+	}
+}
diff --git a/vendor/knative.dev/pkg/test/spoof/response_checks.go b/vendor/knative.dev/pkg/test/spoof/response_checks.go
new file mode 100644
index 000000000..d5e96258f
--- /dev/null
+++ b/vendor/knative.dev/pkg/test/spoof/response_checks.go
@@ -0,0 +1,121 @@
+/*
+Copyright 2020 The Knative Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package spoof
+
+import (
+	"fmt"
+	"net/http"
+	"strings"
+	"sync"
+
+	"k8s.io/apimachinery/pkg/util/sets"
+)
+
+// MatchesBody checks that the *first* response body matches the "expected" body, otherwise failing.
+func MatchesBody(expected string) ResponseChecker {
+	return func(resp *Response) (bool, error) {
+		if !strings.Contains(string(resp.Body), expected) {
+			// Returning (true, err) causes SpoofingClient.Poll to fail.
+			return true, fmt.Errorf("body = %s, want: %s", string(resp.Body), expected)
+		}
+
+		return true, nil
+	}
+}
+
+// MatchesAllOf combines multiple ResponseCheckers to one ResponseChecker with a logical AND. The
+// checkers are executed in order. The first function to trigger an error or a retry will short-circuit
+// the other functions (they will not be executed).
+//
+// This is useful for combining a body with a status check like:
+// MatchesAllOf(IsStatusOK, MatchesBody("test"))
+//
+// The MatchesBody check will only be executed after the IsStatusOK has passed.
+func MatchesAllOf(checkers ...ResponseChecker) ResponseChecker {
+	return func(resp *Response) (bool, error) {
+		for _, checker := range checkers {
+			if done, err := checker(resp); err != nil || !done {
+				return done, err
+			}
+		}
+		return true, nil
+	}
+}
+
+// MatchesAllBodies checks that the *first* response body matches the "expected" body, otherwise failing.
+func MatchesAllBodies(all ...string) ResponseChecker {
+	var m sync.Mutex
+	// This helps with two things:
+	// 1. we can use Equal on sets
+	// 2. it will collapse the duplicates
+	want := sets.NewString(all...)
+	seen := make(sets.String, len(all))
+
+	return func(resp *Response) (bool, error) {
+		bs := string(resp.Body)
+		for expected := range want {
+			if !strings.Contains(bs, expected) {
+				// See if the next one matches.
+				continue
+			}
+
+			m.Lock()
+			defer m.Unlock()
+			seen.Insert(expected)
+
+			// Stop once we've seen them all.
+			return want.Equal(seen), nil
+		}
+
+		// Returning (true, err) causes SpoofingClient.Poll to fail.
+		return true, fmt.Errorf("body = %s, want one of: %s", bs, all)
+	}
+}
+
+// IsStatusOK checks that the response code is a 200.
+func IsStatusOK(resp *Response) (bool, error) {
+	return IsOneOfStatusCodes(http.StatusOK)(resp)
+}
+
+// IsOneOfStatusCodes checks that the response code is equal to the given one.
+func IsOneOfStatusCodes(codes ...int) ResponseChecker {
+	return func(resp *Response) (bool, error) {
+		for _, code := range codes {
+			if resp.StatusCode == code {
+				return true, nil
+			}
+		}
+
+		return true, fmt.Errorf("status = %d %s, want one of: %v", resp.StatusCode, resp.Status, codes)
+	}
+}
+
+// Retrying modifies a ResponseChecker to retry certain response codes.
+func Retrying(rc ResponseChecker, codes ...int) ResponseChecker {
+	return func(resp *Response) (bool, error) {
+		for _, code := range codes {
+			if resp.StatusCode == code {
+				// Returning (false, nil) causes SpoofingClient.Poll to retry.
+				// sc.logger.Info("Retrying for code ", resp.StatusCode)
+				return false, nil
+			}
+		}
+
+		// If we didn't match any retryable codes, invoke the ResponseChecker that we wrapped.
+		return rc(resp)
+	}
+}
diff --git a/vendor/knative.dev/pkg/test/spoof/spoof.go b/vendor/knative.dev/pkg/test/spoof/spoof.go
index e69b39c28..9d00bad9e 100644
--- a/vendor/knative.dev/pkg/test/spoof/spoof.go
+++ b/vendor/knative.dev/pkg/test/spoof/spoof.go
@@ -26,6 +26,7 @@ import (
 	"io/ioutil"
 	"net"
 	"net/http"
+	"net/url"
 	"time"
 
 	"k8s.io/apimachinery/pkg/util/wait"
@@ -245,3 +246,28 @@ func (sc *SpoofingClient) logZipkinTrace(spoofResp *Response) {
 
 	sc.Logf("%s", json)
 }
+
+func (sc *SpoofingClient) WaitForEndpointState(
+	ctx context.Context,
+	url *url.URL,
+	inState ResponseChecker,
+	desc string,
+	opts ...RequestOption) (*Response, error) {
+
+	defer logging.GetEmitableSpan(ctx, "WaitForEndpointState/"+desc).End()
+
+	if url.Scheme == "" || url.Host == "" {
+		return nil, fmt.Errorf("invalid URL: %q", url.String())
+	}
+
+	req, err := http.NewRequest(http.MethodGet, url.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	for _, opt := range opts {
+		opt(req)
+	}
+
+	return sc.Poll(req, inState)
+}